zoukankan      html  css  js  c++  java
  • Ember源码学习

    ember.js是当今最强大的javascript MVC框架。当一把胡子拉碴的大牛人跑进JS界搞这东西时,昭示了JS全盛时期的到来。

    可能你听说过javascriptmvc.js这个时期在jQuery支援下赫赫有名的框架,或者现在更为流行的backbone,但相对于ember.js,它们就黯然失色了。不过正由于看上去非常高端,也吓跑了不少人。在富应用日益流行的今天,越来越多工作转到前端了,JS的代码变得非常庞大,如此组织它们是一个难题。如果公司是使用EXT这样的强大UI框架,这可免谈了。但许多公司只能摆弄一下jQuery,jQuery可是堆代码的利器。堆得快,倒得快,这也是其特色。jQuery易入门,因此其开发者龙蛇混杂,当然这是相对于国外来说,国内考虑到成本与中国特色,前端人员的素质是极差的,他们写的jQuery代码是非常难维护的。因此要引入规范与绝束。MVC无疑是当中最可靠的选项。如果大家的业务代码与UI的编写也按MVC的规定来写,所有都有章可循,这维护成本就大大降低。

    有人说框架会让程序员变成填空题的码农,MVC这种强约束,让程序员成为了流水线的工人了。农民工只能搞些土产品,但工人可以组装精密仪器。欢欣雀跃吧,前端的码农们!你们现在升级了无产阶级的中流砥柱——流水线工人了!你会明白后端的程序员为什么这么高吧,因为他们早在十年前,在JAVA,C#,C++,JAVA的伟大框架的统治下,实现了农转非!相对于后端的工业国家,前端的国度可怜得像非洲部落酋长国,即使jQuery的现世,只不过让部落民转变成法老的子民。

    
    if ('undefined' === typeof Ember) {
    
        Ember = {};
        //暴露到全局作用域下
        if ('undefined' !== typeof window) {
            window.Em = window.Ember = Em = Ember;
        }
    
    }
    Ember.isNamespace = true;
    
    Ember.toString = function() { 
        return "Ember";
    };
    
    Ember.VERSION = '0.9.8.1';
    
    Ember.ENV = 'undefined' === typeof ENV ? {} : ENV;
    
    //决定是否缓存计算值,可以使用volatile禁止它
    Ember.CP_DEFAULT_CACHEABLE = (Ember.ENV.CP_DEFAULT_CACHEABLE !== false);
    
    Ember.VIEW_PRESERVES_CONTEXT = (Ember.ENV.VIEW_PRESERVES_CONTEXT !== false);
    
    Ember.K = function() { 
        return this;
    };
    //调试相关
    
    if ('undefined' === typeof Ember.assert) { 
        Ember.assert = Ember.K;
    }
    if ('undefined' === typeof Ember.warn) { 
        Ember.warn = Ember.K;
    }
    if ('undefined' === typeof Ember.deprecate) { 
        Ember.deprecate = Ember.K;
    }
    if ('undefined' === typeof Ember.deprecateFunc) {
        Ember.deprecateFunc = function(_, func) {
            return func;
        };
    }
    //向前兼容
    if ('undefined' === typeof ember_assert) { 
        window.ember_assert = Ember.K;
    }
    if ('undefined' === typeof ember_warn) { 
        window.ember_warn = Ember.K;
    }
    if ('undefined' === typeof ember_deprecate) { 
        window.ember_deprecate = Ember.K;
    }
    if ('undefined' === typeof ember_deprecateFunc) {
    
        window.ember_deprecateFunc = function(_, func) {
            return func;
        };
    }
    //调试相关
    Ember.Logger = window.console || { 
        log: Ember.K,
        warn: Ember.K,
        error: Ember.K
    };
    //用于储存一些静态方法与特征偶测的结果
    var platform = Ember.platform = {} ;
    
    //类工厂,只是Object.create的别名
    platform.create = Object.create;
    
    if (!platform.create) {
        //向前兼容
        var O_ctor = function() {},
        O_proto = O_ctor.prototype;
    
        platform.create = function(obj, descs) {
            O_ctor.prototype = obj;
            obj = new O_ctor();
            O_ctor.prototype = O_proto;
    
            if (descs !== undefined) {
                for(var key in descs) {
                    if (!descs.hasOwnProperty(key)) continue;
                    //第二个参数也进行补完了
                    platform.defineProperty(obj, key, descs[key]);
                }
            }
    
            return obj;
        };
        //标识是赝品
        platform.create.isSimulated = true;
    }
    
    var defineProperty = Object.defineProperty;
    var canRedefineProperties, canDefinePropertyOnDOM;
    //IE8的 Object.defineProperty就是半成品,只能处理DOM属性
    if (defineProperty) {
        try {
            defineProperty({}, 'a',{
                get:function(){}
                });
        } catch (e) {
            /** @private */
            defineProperty = null;
        }
    }
    //处理其他奇异的BUG
    if (defineProperty) {
        // Detects a bug in Android <3.2 where you cannot redefine a property using
        // Object.defineProperty once accessors have already been set.
        /** @private */
        canRedefineProperties = (function() {
            var obj = {};
    
            defineProperty(obj, 'a', {
                configurable: true,
                enumerable: true,
                get: function() { },
                set: function() { }
            });
    
            defineProperty(obj, 'a', {
                configurable: true,
                enumerable: true,
                writable: true,
                value: true
            });
    
            return obj.a === true;
        })();
    
        // This is for Safari 5.0, which supports Object.defineProperty, but not
        // on DOM nodes.
        /** @private */
        canDefinePropertyOnDOM = (function(){
            try {
                defineProperty(document.createElement('div'), 'definePropertyOnDOM', {});
                return true;
            } catch(e) { }
    
            return false;
        })();
    
        if (!canRedefineProperties) {
            /** @private */
            defineProperty = null;
        } else if (!canDefinePropertyOnDOM) {
            /** @private */
            defineProperty = function(obj, keyName, desc){
                var isNode;
    
                if (typeof Node === "object") {
                    isNode = obj instanceof Node;
                } else {
                    isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string";
                }
    
                if (isNode) {
                    // TODO: Should we have a warning here?
                    return (obj[keyName] = desc.value);
                } else {
                    return Object.defineProperty(obj, keyName, desc);
                }
            };
        }
    }
    
    platform.defineProperty = defineProperty;
    
    platform.hasPropertyAccessors = true;
    
    if (!platform.defineProperty) {
      platform.hasPropertyAccessors = false;
    
      platform.defineProperty = function(obj, keyName, desc) {
        ember_assert("property descriptor cannot have `get` or `set` on this platform", !desc.get && !desc.set);
        obj[keyName] = desc.value;//如果不支持,只能取得这个对象的value进行赋值
      };
    
      platform.defineProperty.isSimulated = true;
    }
    
    
    // UUID部分
    var GUID_KEY = '__ember'+ (+ new Date());
    var uuid, numberCache, stringCache;
    
    uuid         = 0;
    numberCache  = [];
    stringCache  = {};
    //让其不可遍历
    var GUID_DESC = Ember.GUID_DESC = {
      configurable: true,
      writable: true,
      enumerable: false
    };
    
    var o_defineProperty = Ember.platform.defineProperty;
    var o_create = Ember.platform.create;
    
    Ember.GUID_KEY = GUID_KEY;
    //生成一个UUID
    Ember.generateGuid = function(obj, prefix) {
      if (!prefix) prefix = 'ember';
      var ret = (prefix + (uuid++));
      if (obj) {
        GUID_DESC.value = ret;
        o_defineProperty(obj, GUID_KEY, GUID_DESC);
        GUID_DESC.value = null;
      }
    
      return ret ;
    };
    
    //取得每个对象的UUID对应的键名,UUID是用于对象的,因此对于基本数据类型,它们的返回值是规定好的
    Ember.guidFor = function(obj) {
    
      // special cases where we don't want to add a key to object
      if (obj === undefined) return "(undefined)";
      if (obj === null) return "(null)";
    
      var cache, ret;
      var type = typeof obj;
    
      switch(type) {
        case 'number'://处理不可变对象
          ret = numberCache[obj];
          if (!ret) ret = numberCache[obj] = 'nu'+obj;
          return ret;
    
        case 'string'://处理不可变对象
          ret = stringCache[obj];
          if (!ret) ret = stringCache[obj] = 'st'+(uuid++);
          return ret;
    
        case 'boolean'://处理不可变对象
          return obj ? '(true)' : '(false)';
    
        default:
          if (obj[GUID_KEY]) return obj[GUID_KEY];
          if (obj === Object) return '(Object)';//跳过原生对象的构造器
          if (obj === Array)  return '(Array)';//跳过原生对象的构造器
          return Ember.generateGuid(obj, 'ember');
      }
    };
    //元
    var META_DESC = {//其特性描述
      writable:    true,
      configurable: false,
      enumerable:  false,
      value: null
    };
    
    var META_KEY = Ember.GUID_KEY+'_meta';
    
    Ember.META_KEY = META_KEY;
    
    // Placeholder for non-writable metas.
    var EMPTY_META = {//空元
      descs: {},
      watching: {}
    };
    
    if (Object.freeze) Object.freeze(EMPTY_META);
    
    var createMeta = Ember.platform.defineProperty.isSimulated ? o_create : (function(meta) { return meta; });
    
    
    Ember.meta = function meta(obj, writable) {
    
      var ret = obj[META_KEY];
      if (writable===false) return ret || EMPTY_META;//如何不可写,直接返回或返回空元
    
      if (!ret) {//如果此对象刚刚设置
        o_defineProperty(obj, META_KEY, META_DESC);
        ret = obj[META_KEY] = createMeta({
          descs: {},
          watching: {},
          values: {},
          lastSetValues: {},
          cache:  {},
          source: obj
        });
    
        // make sure we don't accidentally try to create constructor like desc
        ret.descs.constructor = null;
    
      } else if (ret.source !== obj) {
        ret = o_create(ret);//复制
        ret.descs    = o_create(ret.descs);//复制
        ret.values   = o_create(ret.values);//复制
        ret.watching = o_create(ret.watching);//复制
        ret.lastSetValues = {};
        ret.cache    = {};
        ret.source   = obj;
    
        o_defineProperty(obj, META_KEY, META_DESC);
        ret = obj[META_KEY] = createMeta(ret);
      }
      return ret;
    };
    //取得对象的某些元信息
    Ember.getMeta = function getMeta(obj, property) {
      var meta = Ember.meta(obj, false);
      return meta[property];
    };
    
    Ember.setMeta = function setMeta(obj, property, value) {
      var meta = Ember.meta(obj, true);
      meta[property] = value;
      return value;
    };
    Ember.metaPath = function(obj, path, writable) {
      var meta = Ember.meta(obj, writable), keyName, value;
    
      for (var i=0, l=path.length; i<l; i++) {
        keyName = path[i];
        value = meta[keyName];
    
        if (!value) {
          if (!writable) { return undefined; }
          value = meta[keyName] = { __ember_source__: obj };
        } else if (value.__ember_source__ !== obj) {
          if (!writable) { return undefined; }
          value = meta[keyName] = o_create(value);
          value.__ember_source__ = obj;
        }
    
        meta = value;
      }
    
      return value;
    };
    
    Ember.wrap = function(func, superFunc) {
    
      function K() {}
    
      var newFunc = function() {
        var ret, sup = this._super;
        this._super = superFunc || K;
        ret = func.apply(this, arguments);
        this._super = sup;
        return ret;
      };
    
      newFunc.base = func;
      return newFunc;
    };
    //用于判定是否为类数组
    mber.isArray = function(obj) {
      if (!obj || obj.setInterval) { return false; }
      if (Array.isArray && Array.isArray(obj)) { return true; }
      if (Ember.Array && Ember.Array.detect(obj)) { return true; }
      if ((obj.length !== undefined) && 'object'===typeof obj) { return true; }
      return false;
    };
    //将一切转换为数组
    //      Ember.makeArray();          => []
    //      Ember.makeArray(null);      => []
    //      Ember.makeArray(undefined); => []
    //      Ember.makeArray('lindsay'); => ['lindsay'] 
    //      Ember.makeArray([1,2,42]);  => [1,2,42]
    Ember.makeArray = function(obj) {
      if (obj === null || obj === undefined) return [];
      return Ember.isArray(obj) ? obj : [obj];
    };
    

    本篇到此为止,只是知道它费了很大劲模拟Object.defineProperties,与搞了个META机制,暂时不知有什么用。

  • 相关阅读:
    Mac上的USB存储设备使用痕迹在新版操作系统有所变化
    Beware of the encrypted VM
    A barrier for Mobile Forensics
    Second Space could let suspect play two different roles easily
    Take advantage of Checkra1n to Jailbreak iDevice for App analysis
    Find out "Who" and "Where"
    Where is the clone one and how to extract it?
    Downgrade extraction on phones running Android 7/8/9
    高版本安卓手机的取证未来
    How to extract WeChat chat messages from a smartphone running Android 7.x or above
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/2531948.html
Copyright © 2011-2022 走看看