JavaScript函数中的this四种绑定形式(2)

var obj = { a: 1, // a是定义在对象obj中的属性 1 fire: function () { console.log(this.a) } } var a = 2; // a是定义在全局环境中的变量 2 var fireInGrobal = obj.fire; fireInGrobal(); // 输出 2

上面这段简单代码的有趣之处在于: 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,其原因在于:我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window 

上面的例子稍微变个形式就会变成一个可能困扰我们的bug: 

在上面,我们的

var a = 2; var obj = { a: 1, // a是定义在对象obj中的属性 fire: function () { console.log(this.a) } } function otherFire (fn) { fn(); } otherFire(obj.fire); // 输出2

关键角色是otherFire函数,它接受一个函数引用作为参数,然后在内部直接调用,但它做的假设是参数fn仍然能够通过this去取得obj内部的a属性,但实际上, this对obj的绑定早已经丢失了,所以输出的是全局的a的值(2),而不是obj内部的a的值(1)

在一串对象属性链中,this绑定的是最内层的对象

在隐式绑定中,如果函数调用位置是在一串对象属性链中,this绑定的是最内层的对象。如下所示:

var obj = { a: 1, obj2: { a: 2, obj3: { a:3, getA: function () { console.log(this.a) } } } } obj.obj2.obj3.getA(); // 输出3

this的显式绑定:(call和bind方法)

【故事——线路3】 迪斯(this)穿越来异世界“伽瓦斯克利”(javascript),经过努力的打拼,积累了一定的财富,于是他买下了自己的房子

JavaScript函数中的this四种绑定形式

上面我们提到了this的隐式绑定所存在的this绑定丢失的问题,也就是对于 “ fireInGrobal = obj.fire”

fireInGrobal调用和obj.fire调用的结果是不同的,因为这个函数赋值的过程无法把fire所绑定的this也传递过去。这个时候,call函数就派上用场了

call的基本使用方式: fn.call(object)

fn是你调用的函数,object参数是你希望函数的this所绑定的对象。

fn.call(object)的作用:

1.即刻调用这个函数(fn)

2.调用这个函数的时候函数的this指向object对象 

例子:

var obj = { a: 1, // a是定义在对象obj中的属性 fire: function () { console.log(this.a) } } var a = 2; // a是定义在全局环境中的变量 var fireInGrobal = obj.fire; fireInGrobal(); // 输出2 fireInGrobal.call(obj); // 输出1

原本丢失了与obj绑定的this参数的fireInGrobal再次重新把this绑回到了obj 

但是,我们其实不太喜欢这种每次调用都要依赖call的方式,我们更希望:能够一次性 返回一个this被永久绑定到obj的fireInGrobal函数,这样我们就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。 

怎么办呢? 聪明的你一定能想到,在fireInGrobal.call(obj)外面包装一个函数不就可以了嘛!

var obj = { a: 1, // a是定义在对象obj中的属性 fire: function () { console.log(this.a) } } var a = 2; // a是定义在全局环境中的变量 var fn = obj.fire; var fireInGrobal = function () { fn.call(obj) //硬绑定 } fireInGrobal(); // 输出1

如果使用bind的话会更加简单

var fireInGrobal = function () { fn.call(obj) //硬绑定 }

可以简化为:

var fireInGrobal = fn.bind(obj);

call和bind的区别是:在绑定this到对象参数的同时: 

1.call将立即执行该函数

2.bind不执行函数,只返回一个可供执行的函数 

【其他】:至于apply,因为除了使用方法,它和call并没有太大差别,这里不加赘述 

在这里,我把显式绑定和隐式绑定下,函数和“包含”函数的对象间的关系比作买房和租房的区别。 

JavaScript函数中的this四种绑定形式

因为this的缘故

在隐式绑定下:函数和只是暂时住在“包含对象“的旅馆里面,可能过几天就又到另一家旅馆住了

在显式绑定下:函数将取得在“包含对象“里的永久居住权,一直都会”住在这里“

new绑定

【故事】 迪斯(this)组建了自己的家庭,并生下多个孩子(通过构造函数new了许多个对象) 

JavaScript函数中的this四种绑定形式

执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyddzd.html