JavaScript 绑定(bind)与匿名函数

标签 javascript node.js anonymous-function

This code来自 mongoose-deep-populate

  async.parallel([
  User.create.bind(User, {_id: 1, manager: 2, mainPage: 1}),
  Comment.create.bind(Comment, {_id: 3, user: 1}),
  ...
], cb)

使用Function.prototype.bind来确保当执行回调函数User.create时,this绑定(bind)到正确的对象不同的背景。这相当于

async.parallel([
    function() { User.create({_id: 1, manager: 2, mainPage: 1}) }, 
    function() { Comment.create({_id: 3, user: 1}) },
], cb) 

如果是这样,与使用匿名函数相比,在什么情况下 bind 是更优选的语法?

最佳答案

两者在某种程度上有很大不同,在您的示例中不清楚,因为您使用的是常量值,但请考虑以下事项:

function mul(num, times) {
    return num * times;
}

function fn1() {
    let num = 3;

    let cb = function(times) {
        return mul(num, times);
    }

    num = 5;
    console.log(`num is now: ${ num }`);

    return cb;
}

function fn2() {
    let num = 3;

    let cb = mul.bind(null, num);

    num = 5;
    console.log(`num is now: ${ num }`);

    return cb;
}

当你运行这两个时,你会得到不同的结果:

let a1 = fn1()(5); // a1 === 25
let a2 = fn2()(5); // s2 === 15

两者之间的区别在于,当使用bind时,您将当前值绑定(bind)到函数(作为参数),而当使用匿名函数时,使用的值将是函数运行时存在的值。被调用。

在某些情况下,执行函数时您甚至可能会遇到 undefined:

var a = ["zero", "one", "two", "three", "four", "five"];
function fn(value, index) {
    console.log(value, index);
}

// doesn't work as i is undefined when the function is invoked
for (var i = 0; i < a.length; i++) {
    setTimeout(() => {
        fn(a[i], i);
    }, 45);
}

// works because the value of i and the value of a[i] are bound
for (var i = 0; i < a.length; i++) {
    setTimeout(fn.bind(null, a[i], i), 45);
}

(如果您使用 let 而不是 var,则使用匿名函数的示例将起作用)

当您想要传递一个调用另一个函数的结果的值时,也会发生同样的情况:

let counter = {
    _current: 0,
    get: function() {
        return this._current++;
    }
}

let map = {
    _items: Object.create(null),
    set: function(key, value, index) {
        this._items[key] = {
            index: index,
            value: value
        }
    }
}

// using anonymous functions the index in most cases won't reflect the real order
setTimeout(function() {
    map.set("one", 1, counter.get());
}, Math.floor(Math.random() * 1500) + 100);
setTimeout(function() {
    map.set("two", 2, counter.get());
}, Math.floor(Math.random() * 1500) + 100);
setTimeout(function() {
    map.set("three", 3, counter.get());
}, Math.floor(Math.random() * 1500) + 100);

// using bind, the index will always be correct
setTimeout(map.set.bind(map, "one", 1, counter.get()), Math.floor(Math.random() * 1500) + 100);
setTimeout(map.set.bind(map, "two", 2, counter.get()), Math.floor(Math.random() * 1500) + 100);
setTimeout(map.set.bind(map, "three", 3, counter.get()), Math.floor(Math.random() * 1500) + 100);

其工作方式不同的原因是,在绑定(bind)时,counter.get() 会在调用 bind 函数之前进行评估,以便绑定(bind)正确的返回值。
使用匿名函数时,仅在执行该函数时才会计算 counter.get(),并且调用哪个匿名函数的顺序是未知的。

关于JavaScript 绑定(bind)与匿名函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37911689/

相关文章:

javascript - 使用 jQuery 添加空图像标签

javascript - 如何使用 websocket 向客户端发送多个数组

javascript - 在node.js中读取文件是否保证项目的顺序

javascript - 使用 Mongoose 通过传递选项 JSON 来过滤数据 DB 级别

javascript - Jquery 事件处理程序仅适用于匿名函数?

javascript - 当未包装在 jquery 中的匿名函数中时,代码将无法运行

php - 闭包参数和 'use' 关键字有什么区别?

php - 当浏览器不允许 JavaScript 时如何在提交后重定向

javascript - jQuery 中列的总计

javascript - Angular js 复选框中的问题