前端JS面试题

mac2024-04-21  37

前端JS面试题

call 和 apply 的区别 是什么,哪一个性能更好一些?

传参的区别 call 是一个个传递apply是传递一个数组bind 是预先处理,但是不会立即执行但是 call 在基于ES6的展开运算符也可以将数组中的每一项传递给函数 call apply 都是 Function 原型上面的方法,而每个函数作为 Function 的实例,可以调取其方法在参数过多的时候,call 的性能会好一些console.time 可以测试一段程序执行的时间 console.timeEnd

实现 (5).add(3).minus(2) 使其输出结果为 6

假设 arr 是一个数组,它之所以可以调用 arr.push()这个方法式因为 它是Array的实例,可以继续调用Array原型上面的 push 方法 ~function(){ //每一个方法执行完,都要返回Number这个类的实例,这样才可以继续调取Number类原型中的方法(链式写法) function check(n){ n = Number(n) return isNaN(n) ? 0 : n } function add(n){ n = check(n) //this 不能赋值 return this + n } function minus(n){ n = check(n) return this - n } ['add','minus'].forEach(item=>{ Number.prototype[item] = eval(item) }) }() console.log((5).add(3).minus(2))

箭头函数与普通函数(function)的区别是什么?构造函数(function) 可以使用new 生成实例,那么箭头函数可以么?为什么

箭头函数与普通函数区别

箭头函数语法上比普通函数更加简洁(ES6中每一种函数都可以使用形参默认值和剩余运算符)

箭头函数中没有自己的this,他里面的this 从属于函数所处的上下文(使用call/apply等任何方式都无法改变this的指向)

document.body.onclick = function(){ //this:boby arr.sort(function(){ //this:window /***********回调函数中的this一般都是window***************/ return a -b }) } /*回调函数:把一个函数b作为实参传递给另外一个函数A ,函数A在执行的时候,可以把传递进来的函数B去执行*/

箭头函数没有arguments(类数组),只能基于…arg获取传递得参数集合(数组)

箭头函数不能被 new 执行(因为:箭头函数没有this 也没有prototype)

如何把一个字符串中得大小写取反(大写变小写,小写变大写)l

let str = 'sdsdsdSDSAD哈哈哈sdjsHJJkj'; str = str.replace(/[a-zA-Z]/g,content=>{ //俩种思路 //先将其转换然后在比较 如果相同代表之前也为大写 //2.根据AScLL值进行比较 return content.toUpperCase() ===content ? content.toLowerCase : content.toUpperCase() })

实现一个字符串匹配算法,从字符串 S 中,查找是否存在字符串 T ,若存在返回所在位置,不存在返回 -1! (如果不能基于 indexof / includes等内置得方法,你会怎么处理)

//使用正则 ~function(){ function myIndexof(T){ let reg = new RegExp(T), res = reg.exec(this); return res===null?res=-1:res.index } String.prototype.myIndexof = myIndexof }() //常规解法 ~function(){ function myIndexof(T){ let lenT = T.length, lenS = this.length, res = -1; if (lenT >lenS) return res; for (var i = 0; i <= lenS - lenT; i++) { if(this.substr(i,lenT)=== T){ res = i break; } } return res } String.prototype.myIndexof = myIndexof }()

输出下面代码运行结果

var a = {}, b = '123',c =123; a[b] = 'b' a[c] = 'c' console.log(a[b]) a = {100 : '哈哈','100' :'嘻嘻'} //输出{100: "嘻嘻"} //因为后面得会替换前面得 对象属性key 可以为字符串也可以数字 a['123'] <=>a[123] var a = {}, b = Symbol('123'),c =Symbol(123); a[b] = 'b' a[c] = 'c' console.log(a[b]) //Symbol 是ES6中新增得数据类型, Symbol(123) === Symbol(123) false 它创建出来得值是唯一值 var a = {}, b = {key:'123'},c ={key:'456'}; a[b] = 'b' a[c] = 'c' console.log(a[b]) //({key:'123'}).toString()==>>>"[object Object]"\ //obj ={} arr = [12,23] obj[arr] = 'xzt' obj => {'12,23':'xzt'}

在输入框中如何判断输入的是一个正确的网址,例如:用户输入一个字符串,验证是否符合URL网址的格式

let str = 'http://www.baidu.com/index.html?lx=1&from=wx#video' let reg = /^((http|https|ftp):\/\/)?(([\w-]+\.)+[a-z0-9]+)((\/[^/]*)+)?(\?[^#]+)?(#.+)?$/i console.log(reg.exec(str))

判断输出题

function Foo(){ Foo.a = function(){ console.log(1) } this.a = function(){ console.log(2) } } //把Foo当做类,在原型上设置实例共有的属性方法=》实例.a() Foo.prototype.a = function(){//原型上面加属性和方法 console.log(3) } //把Foo当做普通对象设置私有的属性方法 =》Foo.a() Foo.a = function(){//在Foo上加了私有属性 console.log(4) } Foo.a()//输出4 let obj = new Foo() //生成 Foo 实例 obj 可以调取原型上的方法 Foo.a : f=>1 obj.a:f=>2 obj.a()//输出2 私有属性中有a Foo.a()//在私有属性上面找 所以输出1

编写代码实现图片懒加载

前端性能优化的重要方案 通过图片或者数据的延迟加载,我们可以加快页面渲染的速度,让第一次打开页面的速度变快只有滑动到某个区域,我们才加载真是的图片,这样也可以节省加载的流量 处理方案 把所有需要延迟加载的图片用一个盒子包起来,设置宽搞和默认站位图开始让所有的img src 为空,把真实图片的地址放到IMG的自定义属性上,让IMG隐藏等到所有其他资源都加载完成后,我们再开始加载图片对于很多图片,需要当页面滚动的时候,当前图片区域完全显示出来后再加载真实图片

实现一个$attr(name,value)遍历,属性为 name 值为 value 的元素集合

function $attr(props,value){ let el = document.getElementsByTagName('*'), arr = []; // [].forEach.call(el,item=>{}) el = Array.from(el)//把非数组转换成数组 el.forEach(item=>{ //存储的是当前元素props 对应的属性值 let itemVale = item.getAttribute(prop) if (prop === 'class') { //样式类属性名要特殊处理 new RegExp("\\b" + value + "\\b").test(itemVale)?arr.push(item):null; return; } if (itemVale===value) { //获取的值 和传递的值校验成功:当前就是我们想要的 arr.push(item) } }) return arr }

英文字母汉字组成的字符串,用正则给英文单词前后加空格

let reg = \\b[a-z]+\b\ig; str = str.replace(reg,value=>{ return " " + value + " " }).trim()//首尾去除空格

编写一个程序,将数组扁平化,并去除其中重复部分数据,最终得到一个升序而且不重复的数组

自己实现new

function myNew(Fn,...arg){ //创建一个空对象 // let obj = {} // //让他的原型链之指向 Fn.prototype(作为Fn 的一个实例) // obj.__proto__ = Fn.prototype let obj = Object.create(Fn.prototype) //Object.create(AA对象):创建一个空对象,并且让空对象obj作为AA对象所属构造函数的实例 //(obj.__proto__ = AA) Fn.call(obj,...arg) return obj }

合并数组

let ary1 = ['A1','A2','B2','C1','C2','C3','D','D1'] let ary2 = [A','B2','C1] let n= 0 for(var i = 0;i<ary2.length;i++){ let item2 = ary2[i] for(var j=0;j<ary1.length;j++){ let item1 = ary2[j] if(item1.includes(item2)){ n = j } } ary1.splice(n+1,0,item2) }

判断输出值

var b = 10; (function b(){ b= 20; console.log(b) //输出 b 这个函数 })() console.log(b)//输出10 let fn = function AAA(){ AAA = 100 console.log(AAA)//当前函数 } AAA()==》 报错 1、本应匿名的函数如果设置了函数名,在外面还是无法调用,但是在函数里面是可以使用的 2、而且类似于创建常亮一样,这个名字存储的值不能再被修改(非严格模式下不报错,但是不会有任何效果,严格模式下直接报错,我们可以把AAA理解为是用const 创建出来的)

赋值比较

== 进行比较的时候,如果俩边数据类型不一样,则先转换为相同的数据类型,然后在进行比较

{} == {} 俩个对象进行比较,比较的是堆内存的地址null == undefined 相等 的 / null === undefined 不相等NaN == NaN 不相等,NaN 和谁都不相等[12] == ‘12’ 对象和字符串比较,是把对象 toString()转换为字符串后再进行比较的剩余所有情况在进行比较的时候,都是转换为数字(前提数据类型不一样) 对象转数字:先转换为字符串,然后在转换为数字字符串转数字:只要出现一个非数字字符,结果就是NaN布尔转数字 :true => 1 false =>0null 转数字 0undefined 转数字 NaN

实现 a1 && a2 && a==3

if (a==1 && a==2 && a==3){ console.log('OK') } //方法一: var a = { n = 0; toString :function (){ return ++this.n; } } //方法二: //shift :删除第一项,把删除的内容返回,原有数组改变 let a = [1,2,3] a.toString = a.shift //方法三: letn = 0 Object.definProperty(window,'a',{ get :function(){ return ++n } })

判断输出

let obj = { 2:3, 3:4, length:2, push : Array.prototype.push } obj.push(1) //this : obj obj[obj.length] = 1 ==> obj[2] = 1 ==> obj.length = 3 obj.push(2) //this : obj obj[obj.length] = 2 ==> obj[3] = 1 ==> obj.length = 4 console.log(obj) Array.prototype.push = function AA(){ this[this.length] = val //=>this.length 在原来的基础上加一 return this.length }

冒泡排序

let ary = [1,5,4,2,8,9] let ary = [1,5,4,2,8,9] function Bubble(ary){ for (var i = 0; i < ary.length-1; i++) { for (var j = 0; j < ary.length-i-1; j++) { let temp; if (ary[j] > ary[j+1]) { temp = ary[j] ary[j] = ary[j+1] ary[j+1] =temp } } } return ary }

插入排序

function insert(ary){ let handel = [] handel.push(ary[0]) for (var i = 1; i < ary.length; i++) { let itemA = ary[i] for (var j=handel.length-1;j>=0; j--) { let itemB = handel[j] if (itemA>itemB) { handel.splice(j+1,0,itemA) break; } if (j===0) { handel.unshift(itemA) } } } return handel }

函数柯理化:预先处理的思想(利用闭包的机制)

请实现一个add 函数,满足以下功能

add(1) add(1)(2) add(1)(2)(3) add(1)(2)(3)(4)
最新回复(0)