call是做什么用的?
JS中使用原型思想。如果一个obj原型链上没有特定的方法,那么JS就不知道如何调用它。比如一个类数组对象(ex. HTMLCollection)就没有好用的数组方法。
但是类数组对象与数组的结构几乎一致,为什么就不能使用数组的方法呢?
所以JS给我们提供了一种方法,能够告诉JS,我们指定了obj像Array一样运作,例如Array.prototype.map.call(obj)
查看示例:
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
Food是没有name和price属性的。但是为了继承Product的一系列属性,Food在构造过程中call了Product的构造函数。
看到了?这也是继承的一种方法。
其实当我们调用对象上的方法时,写成obj.func(...args)
,其内部实现也是func.call(obj, ...args)
。
语法:
fun.call(thisArg, arg1, arg2, ...)
call和apply的区别?
根据MDN,两者只有一个区别,就是call()
方法接受的是若干个参数的列表,而apply()
方法接受的是一个包含多个参数的数组。
刚才是fun.call(thisArg, arg1, arg2, ...)
现在是fun.apply(thisArg, [arg1, arg2, ...])
能看出来吗?就差这么一点。
bind
这里涉及到this
的指向问题。当我们调用一个函数时,函数中的this会指向当前调用函数的对象。
bind()方法相当于创建一个新函数,不管调用这个函数的对象是谁,this
都将会指向绑定的对象。
Function.prototype.bind()-MDN
语法:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
还是看例子:
var module = {
x: 42,
getX: function() {
return this;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX());
// > [object Window]
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
/*
> Object { x: 42, getX: function() {
return this;
} }
*/
在不使用bind时,调用unboundGetX()方法的对象是window,所以this
指向window。
当用bind绑定module时,this
重新指向了module。
一些比较重要的补充:
1. bind()函数在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。如果不能运行,可以在脚本开头加入腻子:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
}
你不用看懂,只要把这段代码贴到开头就好了。
2. 匿名函数和箭头函数:
匿名函数的this
通常会指向全局window,这很适合使用bind做出改变。
示例:
var module = {
x: 42
}
var unboundGetX = function(){return this};
console.log(unboundGetX())
// > [object Window]
var boundGetX = function(){return this}.bind(module);
console.log(boundGetX())
// > Object { x: 42 }
但是!箭头函数会默认做一个bind(this)的操作,也就是箭头函数是不能使用bind的
var boundGetX = ()=>{return this}.bind(module);
console.log(boundGetX())
// Error: Unexpected token .
网友评论