Function.prototype.call()
使用call()方法可以编写一个可用于不同对象的方法。换句话说,使用call(),一个对象可以使用属于另一个对象的方法。更多信息
const person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
const person1 = {
firstName:"John",
lastName: "Doe"
}
const person2 = {
firstName:"Mary",
lastName: "Doe"
}
console.log(person.fullName.call(person1));
call()函数允许将一个对象中的函数/方法分配并调用到另一个对象中。
使用call()可以为函数/方法提供一个新的this值。使用call(),你可以编写一个方法,然后在另一个对象中继承它,而不必为新对象重写该方法。
> 使用call链接对象的构造函数
你可以使用call()来链接对象的构造函数(类似于Java)。
以下示例中,Product对象的构造函数被定义为具有两个参数:name和price。
Food和Toy两个函数调用Product,并传递this,name和price。Product初始化属性name和price,这两个特定的函数定义了category。
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
const cheese = new Food('feta', 5);
const fun = new Toy('robot', 40);
console.log(cheese);
console.log(fun);
>使用call调用匿名函数
在这个例子中,我们创建一个匿名函数,并使用call在数组中的每个对象上调用它。
这里匿名函数的主要目的是为每个对象添加一个打印函数,该函数能够打印对象在数组中的正确索引。
const animals = [
{ species: 'Lion', name: 'King' },
{ species: 'Whale', name: 'Fail' }
];
for (let i = 0; i < animals.length; i++) {
(function(i) {
this.print = function() {
console.log('#' + i + ' ' + this.species
+ ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}
> 使用call方法调用函数并指定'this'的上下文
在下面的例子中,当我们调用greet函数时,this的值将被绑定到obj对象。
function greet() {
const reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
console.log(reply);
}
const obj = {
animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj);
> 使用 call 来调用函数,且没有指定第一个参数
在下面的示例中,我们调用 display 函数时没有传递第一个参数。如果没有传递第一个参数,this 的值将绑定到全局对象。
var sData = 'Wisen';
function display() {
console.log('sData value is %s ', this.sData);
}
display.call();
注意:在严格模式下,this的值将为undefined。请看下文。
'use strict';
var sData = 'Wisen';
function display() {
console.log('sData value is %s ', this.sData);
}
display.call();
Function.prototype.bind()
bind() 方法创建一个新的函数,在调用时将其this关键字设置为提供的值,并在调用新函数时提供任何提供的一系列参数之前。
如需了解更多,请访问参考文档
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX());
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
> 创建一个绑定函数
bind() 最简单的用法是创建一个函数,无论如何调用它,都会使用特定的 this 值。
新的 JavaScript 程序员常犯的一个错误是从对象中提取一个方法,然后稍后调用该函数,并期望它将原始对象作为其 this(例如,在基于回调的代码中使用该方法)。
然而,通常情况下,原始对象会被忽略。通过从该函数创建一个绑定函数并使用原始对象可以很好地解决这个问题:
this.x = 9;
const module = {
x: 81,
getX: function() { return this.x; }
};
module.getX();
const retrieveX = module.getX;
retrieveX();
const boundGetX = retrieveX.bind(module);
console.log(boundGetX());
> 部分应用函数
bind() 的下一个最简单的用途是创建一个带有预定义初始参数的函数。
这些参数(如果有)跟随所提供的this值,然后被插入到传递给目标函数的参数开头,接着是在调用绑定函数时传递的任何参数。
function list() {
return Array.prototype.slice.call(arguments);
}
function addArguments(arg1, arg2) {
return arg1 + arg2;
}
const list1 = list(1, 2, 3);
const result1 = addArguments(1, 2);
const leadingThirtysevenList = list.bind(null, 37);
const addThirtySeven = addArguments.bind(null, 37);
const list2 = leadingThirtysevenList();
const list3 = leadingThirtysevenList(1, 2, 3);
const result2 = addThirtySeven(5);
const result3 = addThirtySeven(5, 10);
> 使用setTimeout()
默认情况下,在setTimeout()内部,this关键字会被设置为window(或global)对象。当使用需要将this指向类实例的类方法时,可以显式地将this绑定到回调函数中,以维护实例。
function LateBloomer() {
this.petalCount = Math.floor(Math.random() * 12) + 1;
}
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
console.log(`I am a beautiful flower with ${this.petalCount} petals!`);
};
const flower = new LateBloomer();
flower.bloom();
如果你想了解更多关于bind方法的内容,请阅读这个资源
this
作为它的第零个参数,然后在bind
、call
和apply
的调用中部分地提供它的参数。那绝对是不正确的。但我看到如果我绑定了this
,然后想使用call
调用绑定的函数,我只需要在call
中提供一些foo值作为第一个参数。这很好。但我仍然不能接受你的答案,因为它没有解释为什么多个绑定不像部分应用程序那样行为。 - Martin Peckabind
。这就是我想知道的 :) 从你的回答中并不清楚它也适用于进一步参数的部分应用,对我来说似乎你只是在谈论上下文参数。谢谢 ;) - Martin Peckathis
的事实更加微妙。 - ZER0