alejs
Version:
a Flexible and fast JavaScript view framework.
1,070 lines (912 loc) • 36.5 kB
JavaScript
/*! Ale.js JavaScript Framework
* Version: 1.2.1
* (c) 2018 Dong Yingxuan (Bill Dong)
* Released under the MIT License
*/
(function(window, document) {
"use strict";
var version = "1.2.1",
allUsedComponents = 0,
componentList = [],
regPluginList = [],
filterList = [],
pluginInjectList = [],
pluginMixinList = [],
needUpdateDOMList = [],
needUpdateDOMListLength = 0,
isNextTickWaiting = false,
tickCallbackFun = null,
configList = {
html: false,
diff: true,
async: true,
configLock: false
};
window.Ale = function(name, config) {
if (typeof name !== "string" || !isRealObj(config)) {
if (!isRealObj(name)) {
throw "Ale.js: Wrong type of parameters was used when creating component objects!";
} else {
var comCreate = handleComponentCreate(name);
if (comCreate !== undefined) {
return new aleLocalComponentGenerateObject(comCreate);
}
}
}
if (componentList[name] !== undefined) {
throw "Ale.js: This component has been created!";
}
var comCreate = handleComponentCreate(config);
if (comCreate !== undefined) {
componentList[name] = comCreate;
}
}
Ale.render = function(name, config) {
var thisComponent = deepCopy(componentList[name]);
return handleComponentRender(thisComponent, config);
}
Ale.config = function(key, val) {
if (configList["configLock"]) {
throw "Ale.js: The configuration function is locked, no changes are allowed!";
}
if (isRealObj(key)) {
for (var i in key) {
configList[i] = key[i];
}
} else if (typeof key === "string" && typeof val === "boolean") {
configList[key] = val;
} else {
throw "Ale.js: The parameter type is wrong when calling the config function!";
}
}
Ale.isHasThisComponent = function(name) {
if (componentList[name] === undefined) {
return false;
}
return true;
}
Ale.use = function(pluginObj) {
//检查必要字段是否添加
if (typeof pluginObj.name !== "string" || typeof pluginObj.install !== "function") {
throw "Ale.js: Some fields were not added when the plugin was registered!";
}
if (regPluginList[pluginObj.name] !== undefined) {
//插件已经被注册了
throw "Ale.js: This plugin has been registered!";
}
//开始注册
regPluginList[pluginObj.name] = pluginObj.name;
pluginObj.install();
}
Ale.filter = function(fun) {
//检查类型
if (typeof fun !== "function" && !Array.isArray(fun)) {
throw "Ale.js: You need to pass in a function or array when adding a filter!";
}
if (typeof fun === "function") {
filterList.push(fun);
} else if (Array.isArray(fun)) {
filterList = filterList.concat(fun);
}
}
Ale.nextTick = function(fun) {
if (typeof fun === "function") {
tickCallbackFun = fun;
} else {
throw "Ale.js: You need to pass in a function when adding a tick callback function!";
}
}
Ale.plugin = {
inject: function(fun) {
if (typeof fun !== "function") {
throw "Ale: The wrong data type for plug-in injection!";
}
pluginInjectList.push(fun);
},
mixin: function(fun) {
if (typeof fun !== "function") {
throw "Ale: The wrong data type for plug-in injection!";
}
pluginMixinList.push(fun);
}
}
Ale.version = version;
function aleLocalComponentGenerateObject(config) {
this.config = config;
this.render = function(newConfig) {
return handleComponentRender(deepCopy(this.config), newConfig);
}
}
function checkDataType(data, dataType) {
if (typeof dataType !== "undefined") {
if (typeof dataType === "function") {
if (!(data instanceof dataType)) {
throw "Ale.js: Incorrect component data type!";
}
} else if (Array.isArray(dataType)) {
var isTrueData = false;
for (var a = 0; a < dataType.length; a++) {
if (typeof dataType[a] === "function") {
if (data instanceof dataType[a]) {
isTrueData = true;
break;
}
} else {
if (typeof data === dataType[a]) {
isTrueData = true;
break;
}
}
}
if (!isTrueData) {
throw "Ale.js: Incorrect component data type!";
}
} else {
if (typeof data !== dataType) {
throw "Ale.js: Incorrect component data type!";
}
}
}
}
function aleComponentObject(el, config) {
this.id = "i" + allUsedComponents++;
this.el = el;
this.nodeList = document.querySelectorAll(this.el);
this.config = config;
this.template = config.template;
this.data = config.data;
this.staticData = config.staticData;
this.dataType = config.dataType;
this.methods = isRealObj(config.methods) ? config.methods : {};
this.life = config.life;
this.type = config.type;
this.imports = config.imports;
this.proxy = isRealObj(config.proxy) ? config.proxy : {};
this.watch = isRealObj(config.watch) ? config.watch : {};
this.name = typeof config.name === "string" ? config.name : "unknow";
//初始化dataType
if (!isRealObj(this.dataType.data)) {
this.dataType.data = {};
}
if (!isRealObj(this.dataType.staticData)) {
this.dataType.staticData = {};
}
//check data type
//xss replace
for (var i in this.data) {
checkDataType(this.data[i], this.dataType.data[i]);
this.data[i] = xssTemReplace(this.data[i]);
}
for (var i in this.staticData) {
checkDataType(this.staticData[i], this.dataType.staticData[i]);
this.staticData[i] = xssTemReplace(this.staticData[i]);
}
//生命周期、methods和代理绑定this
this.life = lifeBindThis(this.life, this);
this.methods = methodsBindThis(this.methods, this);
this.proxy = proxyBindThis(this.proxy, this);
//为了防止栈溢出,克隆一个data
var newData = typeof this.data === "function" ? this.data() : deepCopy(this.data);
this.data = typeof this.data === "function" ? this.data() : this.data;
var newStaticData = typeof this.staticData === "function" ? this.staticData() : deepCopy(this.staticData);
this.staticData = typeof this.staticData === "function" ? this.staticData() : this.staticData;
//设置staticData的getter和setter
(function(i, life, staticData, proxy, dataType) {
Object.defineProperty(i, "staticData", {
set: function(val) {
if (typeof life.staticDataUpdating === "function") {
life.staticDataUpdating();
}
var newValObj = executeProxy("static", proxy.setter, i, val);
val = newValObj.val;
//check data type
for (var a in val) {
checkDataType(val[a], dataType.staticData[a]);
newStaticData[a] = xssTemReplace(val[a]);
}
},
get: function() {
return executeProxy("static", proxy.getter, i, staticData).val;
}
})
})(this, this.life, this.staticData, this.proxy, this.dataType);
for (var i in this.staticData) {
(function(i, life, staticData, proxy, dataType) {
Object.defineProperty(staticData, i, {
set: function(val) {
//check data type
checkDataType(val, dataType.staticData[i]);
if (typeof life.staticDataUpdating === "function") {
life.staticDataUpdating();
}
var newValObj = executeProxy("static", proxy.setter, i, val);
val = newValObj.val;
newStaticData[i] = xssTemReplace(val);
},
get: function() {
return executeProxy("static", proxy.getter, i, newStaticData[i]).val;
}
})
})(i, this.life, this.staticData, this.proxy, this.dataType);
}
//设置data的getter和setter
(function(i, id, data, methods, template, nodeList, life, type, imports, proxy, staticData, dataType, watch) {
Object.defineProperty(i, "data", {
set: function(val) {
//当属性改变时动态渲染
var newValObj = executeProxy("normal", proxy.setter, i, val);
val = newValObj.val;
//check data type
for (var a in val) {
checkDataType(val[a], dataType.data[a]);
newData[a] = xssTemReplace(val[a]);
}
if (newValObj.needBreak) {
return;
}
if (typeof life.updating === "function") {
life.updating();
}
updateDOM(i, data, methods, {
id: id,
type: type,
nodeList: nodeList,
newData: newData,
template: template,
imports: imports,
life: life,
staticData: staticData
});
},
get: function() {
return executeProxy("normal", proxy.getter, i, data).val;
}
})
})(this, this.id, this.data, this.methods, this.template, this.nodeList, this.life, this.type, this.imports, this.proxy, this.staticData, this.dataType, this.watch);
for (var i in this.data) {
(function(i, th, id, data, methods, template, nodeList, life, type, imports, proxy, staticData, dataType) {
Object.defineProperty(data, i, {
set: function(val) {
//check data type
checkDataType(val, dataType.data[i]);
//当属性改变时动态渲染
var newValObj = executeProxy("normal", proxy.setter, i, val);
val = newValObj.val;
newData[i] = xssTemReplace(val);
if (newValObj.needBreak) {
return;
}
if (typeof life.updating === "function") {
life.updating();
}
updateDOM(th, data, methods, {
id: id,
type: type,
nodeList: nodeList,
newData: newData,
template: template,
imports: imports,
life: life,
staticData: staticData
});
},
get: function() {
return executeProxy("normal", proxy.getter, i, newData[i]).val;
}
})
})(i, this, this.id, this.data, this.methods, this.template, this.nodeList, this.life, this.type, this.imports, this.proxy, this.staticData, this.dataType);
}
//start building(一定要放到最后,否则无法在mounting时更新数据)
firstRenderingDOM(this, this.data, this.methods, {
id: this.id,
type: this.type,
nodeList: this.nodeList,
template: this.template,
imports: this.imports,
life: this.life,
staticData: this.staticData
});
if (typeof this.life.mounting === "function") {
this.life.mounting();
}
}
aleComponentObject.prototype.destroy = function() {
for (var i in this.data) {
(function(i, data) {
Object.defineProperty(data, i, {
set: function() {},
get: function() {
return undefined;
}
})
})(i, this.data);
}
for (var i = 0; i < this.nodeList.length; i++) {
this.nodeList[i].innerHTML = "";
}
if (typeof this.life.unmounting === "function") {
this.life.unmounting();
}
var lifeDestroy = this.life.destroy;
for (var i in this) {
delete this[i];
}
if (typeof lifeDestroy === "function") {
lifeDestroy();
}
}
function handleComponentRender(thisComponent, config) {
if (thisComponent === undefined) {
throw "Ale.js: This component has not been created yet!";
}
if (typeof config.el !== "string") {
throw "Ale.js: The type of the el should be a string!";
}
//do life
if (typeof thisComponent.life.using === "function") {
thisComponent.life.using();
}
if (isRealObj(config.proxy)) {
thisComponent.proxy = config.proxy;
}
//start building
thisComponent.data = typeof thisComponent.data === "function" ? thisComponent.data() : thisComponent.data;
if (!isRealObj(thisComponent.data)) {
thisComponent.data = {};
}
for (var i in config.data) {
thisComponent.data[i] = config.data[i];
}
thisComponent.staticData = typeof thisComponent.staticData === "function" ? thisComponent.staticData() : thisComponent.staticData;
if (!isRealObj(thisComponent.staticData)) {
thisComponent.staticData = {};
}
for (var i in config.staticData) {
thisComponent.staticData[i] = config.staticData[i];
}
for (var i in config.methods) {
thisComponent.methods[i] = config.methods[i];
}
return new aleComponentObject(config.el, thisComponent);
}
function handleComponentCreate(config) {
//执行混入 mixin
for (var i = 0; i < pluginMixinList.length; i++) {
config = pluginMixinList[i](config);
}
if (config.template === undefined) {
throw "Ale.js: No template is added when creating a component object!";
}
config.life = isRealObj(config.life) ? config.life : {};
config.dataType = isRealObj(config.dataType) ? config.dataType : {};
//判断组件类型
if (!Array.isArray(config.imports)) {
//单组件
//type 1代表单组件 2代表复合组件
config.type = 1;
} else {
//复合组件
//type 1代表单组件 2代表复合组件
config.type = 2;
//复合组件template第一个必定是父组件的模板
config.template = [config.template];
var thisCom,
thisComData,
thisComStaticData,
newData = {},
newMethods = {},
newLife = {},
newProxy = {},
newStaticData = {},
newDataTypeData = {},
newDataTypeStaticData = {},
newImports = []; //这里为了防止递归
for (var i = 0; i < config.imports.length; i++) {
if (typeof config.imports[i] === "string") {
thisCom = componentList[config.imports[i]];
} else if (typeof config.imports[i] === "object") {
thisCom = config.imports[i].config;
}
if (thisCom === undefined) {
throw "Ale.js: The imported component is not created!";
}
if (thisCom.type === 1) {
//单组件
config.template.push(thisCom.template);
} else {
//复合组件
config.template = config.template.concat(thisCom.template);
newImports = newImports.concat(thisCom.imports);
}
//每一个import都替换一次全部data
thisComData = typeof thisCom.data === "function" ? thisCom.data() : thisCom.data;
thisComStaticData = typeof thisCom.staticData === "function" ? thisCom.staticData() : thisCom.staticData;
if (isRealObj(thisComData)) {
for (var a in thisComData) {
newData[a] = thisComData[a];
}
}
if (isRealObj(thisCom.methods)) {
for (var a in thisCom.methods) {
newMethods[a] = thisCom.methods[a];
}
}
if (isRealObj(thisCom.life)) {
for (var a in thisCom.life) {
newLife[a] = thisCom.life[a];
}
}
if (isRealObj(thisCom.proxy)) {
for (var a in thisCom.proxy) {
newProxy[a] = thisCom.proxy[a];
}
}
if (isRealObj(thisCom.dataType.data)) {
for (var a in thisCom.dataType.data) {
newDataTypeData[a] = thisCom.dataType.data[a];
}
}
if (isRealObj(thisCom.dataType.staticData)) {
for (var a in thisCom.dataType.staticData) {
newDataTypeStaticData[a] = thisCom.dataType.staticData[a];
}
}
if (isRealObj(thisComStaticData)) {
for (var a in thisComStaticData) {
newStaticData[a] = thisComStaticData[a];
}
}
}
config.imports = config.imports.concat(newImports);
//最后替换
config.data = typeof config.data === "function" ? config.data() : config.data;
config.staticData = typeof config.staticData === "function" ? config.staticData() : config.staticData;
if (isRealObj(config.data)) {
for (var i in config.data) {
newData[i] = config.data[i];
}
}
//methods
if (isRealObj(config.methods)) {
for (var i in config.methods) {
newMethods[i] = config.methods[i];
}
}
//life
if (isRealObj(config.life)) {
for (var i in config.life) {
newLife[i] = config.life[i];
}
}
//proxy
if (isRealObj(config.proxy)) {
for (var i in config.proxy) {
newProxy[i] = config.proxy[i];
}
}
//dataType data
if (isRealObj(config.dataType.data)) {
for (var i in config.dataType.data) {
newDataTypeData[i] = config.dataType.data[i];
}
}
//dataType staticData
if (isRealObj(config.dataType.staticData)) {
for (var i in config.dataType.staticData) {
newDataTypeStaticData[i] = config.dataType.staticData[i];
}
}
//staticData
if (isRealObj(config.staticData)) {
for (var i in config.staticData) {
newStaticData[i] = config.staticData[i];
}
}
config.data = newData;
config.methods = newMethods;
config.life = newLife;
config.proxy = newProxy;
config.dataType.data = newDataTypeData;
config.dataType.staticData = newDataTypeStaticData;
config.staticData = newStaticData;
}
return config;
}
/*
type:
normal普通数据
static静态数据
*/
function executeProxy(type, fun, i, val) {
if (typeof fun === "function") {
var needBreak = false;
function preventUpdating() {
needBreak = true;
}
var passInObj = {
type: type,
key: i,
val: val,
preventUpdating: preventUpdating
},
newVal = fun(passInObj);
return {
val: newVal,
needBreak: needBreak
}
}
return {
val: val,
needBreak: false
}
}
function isNative(api) {
return /native code/.test(api.toString()) && typeof api !== 'undefined'
}
function handleDOMUpdateWhenAsync(queue) {
for (var i in queue) {
for (var a = 0; a < queue[i].nodeList.length; a++) {
//开始更新DOM
if (queue[i].diff) {
deepForDiff(queue[i].renderingResultObj.newEl.childNodes, queue[i].nodeList[a].childNodes, queue[i].nodeList[a], queue[i].renderingResultObj.newTem);
} else {
queue[i].nodeList[a].innerHTML = queue[i].renderingResultObj.newTem;
}
elDeepAddDM(queue[i].nodeList[a], queue[i].data, queue[i].methods);
}
}
}
function freshAsyncQueue() {
if (typeof tickCallbackFun === "function") {
//这里新建一个变量存储 tickCallbackFun,是为了预防用户在里面添加nextTick
var tickCallbackFunCopy = tickCallbackFun;
tickCallbackFun = null;
tickCallbackFunCopy();
}
if (needUpdateDOMListLength === 0) {
isNextTickWaiting = false;
} else {
nextTick(needUpdateDOMList);
needUpdateDOMList = [];
needUpdateDOMListLength = 0;
}
}
function nextTick(queue) {
isNextTickWaiting = true;
(function(queue) {
//api状态
if (typeof Promise !== "undefined" && isNative(Promise)) {
new Promise(function(res, rej) {
res();
}).then(function() {
handleDOMUpdateWhenAsync(queue);
//刷新异步队列
freshAsyncQueue();
})
} else {
//使用timeout
setTimeout(function() {
handleDOMUpdateWhenAsync(queue);
//刷新异步队列
freshAsyncQueue();
}, 0);
}
})(queue);
}
function DOMUpdateQueue(data, methods, obj) {
//判断是否在全局设置里打开了async
if (configList.async) {
obj.data = data;
obj.methods = methods;
//判断是否wating
needUpdateDOMList[obj.id.toString()] = obj;
needUpdateDOMListLength++;
if (!isNextTickWaiting) {
//异步更新DOM
nextTick(needUpdateDOMList);
needUpdateDOMList = [];
needUpdateDOMListLength = 0;
}
} else {
for (var a = 0; a < obj.nodeList.length; a++) {
if (obj.diff) {
deepForDiff(obj.renderingResultObj.newEl.childNodes, obj.nodeList[a].childNodes, obj.nodeList[a], obj.renderingResultObj.newTem);
} else {
obj.nodeList[a].innerHTML = obj.renderingResultObj.newTem;
}
elDeepAddDM(obj.nodeList[a], data, methods);
}
}
}
function renderingDOM(obj) {
/* obj内部属性
type
template
data
life
nodeList
imports
staticData
methods
*/
var templateBindObj = {
data: obj.data,
methods: obj.methods,
staticData: obj.staticData
}
//判断组件类型
if (obj.type === 1) {
//单组件
//判断模板是否为函数
var newTem = typeof obj.template === "function" ? bindObj(obj.template, templateBindObj)() : obj.template,
newEl = document.createElement("div");
//filter
for (var a = 0; a < filterList.length; a++) {
newTem = filterList[a](newTem);
}
newEl.innerHTML = newTem;
} else {
//复合组件
var newTem = obj.template[0], //第一个必定是父组件模板
reg,
newEl = document.createElement("div");
if (typeof newTem === "function") {
newTem = bindObj(newTem, templateBindObj)();
}
for (var a = 1; a < obj.template.length; a++) {
reg = new RegExp("<" + (typeof obj.imports[a - 1] === "string" ? obj.imports[a - 1] : obj.imports[a - 1].config.name) + "/>", "g");
if (typeof obj.template[a] === "function") {
newTem = newTem.replace(reg, bindObj(obj.template[a], templateBindObj)());
} else {
newTem = newTem.replace(reg, obj.template[a]);
}
}
//filter
for (var a = 0; a < filterList.length; a++) {
newTem = filterList[a](newTem);
}
newEl.innerHTML = newTem;
}
if (typeof obj.life.rendering === "function") {
obj.life.rendering();
}
return ({
newEl: newEl,
newTem: newTem
});
}
function executePluginInject(th) {
for (var i = 0; i < pluginInjectList.length; i++) {
pluginInjectList[i](th);
}
}
function firstRenderingDOM(i, data, methods, obj) {
/* obj内部属性
type
template
life
nodeList
imports
id
staticData
*/
obj.data = data;
obj.methods = methods;
var renderingResultObj = renderingDOM(obj);
DOMUpdateQueue(data, methods, {
id: obj.id,
nodeList: obj.nodeList,
renderingResultObj: renderingResultObj,
diff: false
});
executePluginInject(i);
}
function updateDOM(i, data, methods, obj) {
/* obj内部属性
type
template
life
nodeList
imports
id
staticData
newData(这里添加newData是为了和data区分开,因为data需要继承this)
*/
obj.data = obj.newData;
obj.methods = methods;
var renderingResultObj = renderingDOM(obj);
DOMUpdateQueue(data, methods, {
id: obj.id,
nodeList: obj.nodeList,
renderingResultObj: renderingResultObj,
newData: obj.newData,
diff: true
});
executePluginInject(i);
}
/* Simple diff
(c) 2018 Dong Yingxuan (Bill Dong)
*/
function deepForDiff(vNewChildren, rChildren, rParent, template) {
if (!configList.diff) {
rParent.innerHTML = template;
}
//判断子节点是否为空
if (vNewChildren.length === 0) {
rParent.innerHTML = "";
return;
}
var a = 0;
for (var i = 0; i < vNewChildren.length; i++) {
//比较同级
while (vNewChildren[i + 1] === undefined && rChildren[i + 1] !== undefined) {
rChildren[i + 1].remove();
}
//比较子级
//判断真实节点是否拥有这个元素
if (rChildren[i] === undefined) {
//没有
//判断是否是文本节点
if (rParent.nodeName === "#text") {
//判断vNewChil是否是文本节点
if (vNewChildren[i].nodeName === "#text") {
rParent.nodeValue = vNewChildren[i].nodeValue;
} else {
rParent.parentNode.replaceChild(vNewChildren[i], rParent);
}
} else {
rParent.appendChild(vNewChildren[i].cloneNode(true));
}
} else {
//有
if (vNewChildren[i].nodeName === "#text") {
//判断真实DOM是否也是文本节点
if (rChildren[i].nodeName === "#text") {
if (vNewChildren[i].nodeValue !== rChildren[i].nodeValue) {
rChildren[i].nodeValue = vNewChildren[i].nodeValue;
}
} else {
//不是
if (rChildren[i].innerHTML !== vNewChildren[i].nodeValue) {
rChildren[i].innerHTML = vNewChildren[i].nodeValue;
}
}
} else {
//不是文本节点
if (rChildren[i].nodeName !== "#text") {
//判断其他差异
var isDifferentNodeOnTag = (rChildren[i].tagName !== vNewChildren[i].tagName);
if (isDifferentNodeOnTag) {
rParent.replaceChild(vNewChildren[i].cloneNode(true), rChildren[i]);
continue;
} else {
var vNewChildrenAttr = vNewChildren[i].attributes,
rChildrenAttr = deepCopy(rChildren[i].attributes),
creatAttrNode;
//判断哪个节点数量最多
if (vNewChildrenAttr.length > rChildrenAttr.length) {
//虚拟大于
for (var c = 0; c < vNewChildrenAttr.length; c++) {
if (rChildrenAttr[c] === undefined || rChildrenAttr[c].name !== vNewChildrenAttr[c].name || rChildrenAttr[c].value !== vNewChildrenAttr[c].value) {
rChildren[i].removeAttribute(rChildrenAttr[c].name);
rChildren[i].setAttribute(vNewChildrenAttr[c].name, vNewChildrenAttr[c].value);
}
}
} else {
//虚拟等于少于
for (var c = 0; c < rChildrenAttr.length; c++) {
if (vNewChildrenAttr[c] === undefined) {
rChildren[i].removeAttribute(rChildrenAttr[c].name);
} else {
if (vNewChildrenAttr[c].name !== rChildrenAttr[c].name || vNewChildrenAttr[c].value !== rChildrenAttr[c].value) {
rChildren[i].removeAttribute(rChildrenAttr[c].name);
rChildren[i].setAttribute(vNewChildrenAttr[c].name, vNewChildrenAttr[c].value);
}
}
}
}
}
//判断虚拟DOM是否有子孙
if (vNewChildren[i].childNodes.length > 0) {
deepForDiff(vNewChildren[i].childNodes, rChildren[i].childNodes, rParent.childNodes[i]);
} else {
//没有
//判断真实DOM是否有子孙
if (rChildren[i].childNodes.length > 0) {
rChildren[i].innerHTML = "";
}
}
} else {
//真实DOM是文本节点
rParent.replaceChild(vNewChildren[i], rChildren[i]);
}
}
}
}
}
function xssTemReplace(template) {
if (typeof template === "string" && !configList.html) {
template = template.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
}
return template;
}
function proxyBindThis(proxy, aleCom) {
for (var i in proxy) {
proxy[i] = bindObj(proxy[i], aleCom);
}
return proxy;
}
function methodsBindThis(methods, aleCom) {
for (var i in methods) {
methods[i] = bindObj(methods[i], aleCom);
}
return methods;
}
function lifeBindThis(life, aleCom) {
for (var i in life) {
life[i] = bindObj(life[i], aleCom);
}
return life;
}
function elDeepAddDM(el, data, methods) {
el.data = data;
el.methods = methods;
if (el.children.length > 0) {
for (var i = 0; i < el.children.length; i++) {
elDeepAddDM(el.children[i], data, methods);
}
}
}
function deepCopy(obj) {
var newObj = Array.isArray(obj) ? [] : {};
if (Array.isArray(obj)) {
for (var key = 0; key < obj.length; key++) {
if (isRealObj(obj[key]) || Array.isArray(obj[key])) {
newObj.push(deepCopy(obj[key]));
} else {
newObj.push(obj[key]);
}
}
} else {
for (var key in obj) {
if (isRealObj(obj[key]) || Array.isArray(obj[key])) {
newObj[key] = deepCopy(obj[key]);
} else {
newObj[key] = obj[key];
}
}
}
return newObj;
}
function isRealObj(obj) {
var proto,
Ctor,
class2type = function() {
return {};
}
if (!obj || class2type().toString.call(obj) !== "[object Object]") {
return false;
}
proto = Object.getPrototypeOf(obj);
if (!proto) {
return true;
}
Ctor = class2type.hasOwnProperty.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && class2type.hasOwnProperty.toString(Ctor) === class2type.hasOwnProperty.toString(Object);
}
function bindObj(fn, ctx) {
function boundFn(a) {
var l = arguments.length;
return l ?
l > 1 ?
fn.apply(ctx, arguments) :
fn.call(ctx, a) :
fn.call(ctx)
}
boundFn._length = fn.length;
return boundFn;
}
})(window, document);