Underscore source code interpretation: Supplements to Object Functions related source code


Why underscore

Recently I started to look at the source code of underscore.js and put the interpretation of the source code of underscore.js in my 2016 plan.

Reading the source code of some famous framework libraries is like talking to a master, you will learn a lot. Why is underscore? The main reason is that underscore is short and concise (about 1.5k lines), encapsulating more than 100 useful methods, low coupling, very suitable for reading method by method, suitable for JavaScript beginners like the original poster. From it, you can not only learn some tricks such as using void 0 instead of undefined to avoid undefined being rewritten, but also common methods such as variable type judgment, function throttling & function debounce, and many browser compatibility. The hack, you can also learn the author's overall design ideas and the principles of API design (backward compatibility).

Later, the host will write a series of articles to share with you the knowledge learned in source code reading.

Welcome to watch~ (If you are interested, welcome star & watch~) Your attention is the motivation for the host to continue writing

Main

Today, the source code interpretation part of Object Functions has been updated.

If you are interested, you may find that the host's previous interpretation series talked about extension methods on Object, which is the Object Functions part of the source code. underscore adds extension methods to 5 types, namely Object -> Array -> Collection -> Function -> Utility, which is exactly the original source code interpretation sequence (not the source code sequence). Among them, there are as many as 38 extension methods on Object, which does not mean that there are too many codes. For example, two lines of code can handle several methods, while the _.isEqual method mentioned in the previous article requires hundreds of OK to achieve. Today is the last article of the Object Functions section. Let's take a look at the source code of a few interesting but unexplained methods that the host thinks. (In fact, many methods are simple to use and very simple to implement. Interested students can grab the source code by themselves)

_.pick

First, let's take a look at the _.pick method, which passes in an object, then deletes the key-value pairs of the object, and returns a copy of the object.

Look directly at the example:


_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');

=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, ['name', 'age']);

=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {

  return _.isNumber(value);

});

=> {age: 50}

At a glance, the first parameter obj is an object, and the second parameter can be a series of key values, or an array (the array contains keys), or an iterative function. We filter obj according to the key value or iterative function Return the new object copy.

If I were to design, I would probably judge the type based on the parameters, and then write a few if-else, the content of each if-else branch has nothing to do. But the writing of underscore is simply wonderful, turning several situations into one.


// 如果第二个参数是函数

if (_.isFunction(oiteratee)) {

  keys = _.allKeys(obj);

  iteratee = optimizeCb(oiteratee, context);

}

First, if-else is inevitable. If the second parameter passed in is function, then the iteration function is passed in. According to the context (this), the new iteration function (optimizeCb) will be returned. The this point in is not very important, it can be selectively ignored here).

If the second parameter is not a function, the following keys may be an array or several consecutive parallel parameters. Here we are going to use another important internal method in underscore, flatten. Its function is to expand the nested array. I will analyze this method in the future. Just know its function here.

else {

  // 如果第二个参数不是函数

  // 则后面的 keys 可能是数组

  // 也可能是连续的几个并列的参数

  keys = flatten(arguments, false, false, 1);

  // 也转为 predicate 函数判断形式

  // 将指定 key 转化为 predicate 函数

  iteratee = function(value, key, obj) { return key in obj; };

  obj = Object(obj);

}

It is also converted to the same form as the incoming iterative function, and it can be judged by one method, and the meaning of the keys variable in the two cases is different, which is really very clever. This makes me think a lot. In many cases, the code is redundant. In fact, it is probably because my code ability is too bad. I can't think of doing this.

_.create

The _.create method is very simple. According to the prototype you give and some own properties, construct a new object to return.

Give a simple example:


var Person = function() {};

Person.prototype = {

  show: function() {

    alert(this.name);

  }

};

var me = _.create(Person.prototype, {name: 'hanzichi'});

console.log(me);

// Object {name: "hanzichi"}

//   name: "hanzichi"

//   __proto__: Object

//     show: function()

In fact, the me variable is an object that has name as its own properties and is constructed with the Person function.

If the browser supports ES5, we can use Object.create():


var Person = function() {};

Person.prototype = {

  show: function() {

    alert(this.name);

  }

};

var me = Object.create(Person.prototype);

_.extendOwn(me, {name: 'hanzichi'});

console.log(me);

If ES5 is not supported, we can define a new constructor, assign the prototype of the constructor to a known prototype variable, and then use the new operator to get the instance:


var Person = function() {};

Person.prototype = {

  show: function() {

    alert(this.name);

  }

};

var _Person = function() {};

_Person.prototype = Person.prototype;

var me = new _Person();

_.extendOwn(me, {name: 'hanzichi'});

console.log(me);

The realization of undercore is also roughly the same.

_.tap

I originally planned to talk about _.tap, but I suddenly felt that it would be better to talk about it with chain calls, and dig a hole.

summary

This is the end of the source code analysis of the Objects Function part. For the specific code, please refer to https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8. 3.js#L901-L1269. Although I have finished reading this part of the code, it takes time to truly understand and digest. I can only say that I understand about 90%. Welcome to discuss and exchange.

Guess you like

Origin blog.51cto.com/15080022/2588318