基础-必会知识(下)
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%内容,订阅专栏后可继续查看/也可单篇购买
前端岗位面试求职攻略及真题解析~~