Deep TypeScript
prototype
JavaScriptはプロトタイプベースの言語。別のオブジェクト(=プロトタイプ)を参照して性質を引き継ぐ。 あるオブジェクトにプロパティやメソッドが見つからなければ、プロトタイプをたどって探す。
サンプル
class構文の実態はprototype構文である。
class構文
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} barks!`);
}
}
prototype構文
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + " makes a sound");
};
// Animal 概念
/*
[[Prototype]]: Function.prototype,
[[Call]]: (thisArg, [name]) => {
// Animal("Pochi")
thisArg.name = name;
return undefined;
},
[[Construct]]: ([name], newTarget) => {
// new Animal("Pochi")
const obj = OrdinaryCreateFromConstructor(newTarget, Animal.prototype);
Animal.[[Call]](obj, [name]);
return obj;
},
prototype: {
[[Prototype]]: Object.prototype,
constructor: Animal,
speak: function() {
console.log(this.name + " makes a sound");
}
},
name: "Animal",
length: 1 // 仮引数の数(name)
*/
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log(this.name + " barks!");
};
// Dog 概念
/*
[[Prototype]]: Function.prototype,
[[Call]]: (thisArg, [name, breed]) => {
// Dog("Pochi", "Shiba")
Animal.[[Call]](thisArg, [name]);
thisArg.breed = breed;
return undefined;
},
[[Construct]]: ([name, breed], newTarget) => {
// new Dog("Pochi", "Shiba")
obj = OrdinaryCreateFromConstructor(newTarget, "%Object.prototype%", internalProto = Dog.prototype);
Dog.[[Call]](obj, [name, breed]);
return obj;
},
prototype: {
[[Prototype]]: Animal.prototype,
constructor: Dog,
bark: function() {
console.log(this.name + " barks!");
}
},
name: "Dog",
length: 2 // 仮引数の数(name, breed)
*/
const dog = new Dog("Pochi", "Shiba");
dog.speak(); // Pochi makes a sound
dog.bark(); // Pochi barks!
// dog 概念
/*
[[Prototype]]: Dog.prototype,
name: "Pochi",
breed: "Shiba"
*/
// dog 全体像
/*
{
[[Prototype]]: {
[[Prototype]]: {
[[Prototype]]: Object.prototype,
constructor: Animal,
speak: [Function: speak]
},
constructor: Dog,
bark: [Function: bark]
},
name: "Pochi",
breed: "Shiba"
};
*/
Object.getPrototypeOf
prototype
を取得する。
インスタンスオブジェクト
Object.getPrototypeOf(dog) === Dog.prototype; // true
Object.getPrototypeOf(Dog.prototype) === Animal.prototype; // true
Object.getPrototypeOf(Animal.prototype) === Object.prototype; // true
Object.getPrototypeOf(Object.prototype) === null; // true
コンストラクタオブジェクト
Object.getPrototypeOf(Dog) === Function.prototype; // true
Object.getPrototypeOf(Function.prototype) === Object.prototype; // true
Object.getPrototypeOf(Object.prototype) === null; // true
instanceof
インスタンスオブジェクトが特定のコンストラクタオブジェクトから生成されたかどうかを判定する演算子。
サンプル
dog instanceof Dog; // true
dog instanceof Animal; // true
dog instanceof Object; // true
内部処理イメージ
プロトタイプチェーンをたどって判定。
function instanceOf(left, right) {
const proto = right?.prototype;
let cur = Object.getPrototypeOf(left);
while (cur) {
if (cur === proto) return true;
cur = Object.getPrototypeOf(cur);
}
return false;
}