基础-必会知识(下)
3 基础-必会知识(下)
3.1 请问你了解js中的this绑定机制吗?
【考点映射】
-
this绑定机制
【频率】★★★★★(面试极有可能出代码题(面试官给代码,答输出))
【难度】☆☆
【参考答案】
this特点:
this是js的关键字之一,它是对象自动生成的一个内部对象,只能在对象内部使用
随着使用场合的不同,this的值会发生变化,并不是一成不变的
this指向完全取决于:什么地方以什么方式调用,而不是 创建时
this 4种绑定机制:默认绑定、隐式绑定、显示绑定、new绑定,箭头函数的this不适用于这4种绑定机制,需要单独分析,将会在后续ES6新特性章节中做重点分析
-
默认绑定(函数调用时无任何调用前缀的情景)
function fn1() { let fn2 = function () { console.log(this); //window fn3(); }; console.log(this); //window fn2(); }; function fn3() { console.log(this); //window }; fn1();
代码中无论函数声明在哪,在哪调用,由于函数调用时前面并未指定任何对象,这种情况下this指向全局对象window
注意:在严格模式下(use strict),全局对象将无法使用默认绑定,会报undefined错误
function fn() { console.log(this); //window console.log(this.a); }; function fn1() { "use strict"; console.log(this); //undefined console.log(this.a); }; var a = 1; fn() //1 fn1() //TypeError: Cannot read property 'a' of undefined
-
隐式绑定
在函数调用时,前面存在调用它的对象,即函数的调用是在该对象上触发的,调用位置上存在上下文对象,那this就会隐式绑定到该对象上
function foo() { console.log(this.a); } var a = 2; var obj = { a: 3, foo: foo }; obj.foo(); //3
代码中foo函数被当做引用属性,被添加到obj对象上。调用过程:获取obj.foo属性→ 根据引用关系找到foo函数,执行调用
这里对foo的调用存在上下文对象obj,this进行了隐式绑定,即this绑定到了obj上,this.a被解析成了obj.a
多层调用链(面试高频考题)(函数调用前存在多个对象,this指向距离调用自己最近的对象)
function foo() { console.log( this.a ); } var a = 2; var obj1 = { a: 4, foo: foo }; var obj2 = { a: 3, obj1: obj1 }; obj2.obj1.foo(); //4
代码中调用链不只一层,存在obj1、obj2两个对象,先获取obj2.obj1→通过引用获取到obj1对象,再访问 obj1.foo →最后执行foo函数调用,获取最后一层调用的上下文对象,即obj1,所以结果是4(obj1.a)
-
隐式丢失
在一些特殊情况下,会存在隐式绑定丢失问题,最常见:参数传递、变量赋值
参数传递
var a = 1; let obj = { a: 2, fn: function () { console.log(this.a); } }; function fn1(param) { param(); }; fn1(obj.fn);//1
代码中将 obj.fn 作为参数传递进 fn1 中执行,只是单纯地传递了一个函数而已,this并没有跟函数绑在一起,发生了隐式丢失,this依旧指向window
变量赋值(本质上与传参相同)
var a = 1; let obj = { a: 2, fn: function () { console.log(this.a); } }; let fn1 = obj.fn; fn1(); //1
-
显式绑定(call、apply、bind)
let obj1 = { a: 2 }; let obj2 = { a: 3 }; let obj3 = { a: 4 } var a = 1; function fn() { console.log(this.a); }; fn(); //1 fn.call(obj1); //2 fn.apply(obj2); //3 fn.bind(obj3)(); //4
代码中,我们分别通过call、apply、bind改变了函数fn的this指向
通常,js中调用一个函数时(函数调用),函数处于一个被动的状态,而call与apply让函数从被动变主动,函数能主动选择自己的上下文,这种写法又称之为函数应用
注意:若使用函数应用的方法改变this指向时,指向参数是null或者undefined,那么 this 将指向全局对象
-
new绑定
function Fn(){ this.a = 1; }; let echo = new Fn(); console.log(echo.a) //1
代码中,构造函数调用创建了一个新对象echo,而在函数体内,this将指向新对象echo上(可以抽象理解为新对象就是this)
-
this绑定优先级
如果一个函数调用存在多种绑定方法,this最终指向是什么呢?this绑定优先级为:
显式绑定 > 隐式绑定 > 默认绑定
new绑定 > 隐式绑定 > 默认绑定
注意:不存在显式绑定和new绑定同时生效的场景,若同时写会直接报错
【延伸考点】
1、作用域链与原型链有什么区别?
作用域链:当访问一个变量时,首先在当前作用域查找标识符,如果没有找到就去父作用域找,作用域链顶端是全局对象window,如果window都没有这个变量则报错
原型链:当在对象上访问某属性时,首先会查找当前对象,如果没有就顺着原型链往上找,原型链顶端是null,如果全程都没找到则返回undefined,而不是报错
3.2 请问call、apply与bind有什么区别?
【考点映射】
-
call、apply与bind区别
【频率】★★★★
【难度】☆
【参考答案】
call、apply与bind:都能用于改变this绑定
apply与call:
都是函数应用,指定this的同时也会执行函数,参数传递方式不同
call与apply的绑定只适用当前调用,调用完毕即失效,下次要用还得重新绑
call:接受一个参数列表,第一个参数指向this,其余的参数在函数执行时都会作为函数形参传入函数
apply:除了第一个参数作为this指向外,其它参数都被包裹在一个数组中,在函数执行时同样会作为形参传入
let o = { a: 1 }; function fn(b, c) { console.log(this.a + b + c); }; // fn.call(this, arg1, arg2, ...); fn.call(o, 2, 3); // 6 // fn.apply(this, [arg1, arg2, ...]); fn.apply(o, [2, 3]); // 6
bind:
绑定this后并不会立马执行,而是返回一个全新的boundFcuntion绑定函数
bind属于硬绑定,返回的boundFunction的this指向无法再次通过bind、apply或 call 修改
let o1 = { a: 1 }; let o2 = { a: 2 }; function fn(b, c) { console.log(t
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
前端岗位面试求职攻略及真题解析~~