what is this underscore.js “safe reference” code d

2020-03-04 02:41发布

问题:

I'm learning Backbone, which uses Underscore.

In some examples, I see initialization code to create an empty array of children like this:

// inside a constructor function for a view object that will be extended:
this.children = _([]);

The Underscore function _ above being called is defined near top of Underscore.js:

// Create a safe reference to the Underscore object for use below.
var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
};

Stepping through in the debugger shows me the return new _(obj) is called at first, so the function is called again and finally this._wrapped = obj is executed. this appears to be referring to _.

I am bewildered. Why not just say this.children = [] in the first place?

回答1:

Because this.children needs to be a instance of underscore: a specialized class that wraps an array, not just a regular javascript array literal. The code in the _ function just makes sure it's always one _ instance wrapping one regular array, even if you try to rewrap an underscore instance repeatedly, call _ with or without the new keyword.

//new _ instance wrapping an array. Straightforward.
var _withNew = new _([]);

//automatically calls `new` for you and returns that, resulting in same as above
var _withoutNew = _([]);

//just gives you _withoutNew back since it's already a proper _ instance
var _doubleWrapped = _(_withoutNew);


回答2:

From http://underscorejs.org/#chaining

You can use Underscore in either an object-oriented or a functional style, depending on your preference. The following two lines of code are identical ways to double a list of numbers.

_.map([1, 2, 3], function(n){ return n * 2; }); // Functional style
_([1, 2, 3]).map(function(n){ return n * 2; }); // OO style

So when using the OO style, the _ is used as a constructor function. Without the first two lines in the constructor function that "Creates a safe reference to the Underscore object" you would have to use the new keyword, as follows

new _([1, 2, 3]).map(function(n){ return n * 2; });

Now you don't :)