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机制,暂时不知有什么用。