一文搞定this问题
this 可能属于 JavaScript 开发中老生常谈的问题了,但 this 相关问题依旧困扰着许多开发同学,这里将之前总结的一篇笔记与大家分享。
this 默认绑定
默认绑定时,this 指向全局即,window。值得注意的是,在严格模式环境中,默认绑定的this指向undefined。
function fn() {
console.log(this); //window
console.log(this.name);
};
function fn1() {
"use strict";
console.log(this); //undefined
console.log(this.name);
};
var name = 'Jack';
fn();
// window
// Jack
fn1()
// undefined
// Uncaught TypeError: Cannot read property 'name' of undefined
this 隐式绑定
- 如果函数作为一个对象的属性调用,那么它的 this 指向这个对象。
// 例子1
function fn() {
console.log(this.name);
};
let obj = {
name: 'LiLei',
func: fn
};
obj.func() // LiLei
// 例子2
// 如果函数调用前存在多个对象,this 指向距离调用自己最近的对象
function fn() {
console.log(this.name);
};
let obj = {
name: 'Jack',
func: fn,
};
let obj1 = {
name: 'Tom',
o: obj
};
obj1.o.func() // Jack
- 隐式丢失
// 例子1. 最常见的就是作为参数传递以及变量赋值时,会存在隐式绑定丢失的问题。
var name = 'LiLei';
let obj = {
name: 'Tom',
fn: function () {
console.log(this.name);
}
};
function fn1(param) {
param();
};
fn1(obj.fn);// LiLei
// 例子2. 变量赋值
var name = 'LiLei';
let obj = {
name: 'Tom',
fn: function () {
console.log(this.name);
}
};
let fn1 = obj.fn;
fn1(); // LiLei
this 显式绑定
通过call、apply以及bind方法改变this的行为我们叫做显式绑定绑定,相比隐式绑定 this 的指向更加明显。
let obj1 = {
name: 'A'
};
let obj2 = {
name: 'B'
};
let obj3 = {
name: 'C'
}
var name = 'D';
function fn() {
console.log(this.name);
};
fn(); // D
fn.call(obj1); // A
fn.apply(obj2); // B
fn.bind(obj3)(); // C
如果以上方法第一个参数传递的是 null 或者 undefined,this 将指向 window。
bind、call、apply 都可以改变 this 指向,但他们的区别是什么:
- call、apply在改变this指向的同时还会执行函数,而bind在改变this后是返回一个全新的boundFcuntion绑定函数,这也是为什么上方例子中bind后还加了一对括号 ()的原因。
- bind属于硬绑定,返回的 boundFunction 的 this 指向无法再次通过bind、apply或 call 修改;call与apply的绑定只适用当前调用,调用完就没了,下次要用还得再次绑。
- call与apply功能完全相同,唯一不同的是call方法传递函数调用形参是以散列形式,而apply方法的形参是一个数组。在传参的情况下,call的性能要高于apply,因为apply在执行时还要多一步解析数组。
new 方法
new 一个函数主要发生了一下几步:
- 以构造器的 prototype 属性为原型,创建新对象;
- 将this(可以理解为上句创建的新对象)和调用参数传给构造器,执行;
- 如果构造器没有手动返回对象,则返回第一步创建的对象
this绑定优先级
如果一个函数调用存在多种绑定方法,this最终指向谁呢?可以记住以下优先级:
- 显式绑定 > 隐式绑定 > 默认绑定
- new绑定 > 隐式绑定 > 默认绑定
// 显式 > 隐式
let obj = {
name:'A',
fn:function () {
console.log(this.name);
}
};
obj1 = {
name:'B'
};
obj.fn.call(obj1);// B
// new>隐式
obj = {
name: 'C',
fn: function () {
this.name = 'D';
}
};
let echo = new obj.fn();
echo.name;// D
箭头函数的 this
ES6的箭头函数中其实并没有 this,它里面的 this 指向取决于外层作用域中的 this,外层作用域或函数的this指向谁,箭头函数中的this便指向谁。
function fn() {
return () => {
console.log(this.name);
};
};
let obj1 = {
name: 'A'
};
let obj2 = {
name: 'B'
};
fn.call(obj1)(); // fn this指向obj1,箭头函数this也指向obj1
fn.call(obj2)(); // fn this 指向obj2,箭头函数this也指向obj2

浙公网安备 33010602011771号