您的位置:首页 > 移动开发 > Cocos引擎

cocos中类扩展的坑

2015-11-17 11:20 405 查看
这个真是坑啊,无语了。

通常在模拟类的实现时,属性是放在实例上,方法是放在原型上,取了节省性能和互不干扰的折中。但是cocos的有点扯。属性也放在了原型上,这就导致了一些问题。

先看重现:

// 定义一个新的类
var newClass = cc.Class.extend({
prop: 123,
ctor: function(){
this.super();
this.prop = 456;
console.log(this.prop);    // 456
console.log(this.__proto__.prop)   // 123
}
});
// 想想,在这里定义prop的时候,下意识是不是认为这是给newClass的实例的?而不是给newClass本身的?


这个坑在平时可能不起眼~看看是怎么发生的:

var ClassA = cc.Class.extend({
arr: [],
ctor: function(){
this.super();
},
init: function(){
this.arr.push(1);
},
onExit: function(){
this.arr = [];
}
});
// 假设这个对象一直存在,要不停的被复用。
var obj1 = new ClassA();
obj1.init();
// 过一会后
obj1.onExit();
// 再过一会
var obj2 = new ClassA();
obj2.init();
// 此时输出`obj2.arr`会发现是`[1, 1]`,而不是期望的`[1]`


尽管我们在onExit时释放了this.arr,让他等于一个新数组。但原型上的arr仍然存在。当实例一个新的对象obj2时,obj2.arr访问的仍然是原型上的arr,结果就变成了
[1, 1]


可能会认为在ctor中初始化一下
this.arr = []
不就结了,实际上ES6的class就是这么要求的。cocos为我们提供的这个类扩展方式,很容易产生歧义。

看看ES6的class规范如何定义属性:

class Point {

constructor(x, y) {
this.x = x;
this.y = y;
}

toString() {
return '('+this.x+', '+this.y+')';
}

}


属性要求用
this.
的方式创建。这样属性定义在实例身上,原型自然干净,坑就更少了。

不过cocos采用的貌似是jQuery作者提出的继承方案。是当初没有class时模拟class的一个方案。这种定义属性的方式,很容易JS原生开发者产生歧义。

再拿PHP的例子看看,虽然不确定PHP具体细节,但至少执行上看起来是没有歧义的:

class Test
{
public $a = array();

function __construct()
{
}
}

$obj = new Test();
array_push($obj->a, "1");
array_push($obj->a, "2");
array_push($obj->a, "3");
var_dump($obj->a);    // array(3) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3" }

$obj1 = new Test();

var_dump($obj1->a);    //  array(0) { }


可以看到obj1对属性a的修改并没有影响到obj2的属性a。但是翻译到cocos的extend,就会出现最上面提到的问题。所以要么就完整的支持 类似PHP这种 直接定义属性 的方式,要么就像ES6的class一样,不支持,只允许
this.
方式创建属性。

不吐槽了。


结论

属性放在ctor函数内进行用
this.prop = value
形式声明。

是的,因为这个,我们遇到严重的内存泄露了。


参考文档

ES6中文学习文档 http://es6.ruanyifeng.com/#docs/class
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: