函数中this的绑定

函数中的this总指向调用它的对象。

默认绑定

当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象。

凡是函数作为独立函数调用,无论它的位置在哪里,它的行为表现,都和直接在全局环境中调用无异。

//1
function fire () {
	console.log(this === window)
}
fire();//true

//2
function innerFire() {
	console.log(this === window)
}
function fire () {
	innerFire();
}
fire();//true

//3
function fire () {
	function innerFire() {
		console.log(this === window)
	}
	innerFire();
}
fire();//true
//不要顾虑于fire函数的作用域对innerFire的影响,
//只要牢记:没有明确的调用对象时,将对函数的this使用默认绑定:绑定到全局的window对象

隐式绑定

当函数被一个对象“包含”的时候,我们称函数的this被隐式绑定到这个对象里面了,这时候,通过this可以直接访问所绑定的对象里面的其他属性。

//下面这两段代码的效果和性质相同
//1
var obj = {
	a:1,
	fire:function() {
        console.log(this.a)
	}
}
obj.fire();//1

//2
function fire () {
    console.log(this.a)
}
var obj = {
    a:1,
    fire:fire
}
obj.fire();//1

fire函数并不会因为它被定义在obj对象的内部和外部而有任何区别,也就是说在上述隐式绑定的两种形式下,fire通过this还是可以访问到obj内的a属性,这告诉我们:

1. this是动态绑定的,或者说是在代码运行期绑定而不是在书写期
2. 函数于对象的独立性, this的传递丢失问题

隐式绑定下,作为对象属性的函数,对于对象来说是独立的。基于this动态绑定的特点,写在对象内部,作为对象属性的函数,对于这个对象来说是独立的。(函数并不被这个外部对象所“完全拥有”)

在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)

定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”。

借用下面的隐式绑定中的this传递丢失问题来说明:

var obj = {
	a: 1,    //定义在对象obj中的属性a   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,
	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

显式绑定:(call、apply和bind方法)

上面我们提到了this的隐式绑定所存在的this绑定丢失的问题,也就是对于 “ fireInGrobal = obj.fire”;fireInGrobal调用和obj.fire调用的结果是不同的,因为这个函数赋值的过程无法把fire所绑定的this也传递过去。这个时候,call函数就派上用场了。(apply方法和call方法类似,只是传参略有不同,故在此只使用call进行举例)

call的基本使用方式: fn.call(object);fn是调用的函数,object参数是希望函数的this所绑定的对象。
fn.call(object)的作用:
1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象

var obj = {
    a: 1,
    fire:function() {
        console.log(this.a)
    }
}
var a = 2;
var fireInGrobal = obj.fire;
fireInGrobal();  //2
fireInGrobal.call(obj);//1

每次调用都要依赖call的方式有点麻烦,我们更希望:能够一次性返回一个this被永久绑定到obj的fireInGrobal函数,这样就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。其实只要在fireInGrobal.call(obj)外面包装一个函数就可以解决这个问题。

var obj = {
    a: 1,
    fire:function() {
    	console.log(this.a)
    }
}
var a = 2;
var fn = obj.fire;
var fireInGrobal = function() {
    fn.call(obj)  //硬绑定
}
fireInGrobal();//1

更简单的方法是使用bind

var obj = {
    a: 1,
    fire:function() {
    	console.log(this.a)
    }
}
var a = 2;
var fn = obj.fire;
var fireInGrobal = fn.bind(obj);
fireInGrobal();//1

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

1.call、apply将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数

new绑定

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

function foo (a) {
    this.a = a;
}
var a1  = new foo (1);
var a2  = new foo (2);
var a3  = new foo (3);
var a4  = new foo (4);
console.log(a1.a);//1
console.log(a2.a);//2
console.log(a3.a);//3
console.log(a4.a);//4

原文连接:【javascript】函数中的this的四种绑定形式 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值