ECMAScript 5による継承チェーンの実現
9150 ワード
以前、javascript functionによるクラス相続チェーンの実現を書いたことがあります.ECMAScript 3.1では、functionをクラスにシミュレートできます.しかし、プロトタイプチェーンのため、構造体の実現は非常に煩雑です.
現在、各ブラウザはECMAScript 5にアップグレードされてから、徐々にfunctionで模擬クラスの考えを捨てました.対象に変換して類の構想をなぞらえ似せます.すなわち、
これにより、新しいクラスの関数は以下の通りです.
大まかな機能は、オブジェクトにget Instance方法と親類のsuperclassオブジェクトを追加し、親類の構造体と方法を呼び出すことができるようにするものです.
テスト:
この方法の注意点:
1.instance ofを完全に使用できず、どのタイプかを判断する(親タイプを判断する).しかし、isProttypeOfで正確にどのような種類かを判断できます.
2.キーワードnewを用いてオブジェクトを実装する必要はありません.newInstanceの方法を使います.(無駄話)
以前の文章を比べてみると、継承の実現は簡単ではないことが分かります.
instance ofの判断制限については、全く心配しなくても大丈夫です.
例えば、次のjavaコードは、どのインターフェースを判断するためにinstance ofを使用していますか?
javascriptはinstance ofがない場合、コードはこのように実現できます.
また、セッティングを書く時は、常にcompossiteモードを使いますが、このモードではinstance ofは必要ありません.
instance ofの問題を解決するために.私たちはfunctionをObject.creatのテンプレートとして導入すれば、この問題を解決できます.
instance ofがはっきりと見えます.プロトタイプチェーンのfunctionを判断できます.
現在、各ブラウザはECMAScript 5にアップグレードされてから、徐々にfunctionで模擬クラスの考えを捨てました.対象に変換して類の構想をなぞらえ似せます.すなわち、
var Cat = {};
以上のコードは、オブジェクトとして見てもいいし、クラスとして見てもいいです.もちろん今流行している静的な言語の中で、たとえばjava、クラス自体が対象です.(相手が先か、それとも先にこのような鶏の卵なのか、それとも卵なのかという哲学的な問題はここでは議論しません.)これにより、新しいクラスの関数は以下の通りです.
var Class = (function() {
/**
* Initialze object from class.
* @param class object.
*/
var initializeClass = (function() {
if (Object.create) {
return Object.create;
} else {
return function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
})();
/**
* The main function of Class.
*
* @param classContent
* @param superClass
*/
return function() {
var classPrototype = arguments[arguments.length - 1] || {};
for (var index = 0; index < arguments.length - 1; index++) {
var superClass = arguments[index];
if (typeof superClass["initialize"] == "function") {
classPrototype.superclass = superClass["initialize"];
} else {
classPrototype.superclass = function() {};
}
for (var prop in superClass) {
if (prop == "initialize" || prop == "newInstance") {
continue;
}
if (classPrototype.hasOwnProperty(prop)) {
if (typeof superClass[prop] == "function") {
classPrototype.superclass[prop] = superClass[prop];
}
} else {
classPrototype[prop] = superClass[prop];
}
}
}
classPrototype.newInstance = function() {
var instance = initializeClass(this);
if (instance["initialize"]) {
instance["initialize"].apply(instance, arguments);
}
return instance;
};
return classPrototype;
};
})();
大まかな機能は、オブジェクトにget Instance方法と親類のsuperclassオブジェクトを追加し、親類の構造体と方法を呼び出すことができるようにするものです.
テスト:
var Animal = Class({
initialize: function(age) {
this.age = age;
},
eat: function() {
alert("eat");
}
});
var Cat = Class(Animal, {
initialize: function(name, age) {
//
Cat.superclass.call(this, age);
//
this.name = name;
//
this.superclass.eat();
},
eat: function() {
alert("eat fish");
}
});
var animal = Animal.newInstance(12);
animal.eat();
var cat = Cat.newInstance("123", 12);
alert(cat.name);
alert(cat.age);
cat.eat();
この方法の注意点:
1.instance ofを完全に使用できず、どのタイプかを判断する(親タイプを判断する).しかし、isProttypeOfで正確にどのような種類かを判断できます.
2.キーワードnewを用いてオブジェクトを実装する必要はありません.newInstanceの方法を使います.(無駄話)
以前の文章を比べてみると、継承の実現は簡単ではないことが分かります.
instance ofの判断制限については、全く心配しなくても大丈夫です.
例えば、次のjavaコードは、どのインターフェースを判断するためにinstance ofを使用していますか?
public interface Animal {
}
public interface Cat extends Animal {
void eatFish();
}
public interface Dog extends Animal {
void eatFood();
}
public class Test {
public void animalExecute(Animal animal) {
if (animal instanceof Cat) {
((Cat) animal).eatFish();
} else if (animal instanceof Dog) {
((Cat) animal).eatFood();
}
}
}
javascriptはinstance ofがない場合、コードはこのように実現できます.
var Animal = Class({});
var Dog = Class(Animal, {
eatFood: function() {};
})
var Cat = Class(Animal, {
eatFish: function() {};
})
function animalExecute(animal) {
if (animal.eatFood) {// Dog
animal.eatFood();
} else if (animal.eatFish) {// Cat
animal.eatFish();
}
}
つまり、javascriptはinstance ofを全く必要とせず、同じ機能を実現することができます.また、セッティングを書く時は、常にcompossiteモードを使いますが、このモードではinstance ofは必要ありません.
instance ofの問題を解決するために.私たちはfunctionをObject.creatのテンプレートとして導入すれば、この問題を解決できます.
var Class = (function() {
/**
* Inherits function.(node.js)
*
* @param ctor subclass's constructor.
* @param superctor superclass's constructor.
*/
var inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
// ECMAScript 5
if (Object.create) {
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
} else {
function F() {};
F.prototype = superCtor.prototype;
ctor.prototype = new F();
ctor.prototype.constructor = ctor;
}
};
/**
* Class function.
*/
return function() {
var subClazz = arguments[arguments.length - 1] || function() {};
var fn = subClazz.initialize == null ? function() {} : subClazz.initialize;
for (var index = 0; index < arguments.length - 1; index++) {
inherits(fn, arguments[index]);
}
for (var prop in subClazz) {
if (prop == "initialize") {
continue;
}
fn.prototype[prop] = subClazz[prop];
}
return fn;
}
})();
/**
* The definition of Cat Class.
*/
var Cat = Class({
/**
* Constructor.
*
* @param name Cat's name
*/
initialize: function(name) {
this.name = name;
},
/**
* Eat function.
*/
eat: function() {
alert(this.name + " is eating fish.");
}
});
/**
* The definition of Black Cat Class.
*/
var BlackCat = Class(Cat, {
/**
* Constructor.
*
* @param name Cat's name.
* @param age Cat's age.
*/
initialize: function(name, age) {
// call the constructor of super class.
BlackCat.super_.call(this, name);
this.age = age;
},
/**
* Eat function.
*/
eat: function() {
alert(this.name + "(" + this.age + ") is eating dog.");
}
});
/**
* The definition of Black Fat Cat Class.
*/
var BlackFatCat = Class(BlackCat, {
/**
* Constructor.
*
* @param name Cat's name.
* @param age Cat's age.
* @param weight Cat's weight.
*/
initialize: function(name, age, weight) {
// call the constructor of super class.
BlackFatCat.super_.call(this, name, age);
this.weight = weight;
},
/**
* Eat function.
*/
eat: function() {
alert(this.name + "(" + this.age + ") is eating dog. My weight: " + this.weight);
}
});
/**
* The definition of Dog Class.
*/
var Dog = Class({});
var cat = new BlackFatCat("John", 24, "100kg");
cat.eat();
// true
alert(cat instanceof Cat);
// true
alert(cat instanceof BlackCat);
// true
alert(cat instanceof BlackFatCat);
// true
alert(cat.constructor === BlackFatCat);
// false
alert(cat instanceof Dog);
instance ofがはっきりと見えます.プロトタイプチェーンのfunctionを判断できます.