BLOG

new演算子とinstanceofについて

memo

new演算子について

コンストラクター関数からインスタンスを作成するために使用する演算子

コンストラクター関数の戻り値がオブジェクトの場合

コンストラクターが返すreturnのオブジェクトを新しいインスタンスオブジェクトとして呼び出し元に返す

コンストラクター関数の戻り値がオブジェクト以外の場合、もしくは戻り地のreturnが定義されていない場合

コンストラクターのプロトタイプのプロパティを__proto__にコピーし、コンストラクター関数内で使用しているthisを呼び出し元へ返却する


function F(a,b){
    this.a = a;
    this.b = b;
        // return {}; これをつけると空のオブジェクトが返ってきて、cも格納されていない

}

F.prototype.c = function(){}

const instance = new F(1,2);
console.log(instance)


F {a: 1, b: 2}
a: 1
b: 2
__proto__:
c: ƒ ()
constructor: ƒ F(a,b)
__proto__: Object

F.prototype.c = function(){}
でオブジェクトのprotoの中にcが格納される


function F(a,b){
    this.a = a;
    this.b = b;
    // return {}; 
}

F.prototype.c = function(){}

function newOpe(c, ...args){
    console.log(args);
}

const instance = newOpe(F, 1, 2);
console.log(instance)


(2) [1, 2]
0: 1
1: 2
length: 2
__proto__: Array(0)

…argsのようなのをレスとパラメーターという。
引数で渡ってきたものを配列に直すためにはこのように記述する


this(this.aなど)が呼び出し元のオブジェクト(return{};など)のインスタンスとなる場合を考える

まずthisというオブジェクトをprototypeの参照を保持した状態で生成する
そのために、オブジェクトのObject.createというメソッドを使う。


function newOpe(c, ...args){
    const _this = Object.create(C.prototype);
    console.log(args);
}

とする。
渡ってきたコンストラクター関数のプロトタイプをコピーする。
この_thisというのはc.prototypeが__proto__に格納された状態で生成される空のオブジェクトとなる


function F(a,b){
    this.a = a;
    this.b = b;
    return {};
}

F.prototype.c = function(){

}

function newOpe(C, ...args){
    const _this = Object.create(C.prototype);
    console.log(_this);
}

const instance = newOpe(F, 1,2);
console.log(instance);


F {}
__proto__:
c: ƒ ()
constructor: ƒ F(a,b)
__proto__: Object

console.log(_this);とすると空のオブジェクトが生成されて、__proto__にはcが入った状態で生成される。
なのでObject.createというメソッドは__proto__に引数で設定されたオブジェクトC.prototypeをコピーして、さらに空のオブジェクトを生成するメソッドである。

また、空のオブジェクトconst _thisをコンストラクター関数Cを実行するときの_thisとして設定してfunction newOpe(C, …args){}のCを実行をすることによってthis.aのようなthisの値が空のオブジェクト_thisに設定される。

上記のような流れを実装するとこうなる


function F(a,b){
    this.a = a;
    this.b = b;
    // return {};
}

F.prototype.c = function(){}

function newOpe(C, ...args){
    const _this = Object.create(C.prototype);
    const result = C.apply(_this, args);
    console.log(result);
}

const instance = newOpe(F, 1,2);


undefind

まずCを実行するのでCから始めて、空のオブジェクトの_thisをCのthisとしたいので、applyメソッドを使う。applyの第一引数にこの関数の中のthisを設定するので_thisを設定する。
第二引数以下はCを実行するときの引数を配列にして渡すので、C.apply(_this, args);とするとCを実行する際に、this.aの中に使われているthisはC.apply(_this, args);の_this、function F(a,b)関数の引数に渡ってくるものはC.apply(_this, args);のargsでそれぞれ渡してあげることが出来る。

出力結果がなぜundifindかというと、returnがないから。
また、このときに_thisがどうなっているかというと、


function F(a,b){
    this.a = a;
    this.b = b;
    // return {};
}

F.prototype.c = function(){}

function newOpe(C, ...args){
    const _this = Object.create(C.prototype);
    const result = C.apply(_this, args);
    console.log(result, _this);
    return _this;
}

const instance = newOpe(F, 1,2);


F {a: 1, b: 2}
a: 1
b: 2
__proto__:
c: ƒ ()
constructor: ƒ F(a,b)
__proto__: Object

instanceofについて

どのコンストラクターから生成されたオブジェクトかを確認する。


function F(a, b) {
    this.a = a;
    this.b = b;
    // return {a: 1};
}

F.prototype.c = function() {}

const instance = new F(1,2);
console.log(instance);


F {a: 1, b: 2}

上記のようなオブジェクトインスタンスが確認できる
このインスタンスがどのコンスタラクター関数から生成されたのか確認する際にinstanceofを使用する

console.log(instance instanceof F);とすると結果はtrueになる。
return{a:1}のコメントアウトを外すと結果はfalseになる。
これは関数Fから生成されたインスタンスではないという意味