我看过这些调用,应用和绑定的例子
var fruit = { name: 'Strawberry' }
function showDetails(size, price) {
console.log(this.name + ' ' + size + ': $' + price + '/lb')
}
showDetails.apply(fruit, ['small', 10])
// Strawberry small: $10/lb
showDetails.call(fruit, 'small', 10)
// Strawberry small: $10/lb
var bound = showDetails.bind(fruit, 'small', 10)
bound()
//Strawberry small: $10/lb
showDetails.bind(fruit, 'small', 10)()
// Strawberry small: $10/lb

这里所有函数都做同样的事情并检查下面的代码,不使用任何这些(调用,应用和绑定)
var fruit = { name: 'Strawberry' };
function showDetails(size, price) {
console.log(this.name + ' ' + size + ': $' + price + '/lb')
}
fruit.show =showDetails;
fruit.show(small,10); //Strawberry small: $10/lb

它的工作方式和预期的一样,为什么,我们什么时候需要调用,应用和绑定。
如何在ES6中使用这些功能?
答案 0 :(得分:2)
call
和apply
因为它们比替代方案简单得多(显然取决于用例)call
和apply
,因为替代方法不适用于我们无法分配属性的对象(冻结或密封)call
和apply
我们还需要apply
,因为call
无法使用动态数量的参数(忽略新的扩展语法),请参阅What is the difference between call and apply?。 bind
是一个完全不同的野兽,请参阅Javascript call() & apply() vs bind()?。
答案 1 :(得分:2)
实际上,在许多情况下,在对象上定义方法将是可行的替代方案。但是,有时它不是一个选项:
"use strict";
function showDetails() { console.log(this.name); }
var obj = Object.seal({ name: 'Strawberry' });
showDetails.call(obj); // Strawberry
obj.showDetails = showDetails; // fails

function name() { console.log(this.name) }
var obj = Object.seal({ name: 'Strawberry' });
name.call(obj); // Strawberry
obj.name = name;
obj.name(); // does not show 'Strawberry', but the function

如果所述属性为只读(使用defineProperty
和writable: false
),它也可能失败。
假设该功能执行自检,例如它计算它拥有的属性数量:
function memberCount() { return Object.keys(this).length; };
var obj = { name: 'Strawberry' };
console.log(memberCount.call(obj)); // 1
obj.count = memberCount;
console.log(obj.count()); // 2

对于您期望某种行为的对象(如数组:
),这尤其是一个问题
function first() { return this[0]; };
var arr = ['Strawberry', 'Banana'];
console.log(first.call(arr)); // Strawberry
arr.first = first;
// ...
for (var i in arr) { // Iterate through array
if (arr.hasOwnProperty(i)) {
console.log(arr[i]); // Oops, the function appears also.
}
}

apply
和bind
还有其他一些例子,如果目标对象已经 方法,则使用apply
或bind
非常有用:
apply
可以与需要单独参数的方法一起使用,而您只需要一组值。在ES6中,您可以使用扩展语法来克服这个问题,但传统上,apply
就是解决此问题的方法。
例如,要获取数组中的最小值:
var arr = [5,3,1,6,2];
console.log(Math.min.apply(Math, arr));

bind
方法通常用于将方法作为回调传递,但您需要将其绑定到对象:
var obj = {
flavour: 'Strawberry',
smell: function () { console.log(this.flavour) }
};
window.addEventListener('load', obj.smell); // ......> undefined
window.addEventListener('load', obj.smell.bind(obj)); // .....>Strawberry

必须绑定this
,仍然可以使用这些方法。但是使用箭头函数语法,this
保留其词法值,并将this
参数传递给apply
,call
或bind
这样的函数无效。通常它也变得不必要,因为词汇this
通常正是所需要的。
以获取数组的最小值为例。使用ES6,可以写成如下:
const arr = [5,3,1,6,2,4];
console.log(Math.min(...arr));

或者举例说明一个方法(使用this
)作为回调传递:
class Cls {
constructor() {
this.flavour = 'Strawberry'
this.smell = () => console.log(this.flavour)
}
};
window.addEventListener('load', (new Cls).smell); // ......> Strawberry

答案 2 :(得分:0)
我们可以通过在javascript中将对象附加到对象来实现相同的功能
根据你的例子你是对的。但是在javascript中我们需要将函数作为回调函数传递给browser-event-loop-queue来执行异步。在这种情况下,对象将丢失。请查看以下示例
var fruit = { name: 'Strawberry' };
function showDetails(size, price) {
console.log(this.name + ' ' + size + ': $' + price + '/lb')
}
fruit.show =showDetails;
setTimeout(fruit.show, 100);
这里的输出是未定义的,所以要附加参数和上下文对象,我们需要“bind”
现在我们可以使用
进行上述工作了 setTimeout(fruit.show.bind(fruit, size, price), 100);
用于apply / call是通过动态提供其上下文和参数来执行函数。检查以下呼叫的使用情况。
var Array.protoype.forEach = function(cb /*, thisArg*/){
var T;
if (arguments.length > 1) {
T = arguments[1];
}
for(var i =0; i<this.length; i++){
cb.call(T, this[i], i, this);
}
}