zoukankan      html  css  js  c++  java
  • underscore源码解析

    前言

    underscore是最适合初级人士阅读的源码,在阅读源码时,有一些有趣的实现,记录如下。
    基于underscore1.8.3。

    留存root

    // Establish the root object, `window` (`self`) in the browser, `global`
    // on the server, or `this` in some virtual machines. We use `self`
    // instead of `window` for `WebWorker` support.
    var root = typeof self == 'object' && self.self === self && self ||
                typeof global == 'object' && global.global === global && global ||
                this ||
                {};
    
    // Save the previous value of the `_` variable.
    var previousUnderscore = root._;
    
    // .......
    _.noConflict = function() {
        root._ = previousUnderscore;
        return this;
    };
    

    在浏览器情况下,self是window自身的引用。上面的语法主要是为了保证在sever端和服务端都能正常获得根对象。
    将root._ 存起来,是为了防止命名冲突。调用noConflict方法,就能把原来的 _ 恢复,然后重新赋值到不冲突的变量上即可。

    保留原生方法、减少变量查询

    在underscore源码常看到会将一些常用的方法保留起来。

    // Save bytes in the minified (but not gzipped) version:
    var ArrayProto = Array.prototype, ObjProto = Object.prototype;
    var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
    
    // Create quick reference variables for speed access to core prototypes.
    var push = ArrayProto.push,
      slice = ArrayProto.slice,
      toString = ObjProto.toString,
      hasOwnProperty = ObjProto.hasOwnProperty;
    

    这样做的好处有两个:

    1. 减小*.min.js的体积。 在压缩时,some.func1只会被压缩成a.func1。如果把一个对象上常用的方法存为一个变量func1,那么压缩后将节省很多字节。
    2. 加快变量访问速度。
      在实际中,点操作符的使用会使得JavaScript引擎检索该对象下的所有成员。如果嵌套越深,那么读取速度越慢,花费时间越久。如果不是该对象的实例属性,引擎甚至要去检索原型链,将更加耗费时间。

    题外话:实际上,为了更好得提高性能,通常将变量保存到局部作用域,检索将会加快。

    链式调用

    var chainResult = function(instance, obj) {
        // 如果_chain为true,则return一个加了链式属性的underscore对象。
        return instance._chain ? _(obj).chain() : obj;
    };
    // Add your own custom functions to the Underscore object.
    // 可以把自己写的扩展方法通过mixin加入到underscore (_) 上。
    _.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));
            };
        });
        return _;
    };
    
    // Add all of the Underscore functions to the wrapper object.
    // 对underscore使用mixin,可以将全部实例方法挂载到原型上。
    _.mixin(_);
    
    // 链式调用方法,不过是加了一个Boolean型开关,来对返回值做判断
    _.chain = function(obj) {
        var instance = _(obj);
        instance._chain = true;
        return instance;
    };
    

    _.mixin方法用来把obj上的方法,都内置到下划线 _ 上,相当于jquery的extends方法。
    此处调用 _ mixin( _ );实际上,是将 _ 上的方法,都挂载到 _ .prototype上,以便于之后的链式调用。

    再来关注一下 _.chain这个方法,调用之后会返回一个underscore对象,并且把该对象的 _ chain属性赋为true。在chainResult这个方法里,会对当前的这个实例的 _ chain属性进行判断,如果调用了chain方法,就认为接下来会进行链式调用,就会将这个实例包裹之后,继续返回。

    链式调用的关键就在于,函数return原对象

    构造函数

    var _ = function(obj) {
        // 如果是underscore的实例,就直接返回obj
        if (obj instanceof _) return obj;
        // 如果this不是underscore的实例,就new一个新的underscore实例并返回
        if (!(this instanceof _)) return new _(obj);
        // 将this._wrapped属性置为obj
        this._wrapped = obj;
    };
    

    需要注意第二步,this的指向,因为如果直接调用 _ 函数,则this指向为window,使用new构造函数,this指向为新创建的对象。

    一些函数

    接下来对一些函数做分析。

    optimizeCb

    这个方法是一个优化方法,根剧不同的参数个数,返回不同的调用方式。
    好处有三:

    1. call比apply性能优异,因为apply传入数组,也是用调用底层的CALL方法,可以查看ecmascript262规范
    2. 因为arguments这个类数组对象较为消耗性能,所以不直接使用arguments来做判断。
    3. 绑定上下文。

    isArray

    _.isArray = nativeIsArray || function(obj) {
        return toString.call(obj) === '[object Array]';
    };
    

    目前判断数组的方法,较为公认的做法就是通过toString,查看是否是[object Array]。在ES5之后,原生带有isArray方法,兼容性不是很完善,IE9之后支持。可以把这个改一下,作为polyfill。
    在zepto中的isArray实现稍有不同:

    isArray = Array.isArray ||
          function(object){ return object instanceof Array }
    

    这两种方法有所区别,zepto的实现在iframe的情况下会有bug,具体参见这篇博客
    不过由于移动端通常不会使用iframe,所以,不会有特别大的问题。

  • 相关阅读:
    数据库系统load飙高问题解决思路
    随Linux开机自动启动mysql
    mysql_safe和mysql_multi
    mysqlslap压测
    “努力就会成功”
    MongonDB 知识
    Linux系统下MongoDB的简单安装与基本操作
    性能压测,更新库存时间长
    Buffer Latch Timeout的解析
    SQL Server 性能调优(一)——从等待状态判断系统资源瓶颈
  • 原文地址:https://www.cnblogs.com/liuyongjia/p/8053489.html
Copyright © 2011-2022 走看看