为什么在javascript中我们可以直接调用方法,却需要使用call或apply方法呢?

3
为什么要在JavaScript中使用Call或Apply方法?除了参数的差别之外,普通方法调用和使用Call/Apply的主要区别是什么?如果您能通过场景举例加以解释,那就更好了。
5个回答

2

2

你可能已经知道,在JavaScript中函数是一等公民。这意味着你可以将它们作为参数传递给其他函数。

在某些情况下,你需要处理依赖于上下文的方法。例如:

const button = document.querySelector('button');
const getRect = button.getBoundingClientRect;

getRect(); // TypeError...

// You have to pass a context fo that function
getRect.call(button);

还有一些其他传递上下文的函数。请查看applybindcall等...

callapply的另一个很好的使用示例是monkey-patching

// Save the original console.log() method
var log = console.log;

console.log = function() {
   // Invoke the original method with an additional parameter
   log.apply(console, [(new Date()).toString()].concat(arguments));
};

Kyle Simpson在他的系列教程《你不知道的JavaScript》中有很好的解释。


1
我可以给你两个例子来解释为什么这很重要。假设你有一个如下所示的类:
class MyClass {
  myProp = 'Hello World';
  myMethod() {
    console.log(this.myProp);
  }
}

假设您想在按钮点击事件中调用myMethod。您需要执行以下操作:
const myInstance = new MyClass();
document.querySelector('button').addEventListener('click', myInstance.myMethod);

现在有一个问题:使用addEventListener时,执行上下文会发生变化,this指向元素而不是类实例(该实例上没有myProp属性)。如何将其改回来?在这种情况下,您可以使用bind
document.querySelector('button').addEventListener('click', myInstance.myMethod.bind(myInstance));

这实质上将引用更改回类。这只是一个例子。有很多例子可以改变方法的当前执行上下文。我们来看另一个例子:
假设有一个第三方函数需要访问某些类成员。
第三方函数需要目标实例的“name”和“lastname”属性。
function getFullName() {
  return this.name + ' ' + this.lastname;
}

如果你执行这个方法时没有使用callapply,该方法会默认当前实例(在这种情况下是window),并在当前对象上查找属性。但有时可能需要改变这种行为。比如说你有一个提供namelastname属性的类,并且你想利用这个方法的功能。你可以这样做:
class MyName {
  name = 'Tom';
  lastname = 'Hanks';
}

getFullName.apply(new MyName()); // --> 'Tom Hanks'

所以你看到了callapply是如何有帮助的。您可以参考Zer0的答案,了解更多关于callapplybind的信息。


1

这是关于在应用(apply)和调用(call)中的上下文(context)的问题。使用apply,您可以将参数传递给一个数组。


1
你也可以通过它访问不同对象中具有相同名称的函数,例如toString()或其他你喜欢的函数:
class MyObject {
    constructor(operator) {
        this.operator = operator;
    }
    
    calculate(a, b) {
        switch(this.operator) {
            case '+': return a + b;
            case '-': return a - b;
            case '*': return a * b;
            case '/': return a / b;
        }
    }
}

const operators = [
    new MyObject('+'),
    new MyObject('-'),
    new MyObject('*')
];
for (const op of operators) {
    const func = op['calculate'];
    console.log(func.call(op, 1, 1));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接