首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript函数调用:常规调用vs调用与绑定调用

Javascript函数调用:常规调用vs调用与绑定调用
EN

Stack Overflow用户
提问于 2012-07-17 12:59:06
回答 2查看 1.1K关注 0票数 3

我的问题很简单:我将一个函数传递给其他函数,以便稍后调用(示例回调函数),问题是什么时候、为什么和什么是最佳实践。

示例:我有xxx()函数,我必须传递它,如下面的window.onload事件所示。

什么是最佳实践?为什么?有任何性能方面,或者为什么要选择使用调用或绑定来调用此函数?

代码语言:javascript
复制
function xxx(text)
{
    var div = document.createElement("div");
    div.innerHTML = text + " - this: " + this.toString();

    document.body.appendChild(div)
}

function callFunction(func)
{
    func("callFunction");
}

function callUsingCall(func)
{
    func.call(this, ["callUsingCall"]);
}

function callUsingBind(func)
{
    func.call(this, ["callUsingCall"]);
}


window.onload = function(){
    callFunction(xxx);

    callUsingCall(xxx);

    callUsingBind(xxx.bind(document));
}

谢谢,

塞巴斯蒂安P.

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-17 13:02:00

我不认为有什么“最佳”的做法。

如果调用的函数关心this是什么,就使用this

如果要确保只能使用指定的bind值调用函数,则可以使用this

这两者都有一些开销,即至少有一个深度的函数调用/作用域

否则你只需要调用这个函数。

(例句:)

票数 4
EN

Stack Overflow用户

发布于 2012-07-17 13:18:44

this对象是函数的上下文。就像你做了一台机器一样,this对象就是机器工作的地方,就像你的房子。你可以随意移动它。

我们有4种设置this对象的方法。

调用非方法的函数:

代码语言:javascript
复制
fn(someArguments)

这样,this对象被设置为null,或者可能设置为window对象。

作为方法调用函数的

代码语言:javascript
复制
someObject.fn(someArguments)

在这种情况下,this对象将指向someObject,并且它是可变的。

使用函数的call apply 方法调用。

代码语言:javascript
复制
fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])

在本例中,this对象将指向此处的someObject。当调用它时,您正在强迫它具有另一个上下文。

绑定a函数

var fn2 = fn.bind(anotherObject, someArguments)

这将创建另一个绑定到我们给它的this对象(anotherObject)的函数。无论您如何称呼它,this对象都将是相同的。

用例

现在,你可以做一些棘手的事情知道这一点。我们之所以在这里使用它(我认为它首先来自C++)是因为对象的方法需要访问它们的父对象。this对象提供访问。

代码语言:javascript
复制
var coolObject = {
  points : ['People are amazing'],
  addPoint : function (p) { this.points.push(p) }
}

因此,如果您执行以下操作,它将无法工作:

代码语言:javascript
复制
var addPoint = coolObject.addPoint;
addPoint('This will result in an error');

这个错误将被抛出,因为这个对象不再是我们的coolObject,并且没有points属性。所以在这样的时候,你可以这样做:

代码语言:javascript
复制
var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');

这是没有意义的,但是这个函数会正常工作,甚至this对象也不是它应该的样子。

代码语言:javascript
复制
var anotherCoolObject = {
  points : ['Im a thief!'],
  addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');

如果您这样调用它,则函数仍然可以工作,因为this对象将指向具有points属性的anotherCoolObject。

我见过的最流行的用例是切片参数对象:

代码语言:javascript
复制
function returnHalf() {
  return [].slice.call(arguments, 0, arguments.length / 2);
}

returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']

所以你看,参数对象不是数组的实例。如果我们做arguments.slice(...),那么你就会被编译器杀死。但是这里我们在参数对象上使用数组的方法,因为它类似于数组。

有时,您不希望您的函数上下文被更改,或者您希望添加您自己的参数,则使用bind。

例如,当您为带有jquery的事件添加侦听器时,当jquery调用您的函数时,这个对象将是元素。但有时你想做一些棘手的事情并改变它:

代码语言:javascript
复制
var myElement = {
  init : function () {
    $(this.element).click(this.listener.bind(this));
  },
  view : "<li>${Name}</li>",
  name : 'ed',
  element : $('#myelement'),
  listener : function () {
    this.element.append($.tmpl( this.view, this ));
  }
}

myElement.init();

因此,在这里,将其绑定到myElement,这样就可以访问对象属性来呈现视图。另一个例子是:

代码语言:javascript
复制
for (var i = 0; i < 10; i++) {
  setTimeout(function () {console.log(i)}, 10)
}

// All of them will be 10.

for (var i = 0; i < 10; i++) {
  setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}

如果在循环中放置了异步函数调用,则在调用回调时,循环完成,计数器到达末尾时,可以使用bind将当前计数器干净地绑定到回调。

我经常使用的另一个很好的用例是将带参数的函数传递给async模块,而不创建闭包。

代码语言:javascript
复制
async.parallel({
  writeFile : function (cb) {
    fs.writeFile('lolz.txt', someData, cb);
  }, 
  writeFile2 : function (cb) {
    fs.writeFile('lolz2.txt', someData, cb);
  }
}, function (err){ 
    console.log('finished')
});

async.parallel({
  writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
  writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){ 
    console.log('finished')
});

这两个实现是相同的。

性能

看看这些:

http://jsperf.com/bind-vs-call2

http://jsperf.com/js-bind-vs-closure/2

http://jsperf.com/call-vs-closure-to-pass-scope/10

与其他类型的调用相比,bind具有很大的性能开销,但请确保在预成熟优化时不要牺牲性能和可维护性。

此外,您还可以查看的文章。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11523012

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档