Skip to content

《嗨,听说你很懂 this?我不太相信!》 #11

@wangsiyuan0215

Description

@wangsiyuan0215

《嗨,听说你很懂 this?我不太相信!》

this 绑定的方式主要有四种, new 绑定 > 硬绑定(显示绑定) > 隐式绑定 > 默认绑定。

new 绑定:

使用 new 关键字来调用函数,会执行一下的过程:

  • 创建一个新对象;
  • 将构造函数的作用域赋值给新对象,即 this 指向这个对象;
  • 将新对象的原型对象指针指向构造函数的原型对象;
  • 执行构造函数中的代码;
  • 返回新对象。

因此,我们使用 new 来调用函数的时候,就会将新对象绑定到构造函数的 this 上。

硬绑定

通过 bind/apply/call 的方式显式的绑定 this(更改 this 的指向)。

一般的调用过程比较容易理解,在这篇文章中有一处不太好理解的就是:

function sayHi(){
    console.log('Hello,', this.name);
}
var person = {
    name: 'YvetteLau',
    sayHi: sayHi
}
var name = 'Wiliam';
var Hi = function(fn) {
    fn();
}
Hi.call(person, person.sayHi); 

调用结果为:Hello, Wiliam

原文是这么解释的:

Hi.call(person, person.sayHi) 的确是将 this 绑定到 Hi 中的 this 了。但是在执行 fn 的时候,相当于直接调用了 sayHi 方法 (记住: person.sayHi 已经被赋值给 fn 了,隐式绑定也丢了),没有指定 this 的值,对应的是默认绑定。

而我觉得可以这么理解,首先 Hi.call(person, person.sayHi) 确实是将 Hi 函数的 this 显式的绑定到了 person 对象,但是由于对于引用类型的参数传递是基于引用赋值的,也就是说 Hi 函数的参数 fn 此时指向 person.sayHi,而二者均指向全局的 sayHi 函数。

Hi.call(...) 会调用 Hi 函数,执行 Hi 函数内部的代码 —— 仅仅执行了 fn(),由于 sayHi 函数中的 this 没有 new 绑定,没有隐式绑定(因为 fn 仅仅单纯的指向了 sayHi),更没有显示绑定,那么最后只能是默认绑定了。

隐式绑定

函数的调用是在某个对象上执行的,即存在于上下文对象之中。

隐式绑定是很容易丢失的,容易到仅仅通过赋值就可以丢失 this 的绑定:

function sayHi(){
    console.log('Hello,', this.name);
}
var person = {
    name: 'YvetteLau',
    sayHi: sayHi
}
var name = 'Wiliam';
var Hi = person.sayHi;
Hi();

上述代码的结果为:Hello, Wiliam。原因上述涉及到了,仅仅因为引用类型赋值属于引用赋值,也就是说 Hi 和 person.sayHi 在内存中同时指向 sayHi 的地址,执行 Hi 时其实就是在执行 sayHi 函数,由于调用 Hi 时并没有任何的上下文对象,因此采用的是默认绑定 —— 绑定到全局变量(仅仅针对此种情况)。

默认绑定

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

这里不做过多的解释了。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions