一文搞定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 隐式绑定

  1. 如果函数作为一个对象的属性调用,那么它的 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. 隐式丢失
// 例子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 一个函数主要发生了一下几步:

  1. 以构造器的 prototype 属性为原型,创建新对象;
  2. 将this(可以理解为上句创建的新对象)和调用参数传给构造器,执行;
  3. 如果构造器没有手动返回对象,则返回第一步创建的对象

this绑定优先级

如果一个函数调用存在多种绑定方法,this最终指向谁呢?可以记住以下优先级:

  1. 显式绑定 > 隐式绑定 > 默认绑定
  2. 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
posted @ 2021-01-20 10:37  jsguo  阅读(59)  评论(1)    收藏  举报