Underscore.js Source Research (8)

Source: Internet
Author: User

Overview

Very early wanted to study the source of underscore, Although underscore.js this library is somewhat outdated, but I still want to learn the library architecture, functional programming and common methods of writing these aspects of the content, and there is nothing else to study, so the end of the study of underscore source of the wish it.

Underscore.js Source Research (1)
Underscore.js Source Research (2)
Underscore.js Source Research (3)
Underscore.js Source Research (4)
Underscore.js Source Research (5)
Underscore.js Source Research (6)
Underscore.js Source Research (7)
Underscore.js Source Research (8)

Reference: Underscore.js official notes, Undersercore source analysis, Undersercore source Analysis Segmentfault

Chained calls

For a method of an object, we can return this in the method to enable it to support chained calls . If we do not modify the source code of the original method, we can use the following function to enable it to support chained calls.

//其中obj是一个对象,functions是对象的方法名数组function chained(obj, functions) {    //由于functions是一个数组,所以可以使用foreach    functions.forEach((funcName) => {        const func = obj[funcName];        //修改原方法        obj[funcName] = function() {            func.apply(this, arguments);            return this;        }    })}

Examples are as follows:

let speaker = {    haha() {        console.log('haha');    },    yaya() {        console.log('yaya');    },    lala() {        console.log('lala');    }}chained(speaker, ['haha', 'lala', 'yaya']);speaker.haha().yaya().haha().lala().yaya();

The output is as follows:

hahayayahahalalayaya
Chained calls inside the Underscore.js

The chain call inside the underscore.js is slightly different from the above.

Its mechanism is this:

    1. Attach the Underscore.js method to _ below.
    2. Use the _.function method to traverse all the methods that are mounted under _, and then mount it under _.prototype so that the generated underscore object can call these methods directly.
    3. When the method is mounted below the _.prototype, the method is rewritten using a function similar to the above (add return this).
    4. Create an identity _chain when rewriting to identify whether this method can be called in a chain.

Here's a look at how it works:

First of all, using the following function, you can get an array with the name of the method that is attached to _ below the array.

_function = _.methods = function(obj) {    var names = [];    for( var key in obj) {        if(_.isFunction(obj[key])) names.push(key);    }    return names.sort();};

Then we take each method name and mount it to _.prototype below :

_.mixin = function(obj) {    _.each(_.functions(obj), function(name) {        var func = _[name] = obj[name];        _.prototype[name] = function() {            var args = [this._wrapped];            push.apply(args, arguments);            return chainResult(this, func.apply(_, args));        };    });};_.mixin(_);

As you can see from above, a Chainresult method is returned when it is mounted. and args is equal to the original object + parameter 1+ parameter ... Array, so it func.apply(_, args) is _[func](原对象,参数1,参数2,...) the result of processing.

Let's see what Chainresult is like:

var chainResult = function(instance, obj){    return instance._chain ? _(obj).chain() : obj;};

It determines that if the original object can be chained, then the processed result, obj, can also be chained. How to make the result can also be chained to call it? The answer is to use the _.chain method:

_chain = function(obj) {    var instance = _(obj);    instance._chain = true;    return instance;}

This method is similar to the chained method we started with, but it transforms the original object into a underscore object, and the **_chain property of the object is true, that is, it can be called by a chain.

So if we want to implement the chain call in Underscore.js, we can use the chain method directly, the example is as follows:

_([1,2]).push(3).push(5) //输出4,并不是我们想要的_([1,2]).chain().push(3).push(5).value() //输出[1, 2, 3, 5],正是我们想要的

As you can see, we have used the value () function above, which can break the chain call , not return the pointer but return the value, the code is as follows:

_.prototype.value = function() {    return this._wrapped;}

Wait, what's _wrapped? It is the original object before generating the underscore object, see the following code:

var _ = function(obj) {    if(obj instanceof _) return obj;    if(!(this instanceof _)) return new _(obj);    this._wrapped = obj;}

That is, when using _ to generate the underscore object, the original object is stored in the **_wrapped attribute * *, so _wrapped is the original object.

Underscore.js Source Research (8)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.