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