028-86261949

当前位置:首页 > 技术交流 > 前端20道大厂面试题,你能答出几个呢?

前端20道大厂面试题,你能答出几个呢?

2019/09/20 16:32 分类: 技术交流 浏览:0

1. new的实现原理是什么?

new 的实现原理:

  1. 创建一个空对象,构造函数中的this指向这个空对象

  2. 这个新对象被执行 [[原型]] 连接

  3. 执行构造函数方法,属性和方法被添加到this引用的对象中

  4. 如果构造函数中没有返回其它对象,那么返回this,即创建的这个的新对象,否则,返回构造函数中返回的对象。

 

2. 如何正确判断this的指向?

如果用一句话说明 this 的指向,那么即是: 谁调用它,this 就指向谁。

但是仅通过这句话,我们很多时候并不能准确判断 this 的指向。因此我们需要借助一些规则去帮助自己:

this 的指向可以按照以下顺序判断:

全局环境中的 this

浏览器环境:无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象 window;

node 环境:无论是否在严格模式下,在全局执行环境中(在任何函数体外部),this 都是空对象 {};

是否是 new 绑定

如果是 new 绑定,并且构造函数中没有返回 function 或者是 object,那么 this 指向这个新对象。如下:

构造函数返回值不是 function 或 object。new Super() 返回的是 this 对象。

 

构造函数返回值是 function 或 object,new Super()是返回的是Super种返回的对象。

 

函数是否通过 call,apply 调用,或者使用了 bind 绑定,如果是,那么this绑定的就是指定的对象【归结为显式绑定】。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这里同样需要注意一种特殊情况,如果 call,apply 或者 bind 传入的第一个参数值是 undefined 或者 null,严格模式下 this 的值为传入的值 null /undefined。非严格模式下,实际应用的默认绑定规则,this 指向全局对象(node环境为global,浏览器环境为window)

 

隐式绑定,函数的调用是在某个对象上触发的,即调用位置上存在上下文对象。典型的隐式调用为: xxx.fn()

 

 

默认绑定,在不能应用其它绑定规则时使用的默认规则,通常是独立函数调用。

非严格模式:node环境,指向全局对象 global,浏览器环境,指向全局对象 window。

严格模式:执行 undefined

 

箭头函数的情况:

箭头函数没有自己的this,继承外层上下文绑定的this。

 

3. 深拷贝和浅拷贝的区别是什么?实现一个深拷贝

查看解析

深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。

深拷贝

深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

浅拷贝

浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。

可以使用 for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat() 等,例如:

 

可以看出浅拷贝只最第一层属性进行了拷贝,当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。

深拷贝实现

1.深拷贝最简单的实现是: JSON.parse(JSON.stringify(obj))

JSON.parse(JSON.stringify(obj)) 是最简单的实现方式,但是有一些缺陷:

  1. 对象的属性值是函数时,无法拷贝。

  2. 原型链上的属性无法拷贝

  3. 不能正确的处理 Date 类型的数据

  4. 不能处理 RegExp

  5. 会忽略 symbol

  6. 会忽略 undefined

2.实现一个 deepClone 函数

  1. 如果是基本数据类型,直接返回

  2. 如果是 RegExp 或者 Date 类型,返回对应类型

  3. 如果是复杂数据类型,递归。

  4. 考虑循环引用的问题

 

4. call/apply 的实现原理是什么?

查看解析

call 和 apply 的功能相同,都是改变 this 的执行,并立即执行函数。区别在于传参方式不同。

  • func.call(thisArg, arg1, arg2, ...):第一个参数是 this 指向的对象,其它参数依次传入。

  • func.apply(thisArg, [argsArray]):第一个参数是 this 指向的对象,第二个参数是数组或类数组。

一起思考一下,如何模拟实现 call ?

首先,我们知道,函数都可以调用 call,说明 call 是函数原型上的方法,所有的实例都可以调用。即: Function.prototype.call。

  • 在 call 方法中获取调用call()函数

  • 如果第一个参数没有传入,那么默认指向 window / global(非严格模式)

  • 传入 call 的第一个参数是 this 指向的对象,根据隐式绑定的规则,我们知道 obj.foo(), foo() 中的 this 指向 obj;因此我们可以这样调用函数 thisArgs.func(...args)

  • 返回执行结果

 

apply 的实现思路和 call 一致,仅参数处理略有差别。如下:

 

5. 柯里化函数实现

6. 如何让 (a == 1 && a == 2 && a == 3) 的值为true?

7. 什么是BFC?BFC的布局规则是什么?如何创建BFC?

8. 异步加载JS脚本的方式有哪些?

9. ES5有几种方式可以实现继承?分别有哪些优缺点?

10. 隐藏页面中的某个元素的方法有哪些?

11. let、const、var 的区别有哪些?

12. 说一说你对JS执行上下文栈和作用域链的理解?

13. 防抖函数的作用是什么?请实现一个防抖函数

14. 节流函数的作用是什么?有哪些应用场景,请实现一个节流函数

15. 什么是闭包?闭包的作用是什么?

16. 实现 Promise.all 方法

17. 请实现一个 flattenDeep 函数,把嵌套的数组扁平化

18. 请实现一个 uniq 函数,实现数组去重

19. 可迭代对象有哪些特点

20. JSONP 的原理是什么?

#标签:前端,面试前端,web