改变this指向

43 阅读2分钟

1. call

call方法可以指定this的指向,然后在指定的作用域中,执行函数。

A.call(B)
调用A方法,但是this指向B这个对象


var obj = {};
var f = function() {
    return this;
}
console.log(f() === window); // this指向window
console.log(f.call(obj) === obj); // this指向obj

call方法的参数,应该是对象,如果参数为空,null,undefined,则默认传全局对象。

如果call传参不是以上类型,则转化为对应的包装对象,例如:

var f = function() {
    return this;
};
console.log(f.call(4)); // Number对象

call可以接受多个参数,第一个是this指向的对象,之后的参数是参数列表,这些参数会传递给前边的方法

call一个经常的应用,就是调用原生方法

var obj = {};
console.log(obj.hasOwnProperty("toString")); // false
console.log(obj.toString()); // [object Object]

// 上面的例子证明,obj可以调用toString方法,但是toString这个方法不是自身拥有的
// 来自于它的原型对象上面

obj.hasOwnProperty = function() {
    return "aaa";
}
console.log(obj.hasOwnProperty("toString")); // aaa
// 如果上面我们对hasOwnProperty这个方法进行了覆盖,不能得到想要的结果
// 使用call可以调用原生的方法
console.log(Object.prototype.hasOwnProperty.call(obj, "toString"))

2.apply

apply和call作用类似,也是改变this的指向,然后调用该函数,唯一区别是apply接受数组作为函数执行时的参数,语法如下:

func.apply(thisValue,[arg1,arg2,...])

配合数组对象的slice方法,可以将一个类似数组的对象转为真正的数组。

Array.prototype.slice.apply({0:1, length: 1}) // [1]

3. bind

bind用于将函数体内的this绑定到一个对象,然后返回一个新函数

var d = new Date();
console.log(d.getTime());

var fn = d.getTime;
fn();
// 上面的调用方式,使得this指向了全局对象,而非Date
// 下面使用bind绑定
var fn = d.getTime.bind(d);
console.log(fn());

bind的另一种用法

// call方法来源于Function.prototype
var slice = Function.prototype.call.bind(Array.prototype.slice);
// 这里相当于改写了slice方法
// 以前调用slice方法[1,2,3].slice(0,1)
console.log(slice([1,2,3], 0, 1));
function fn() {
    console.log(this.v);
}

var obj = {
    v: 123
}

var func = Function.prototype.call.bind(Function.prototype.bind);
func(fn, obj)();

上面代码打的含义是,将Function.prototype.bind方法绑定在Function.prototype.call上面,所以bind方法就可以直接使用,不需要在函数实例上使用