var A = Class.extend({
arr : [1, 2]
});
var a1 = new A();
var a2 = new A();
a1.arr.push(3);
console.log("arr = " + a1.arr); //arr = 1,2,3
console.log("arr = " + a2.arr); //arr = 1,2,3
Cocos2d-js里面简单的类继承和对象创建,但是奇怪的是,a1对象和a2对象里面的成员属性arr明显是指向了同一个数组,所以这样的写法是不可取的,数组的定义应该在init函数里面进行定义。
出现这个问题的原因要从JavaScript的继承的实现来找。JavaScript本身没有提供继承的机制,一般是通过对象的原型来实现。Cocos2d-JS里面的类继承实现参考了John Resiq的JavaScript继承的机制,并修改了Class根类的实现。下面是John Resiq的Class实现
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
从上面的代码可以看出,A继承了Class,把Array类型的成员属性指向实参prop对象中对应Array,而构造函数也没有对Array类型的成员属性进行处理,所以像本文一开始那样创建对象,属性arr会指向同一个数组。
如果你就是喜欢那样定义类里面的数组的话,可以对构造函数Class()进行修改,如下
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
for(var name in this) {
this[name] instanceof Array &&
(this[name] = this[name].slice());
}
}
原来代码的结果如下
var A = Class.extend({
arr : [1, 2]
});
var a1 = new A();
var a2 = new A();
a1.arr.push(3);
console.log("arr = " + a1.arr); //arr = 1,2,3
console.log("arr = " + a2.arr); //arr = 1,2
在构造函数里面把每一个数组属性都给一个副本就可以了