likes
comments
collection
share

干翻this这座大山(二)

作者站长头像
站长
· 阅读数 39

前言

在上一篇文章中,我们知道了this的基本指向规则。在这一篇章的内容中我们将继续深入学习this的

一,显式绑定

要想“掰弯”this改变他的指向我们通常有三种方法:利用call,applybind

1. 用callapply进行显式绑定

大家来看这段代码

var obj = {
    a: 1
}

function foo() {
    console.log(this.a);
}

foo() 

经过上一篇章的学习相信大家已经能秒杀这道题,这不一眼foo独立调用this指向全局嘛,结果显而易见undefined。但是现在如果我想让这个this指向obj我该怎么做呢?这个时候我们的call就登场了~

在JavaScript中,call 是一个内建函数,属于函数原型 (Function.prototype.call),它允许你调用一个函数,并指定该函数的 this 值(函数运行时上下文中的 this 指向),以及作为单独参数传入的列表。在本题中,在调用foo函数时,你可以使用点语法和call方法来指定foo函数内部this的指向,通过call方法的参数来传入你希望this所引用的对象。那如果需要传参数呢?当foo函数需要参数xy时,并且你同时还想使用call方法来指定this的指向,你可以将需要传递给foo的参数直接放在call方法的参数列表中,且这些参数应该放在你想要作为this的对象之后。,如下

var obj = {
    a: 1
}

function foo(x, y) {
    console.log(this.a, x + y);
}

foo.call(obj, 2, 3) // 1 5

经过我们.call的修改,this成功的指向了obj且接受了参数。打印出来的结果分别是this指向的a的值1,和x+y的值5。

除了call之外,apply同样也能达到同样的效果,唯一不同的是他们的参数传递方式。apply接收的参数需要用数组装起来,如foo.call(obj, 2, 3)需改写成foo.apply(obj,[ 2, 3])的形式。

2.使用bind进行显式绑定

bind 方法是 JavaScript 中的一个函数实例方法,它用于创建一个新的函数,这个新函数在被调用时,其 this 关键字会被设置为提供的值,同时会创建一个新的函数上下文(返回一个函数体)。

var obj = {
    a: 1
}

function foo(x, y) {
    console.log(this.a, x + y);
}

var bar = foo.bind(obj,2,3) 
bar()

题中 bind返回的是一个新函数bar,并且这个新函数在被调用时()才会执行原始函数,这个性质由bind的源码决定。值得注意d的是,无论参数在bind()内还是在他返回的函数体bar()内他都能接收且执行,如果两者都传入了参数,则只有bind()内的参数生效。

二,new绑定

要明白构造函数里的this指向我们首先得搞懂new的底层执行机制,new,他到底做了哪些事情?

在《对象的基本知识,对构造函数的基本认识》一文中我们简要概述了new的作用三部,但在今天学习了原型和this这两篇文章后我们对new又有了新的认识。

new的作用

new他到底做了什么?举个例子,对于代码

function Person(){
    this.name = 'tao'
}
let p = new Person()

来说,如果没有下面new的构造,this势必会指向全局,

  1. new第一步在这个函数体内创建一个新的空对象,例obj;
  2. 设置新对象的[[Prototype]](内部链接),新对象的[[Prototype]]会被设置为Person.prototype。 Object.proto = Person.prototype;使得obj的隐式原型等于Person的显示原型;
  3. 构造函数(在这个例子中是Person)会被调用,同时传入new操作符创建的新对象作为this的上下文。这意味着,构造函数内部有任何对this的引用,它们都将指向这个新创建的对象。 也可以理解为两步操作:1)在代码执行前new做了一步“掰弯操作”,Person.call(obj),这一步把Person中的所有的this引用都指向了obj;2)执行代码
  4. 返回新对象。return obj

实际产生的效果等同如下:

function Person() {
    //var obj(){
    //
    // }
    // person.call(obj);
    // Object.__proto__ = person.prototype;

    this.name = 'zhutao'
    // return new Person
}

所以这里的答案显而易见, 所以现在我们明白了new 绑定的规则: 通过new创建一个函数,this指向他创建的这个函数。

三,箭头函数中的this

什么是箭头函数

箭头函数是定义函数的一种新方式。箭头函数(Arrow Functions)是ES6(ECMAScript 2015)中引入的一种新的函数定义方式。箭头函数提供了一种更简洁、更直观的语法来编写函数,特别是在处理一些简单的回调函数或者不需要自己this绑定的场景时非常有用。 对于代码串var bar = () => {}来说,var定义了一个变量bar,箭头函数语法将其赋值给变量 bar。他和var bar = function(){}的表达相同,但是在行为上有所不同。

箭头函数的this 绑定

在JavaScript中,箭头函数(Arrow Functions)有一个特殊的特性,那就是它们不绑定自己的this值。相反,箭头函数会从自己的作用域链的上一层(词法作用域)中捕获this值作为自己的this值。这通常意味着箭头函数中的this值就是定义它所在的那个上下文中的this值。

箭头函数体,没有this这个机制,写在他里面的this是他外层非箭头函数的this。不能说箭头函数的this,这句话是错的,因为箭头函数没有this这个机制(没有这个概念)

function foo() {
    var bar = () => {
        console.log(this);
    }
    bar()
}
foo()

所以我们来看这串代码,箭头函数里面的this理所应当的指向foo函数。

在本篇的最后让我们再看一道题回顾这两篇所学的知识:

var obj = {
    a: 1,
    b: function () {
        const fn = () => {
            console.log(this.a)
        }
    }
}
obj.b()

请问this指向谁?

首先,b不是独立调用,所以是隐式绑定规则;其次,箭头函数在function b内,所以this在b内。b在obj里面,且b的词法作用域是obj,所以答案显而易见,this指向obj,this.a的值是1。

转载自:https://juejin.cn/post/7369114828076515364
评论
请登录