从Ecma范例深切明白this

this是面向对象编程中的一个观点,它平常指向当前要领挪用地点的对象,这一点在java、c++这类比较严厉的面向对象编程言语里是异常明白的。但是在javascript中,this的定义要天真许多,假如未正确控制,异常轻易殽杂。本人在口试过程当中也发明,口试者很少有由能够回复得异常周全的。本文总结了this的各种状况,并从Ecma范例的角度探讨了this的细致完成,愿望对人人明白this有所协助。

this指向的四中状况

在javascript内里,this的指向能够归结为以下四种状况。只需能切记这四种状况,大部分状况下就已够用了。

1.在全局代码或许一般的函数挪用中,this指向全局对象,在浏览器内里既为window对象。

    console.log(this);//输出window
    
    function foo(){
        console.log(this);
    }
    foo();//输出window

在浏览器环境里运转上述代码,两处输出效果均为window对象。

2.经由过程call或apply要领挪用函数,this指向要领挪用的第一个参数。

    var obj = {name:'test'};
    
    function foo(){
        console.log(this);
    }
    
    foo.call(obj);//输出obj
    foo.apply(obj);//输出obj

在浏览器环境里实行以上代码,输出效果均为对象obj。call和apply除了参数情势不一样外其他都一样,call采纳逗号支解,apply采纳数组。说到这里,趁便引见一个小技能。如安在不天生新数组的状况下完成两个数组的衔接?请看下面的代码。

    var arr1 = [1, 2 , 3],
        arr2 = [4, 5, 6];
    Array.prototype.push.apply(arr1, arr2);
    
    console.log(arr1);//输出[1, 2, 3, 4, 5, 6]

实行上述代码后,输出效果为[1, 2, 3, 4, 5, 6]。这是一个异常有用的小技能,由于apply第二个参数为数组情势,所以我们能够把push要领“借”过来,从而完成两个数组的衔接。

3.挪用对象的要领,this指向该对象。

    var obj = {name:'test'};
    
    function foo(){
        console.log(this);
    }
    obj.foo = foo;
    
    obj.foo();//输出obj

实行以上代码后,控制台输出为obj对象。这就是我们常说的“谁挪用,指向谁”。

4.组织要领中的this,指向新组织的对象。

    function C(){
        this.name = 'test';
        this.age = 18;
        console.log(this);
    }
    var c = new C();//输出 c
    console.log(c);//输出 c

实行以上代码后,控制台输出均为c所指向的对象。当new操作符用于函数时,会建立一个新对象,并用this指向它。

Ecma范例

Ecma范例内里细致引见了this的完成细节,经由过程浏览范例,我们能够更正确的明白上述四种状况究竟是怎样回事。
函数对象有一个叫[[Call]]内部要领,函数的实行实际上是经由过程[[Call]]要领来实行的。[[Call]]要领吸收两个参数thisArg和argumentList,thisArg和this的指向有直接关联,argumentList为函数的实参列表。thisArg又是怎样来的呢?我们能够和前面议论的四种状况对应起来:

  1. 一般要领挪用thisArg为undefined。

  2. 经由过程call或apply挪用,thisArg既为第一个参数。

  3. 经由过程对象挪用,thisArg指向该对象。

  4. 在组织要领中,thisArg为新组织的对象。

thisArg和this是什么关联?范例里的形貌是如许的:

  1. If the function code is strict code, set the ThisBinding to thisArg.

  2. Else if thisArg is null or undefined, set the ThisBinding to the global object.

  3. Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).

  4. Else set the ThisBinding to thisArg.

在严厉形式下,thisArg和this是一一对应的。

function foo(){
    'use strict';
    console.log(this);
}
foo();//输出undefined

该示例输出的效果为undefined。

第二点是说假如thisArg为null或许undefined则this指向全局对象。

function foo(){
    console.log(this);
}
foo.call(null);//输出window

该示例的输出效果为window。

第三点说假如thisArg为非对象范例,则会强迫转型成对象范例。

function foo(){
    console.log(this);
}
var aa = 2;
console.log(aa);//输出2
foo.call(aa);//输出 Number

这里的输出效果分别为2和Number,它将基础范例转型成了对象包装范例。

第四点申明剩下的状况thisArg和this为一一对应的关联。

范例内里对this指向的形貌照样比较明白的。只需你搞清楚thisArg怎样肯定,thisArg和this的对应关联,那末你就可以搞定一切this的状况了。

确保this的指向

在实际使用this的过程当中,遇到得最多得一个题目能够就是上下文丧失的题目了。由于javascript中的函数是能够作为参数通报的,那末其他对象在实行回调函数时就能够形成回调函数本来的上下文丧失,也就是this的指向改变了。

var C = function(){
    this.name = 'test';
    this.greet = function(){
        console.log('Hello,I am '+this.name+'!');
    };
}
var obj = new C();

obj.greet();//输出 Hello,I am test!

setTimeout(obj.greet, 1000);//输出 Hello,I am !

可见第二条输出中this的值改变了,实在我们是愿望this能够指向obj的。处理该题目的要领有两种。

1.bind要领。
bind要领经由过程闭包奇妙地完成了上下文的绑定,它实际上是将原要领包装成了一个新要领。平常的完成以下:

Function.prototype.bind = function(){
    var args = arguments,
        thisArg = arguments[0],
        func = this;
    return function(){
        var arg = Array.prototype.slice.call(args, 1);
        Array.prototype.push.apply(args, arguments);
        return func.apply(thisArg, arg);
    }
}

前面的示例代码我们只需要加上bind,就可以够获得我们愿望的效果了。

...
setTimeout(obj.greet.bind(obj), 1000);//输出 Hello,I am test!
...

2.es6箭头函数。
es6内里供应了一个新的语法糖,箭头函数。箭头函数的this不再变化多端,它永久指向函数定义时的this值。

var C = function(){
    this.name = 'test';
    this.greet = ()=>{
        console.log('Hello,I am '+this.name+'!');
    };
}
var obj = new C();

obj.greet();//输出 Hello,I am test!

setTimeout(obj.greet, 1000);//输出 Hello,I am test!

我们将前面的示例该成箭头函数后,两处的输出效果一样了。this的值不再改变了,这是我们想要的。

小结

this看起来是个异常小的知识点,实在挖起来照样有许多细节的,特别是范例内里的一些定义,本人以为关于一个js程序员来讲是异常重要的。本人背面也预备找些ecma范例内里的知识点和人人分享,愿望能对人人有所协助。由于本人才能有限,若有明白毛病的处所还望指出。

    原文作者:crossea
    原文地址: https://segmentfault.com/a/1190000003906484
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞