PS:只是看源码学习过程中把认为重要的内容以笔记的形式记录下来。
本来是想写CCNode的,结果发现CCNode继承BaseNode,BaseNode再继承CCObject,那么,就先来看CCObject吧~
在CCObject类中,他是通过给原型方法赋值来实现类似成员函数相关的功能,如:prototype.destroy = function () {}。
【1】destroy():销毁对象。【因为这个方法很重要,所以我每步都插入关键的核心代码】
1.把需要销毁的对象加到销毁队列objectsToDestroy中。(不会立马销毁)
prototype.destroy = function () {
// 省略上下文
objectsToDestroy.push(this);
// 省略上下文
};
2.在CCDirector的主循环里,再当前帧渲染之前调用deferredDestroy()进行销毁。
mainLoop: CC_EDITOR ? function (deltaTime, updateAnimate) {
// 省略上下文
} : function (now) {
// 省略上下文
// Update
if (!this._paused) {
// 省略上下文
// Destroy entities that have been removed recently
Obj._deferredDestroy();
}
// 省略上下文
}
},
3.【deferredDestroy函数内部】遍历objectsToDestroy,如果对象还没销毁,则调用_destroyImmediate。然后把删掉的对象从objectsToDestroy队列里面清除。
function deferredDestroy () {
var deleteCount = objectsToDestroy.length;
for (var i = 0; i < deleteCount; ++i) {
var obj = objectsToDestroy[i];
if (!(obj._objFlags & Destroyed)) {
obj._destroyImmediate();
}
}
// if we called b.destory() in a.onDestroy(), objectsToDestroy will be resized,
// but we only destroy the objects which called destory in this frame.
if (deleteCount === objectsToDestroy.length) {
objectsToDestroy.length = 0;
}
else {
objectsToDestroy.splice(0, deleteCount);
}
if (CC_EDITOR) {
deferredDestroyTimer = null;
}
}
4.【_destroyImmediate函数内部】在对象销毁前,调用_onPreDestroy(). 所有的子类就可以在这个接口里做一些销毁对象前需要执行的操作了。
5.【_destroyImmediate函数内部】调用_destruct(),清除实例的所有引用。
prototype._destroyImmediate = function () {
if (this._objFlags & Destroyed) {
cc.errorID(5000);
return;
}
// engine internal callback
if (this._onPreDestroy) {
this._onPreDestroy();
}
if ((CC_TEST ? (/* make CC_EDITOR mockable*/ Function('return !CC_EDITOR'))() : !CC_EDITOR) || cc.engine._isPlaying) {
this._destruct();
}
this._objFlags |= Destroyed;
};
6.【_destruct函数内部】调用compileDestruct()构造出“析构函数”,然后调用destruct(this)析构函数清除实例的所有引用。
prototype._destruct = function () {
var ctor = this.constructor;
var destruct = ctor.__destruct__;
if (!destruct) {
destruct = compileDestruct(this, ctor);
js.value(ctor, '__destruct__', destruct, true);
}
destruct(this);
};
7.【compileDestruct函数内部】会遍历对象的key,然后用自带的原型方法hasOwnProperty去检测对象的自有属性,然后把所有自有属性置空再赋值给propsToReset。
8.【compileDestruct函数内部】判断如果有构造函数,则是类类型,同样把类里面的string、object、funciton等置空赋值给propsToReset。
PS:上面的7,8两个步骤很关键,大致意思就是构建一个propsToReset出来,key值用对象的key,value就是置空的值。
9.【compileDestruct函数内部】返回一个方法(可以勉强理解为“析构函数”),方法内部其实就是遍历propsToReset,把propsToReset的值赋值给对象,从而真正实现了清除实例的所有引用。
function compileDestruct (obj, ctor) {
var shouldSkipId = obj instanceof cc._BaseNode || obj instanceof cc.Component;
var idToSkip = shouldSkipId ? '_id' : null;
var key, propsToReset = {};
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (key === idToSkip) {
continue;
}
switch (typeof obj[key]) {
case 'string':
propsToReset[key] = '';
break;
case 'object':
case 'function':
propsToReset[key] = null;
break;
}
}
}
// Overwrite propsToReset according to Class
if (cc.Class._isCCClass(ctor)) {
var attrs = cc.Class.Attr.getClassAttrs(ctor);
var propList = ctor.__props__;
for (var i = 0; i < propList.length; i++) {
key = propList[i];
var attrKey = key + cc.Class.Attr.DELIMETER + 'default';
if (attrKey in attrs) {
if (shouldSkipId && key === '_id') {
continue;
}
switch (typeof attrs[attrKey]) {
case 'string':
propsToReset[key] = '';
break;
case 'object':
case 'function':
propsToReset[key] = null;
break;
case 'undefined':
propsToReset[key] = undefined;
break;
}
}
}
}
if (CC_SUPPORT_JIT) {
// compile code
var func = '';
for (key in propsToReset) {
var statement;
if (CCClass.IDENTIFIER_RE.test(key)) {
statement = 'o.' + key + '=';
}
else {
statement = 'o[' + CCClass.escapeForJS(key) + ']=';
}
var val = propsToReset[key];
if (val === '') {
val = '""';
}
func += (statement + val + ';\n');
}
return Function('o', func);
}
else {
return function (o) {
for (var key in propsToReset) {
o[key] = propsToReset[key];
}
};
}
}
【2】_objFlags:应该是记录对象的状态吧,状态的定义在CCObject.js也有,但具体每个状态什么时候用到,暂时在CCObject还没看到,估计是给子类使用的?
【3】cc.isValid():这个我们经常用来判断对象是否还有效的方法,就是通过_objFlags的状态来判断的。