简体   繁体   English

JavaScript绑定与匿名函数

[英]JavaScript bind vs anonymous function

This code from mongoose-deep-populate 这段代码来自mongoose-deep-populate

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

uses Function.prototype.bind to ensure that this is bound to the proper object when the callback function User.create is executed in a different context. 使用Function.prototype.bind以确保this回调函数时被绑定到正确的对象User.create在不同的上下文中执行。 Is this equivalent to 这等于

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

?

If so, in what situation is bind a more preferable syntax compared to using an anonymous function? 如果是这样,在什么情况下bind比使用匿名函数更可取的语法?

The two are quite different in a way that isn't clear in your example because you are using constant values, but consider the following: 两者之间的差异非常大,因为您使用的是常量值,因此在您的示例中不清楚,但是请注意以下几点:

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;
}

When you run the two you'll get different results: 当您运行两者时,您将得到不同的结果:

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

The difference between the two is that when using bind you bind the current values to the function (as parameters) while when using an anonymous function the used values will be the ones that exist when the function is invoked. 两者之间的区别在于,使用bind会将当前值绑定到函数(作为参数),而使用匿名函数时,使用的值将是调用函数时存在的值。

In some scenarios you might even face an undefined when the function is executed: 在某些情况下,执行函数时甚至可能会遇到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);
}

(the example with the anonymous function will work if you use let instead of var ) (如果您使用let而不是var则带有匿名函数的示例将起作用)

The same happens when you want to pass a value which is a result of calling another function: 当您要传递一个调用另一个函数的值时,也会发生相同的情况:

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);

The reason it works differently is that when binding the counter.get() gets evaluated before the bind function is invoked so the correct return value is bound. 它工作原理不同的原因是,在绑定时,在调用bind函数之前对counter.get()进行求值,以便bind正确的返回值。
When using an anonymous function the counter.get() is evaluated only when the function is executed, and the order of which anonymous function is called isn't known. 使用匿名函数时,只会在执行该函数时对counter.get()进行求值,并且未知调用匿名函数的顺序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM