underscore.js源码研究(2)

概述

很早就想研究underscore源码了,虽然underscore.js这个库有些过期了,可是我仍是想学习一下库的架构,函数式编程以及经常使用方法的编写这些方面的内容,又刚好没什么其它要研究的了,因此就告终研究underscore源码这一心愿吧。html

underscore.js源码研究(1)
underscore.js源码研究(2)
underscore.js源码研究(3)
underscore.js源码研究(4)
underscore.js源码研究(5)
underscore.js源码研究(6)
underscore.js源码研究(7)
underscore.js源码研究(8)git

参考资料:underscore.js官方注释undersercore 源码分析undersercore 源码分析 segmentfault编程

解决冲突

咱们知道,_既是underscore的函数也是对象,咱们把方法先挂载到它的对象属性上,使得方法能够直接调用,而后咱们利用mixin方法把这些方法挂载到它的原型属性上,使得这个函数返回的underscore对象能够利用这些方法。segmentfault

那么若是其它库也用到了_这个符号呢?underscore中是这样解决的:api

var previousUnderscore = root._;

_.noConflict = function() {
    root._ = previousUnderscore;
    return this;
};

//给underscore从新定义一个符号:
var __ = _.noConflict();

内建方法

underscore这个库里面有一些私有的变量和方法,也会暴露出一些方法,这些暴露出的方法一旦被用户改写,可能整个库就不能按照但愿的方向运行了。因此underscore把一些暴露的方法赋给一些内建方法,而后在其它方法使用这些方法的时候能够用内建方法判断是否被改写了。示例以下:缓存

//声明内建方法
var builtinIteratee;

//双重赋值赋给内建方法
_.iteratee = builtinIteratee = function(value, context) {
return cb(value, context, Infinity);
};

//cb函数中判断iteratee方法是否被改写。
var cb = function(value, context, argCount) {
    if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
    if (value == null) return _.identity;
    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
    if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);
    return _.property(value);
};

值得一提的是,因为js中传递的是引用,因此赋给内建方法并不会有太大的内存开销,因此我以为这个想法很是好。架构

建立对象

new Person()实际上为咱们作了以下事情:app

//建立一个对象,并设置其指向的原型
var obj = {'__proto__': Person.prototype};

//调用Person()的构造方法,而且将上下文(this)绑定到obj上
Person.apply(obj, arguments);

//返回建立的对象
return obj;

可是使用new须要一个构造函数,这在不少时候很是不方便。更多时候,咱们但愿经过一个对象直接建立另外一个对象,因而就有了Object.create()方法。Object.create(obj)的原理是这样的:ide

//建立一个临时的构造函数,并将原型指向
var Ctor = function() {};
ctor.prototype = obj;

//经过new新建一个对象
var obj2 = new Ctor();

//清除Ctor,防止内存泄漏。并返回obj2
Ctor.prototype = null;
return obj2;

因此,mdn上这样描述Object.create()方法:建立一个新对象,使用现有的对象来提供新建立的对象的__proto__。函数式编程

须要注意的是,为了提高速度,underscore把Ctor进行了缓存

var Ctor = function() {};

因此后面当咱们为了防止内存泄漏清除Ctor的时候,只是清除它的原型。

而underscore的baseCreate方法就是对Object.create()方法的polyfill

var baseCreate = function(prototype) {
    if (!_.isObject(prototype)) return {};
    //nativeCreate便是Object.create()方法
    if (nativeCreate) return nativeCreate(prototype);

    Ctor.prototype = prototype;
    var result = new Ctor;
    Ctor.prototype = null;

    return result;
};

须要注意的是,Object.create()方法支持多个参数,可是underscore的baseCreate方法只支持一个参数

相关文章
相关标签/搜索