JSプロトタイプとほとんど知られていない事実

叙情的な紹介 



次のインタビューでもう一度プロトタイプについてたくさんの質問を受けたので、プロトタイピングの複雑さを少し忘れていたことに気づき、知識を更新することにしました。著者のインスピレーション、彼がプロトタイプをどのように「感じている」か、または記事がトピックの別の部分に関するものであり、何が起こっているのかを完全に把握していないかのいずれかで書かれた記事をたくさん見つけました。 



ES5の昔から、そして私が聞いたことのないES6でさえ、多くの非自明なことがあることがわかりました。また、ブラウザコンソールの出力が現実に対応していない可能性があることも判明しました。



プロトタイプとは



JSのオブジェクトには、たとえば次のコードのように、独自の継承されたプロパティがあります。



var foo = { bar: 1 };
foo.bar === 1 // true
typeof foo.toString === "function" // true


オブジェクトにfoobar値を持つ独自のプロパティがありますが1、などの他のプロパティもありますtoStringオブジェクトfooが新しいプロパティを取得する方法を理解するために、オブジェクトtoString何で構成されているかを見てみましょう。





重要なのは、オブジェクトが別のプロトタイプオブジェクトへの参照を持っているということです。フィールドfoo.toStringアクセスするとき、そのようなプロパティの検索は、最初にオブジェクト自体から実行され、次にそのプロトタイプ、そのプロトタイプのプロトタイプなどから、プロトタイプチェーンが終了するまで実行されます。これは、オブジェクトとそのプロトタイプオブジェクトが順番にチェックされる、単一にリンクされたオブジェクトのリストのようなものです。これは、プロパティの継承が実装される方法です。たとえば、(ほとんどですが、後で詳しく説明します)任意のオブジェクトにメソッドvalueOfとがありtoStringます。



 



, constructor __proto__. constructor -, , __proto__ ( null, ). ., .



constructor 



constructor – , : 



const a = {};
a.constructor === Object // true


, , : 



object.constructor(object.arg)


, , , . constructor , writable , , , .



 



, , JS . , , [[SlotName]]. [[Prototype]] - ( null, ).





- , [[Prototype]] JS , . , __proto__, , JS .



,



__proto__ [[Prototype]] Object.prototype:





- __proto__ . __proto__ , . __proto__ :



const foo = {};
foo.toString(); //  toString()   Object.prototype   '[object Object]',   
foo.__proto__ = null; //    null
foo.toString(); //      TypeError: foo.toString is not a function
foo.__proto__ = Object.prototype; //   
foo.toString(); //   ,  TypeError: foo.toString is not a function


? , __proto__ Object.prototype, foo. - Object.prototype, __proto__ .

. :





var baz = { test: "test" };
var foo = { bar: 1 };
foo.__proto__ = baz;


Chrome foo :





baz Object.prototype:



baz.__proto__ = null;


Chrome :





Object.prototype baz __proto__ undefined foo, Chrome __proto__ . [[Prototype]], __proto__, , .





: .



: __proto__ Object.setPrototypeOf.



var myProto = { name: "Jake" };
var foo = {};
Object.setPrototypeOf(foo, myProto);
foo.__proto__ = myProto;


, , .

[[Extensible]] , . , false : Object.freeze, Object.seal, Object.preventExtensions. :



const obj = {};
Object.preventExtensions(obj);
Object.setPrototypeOf(obj, Function.prototype); // TypeError: #<Object> is not extensible


. .

:



const foo = Object.create(myPrototype);


Object.create, __proto__:



const foo = { __proto__: myPrototype };


:



const f = function () {}
f.prototype = myPrototype;
const foo = new f();


new, . , new prototype , .. [[Prototype]], .





.



function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

const user = new Person('John', 'Doe');


Person , :





Person.prototype? , prototype (note 3), prototype , . , :



Person.prototype.fullName = function () {
    return this.firstName + ' ' + this.lastName;
}




user.fullName() "John Doe".



new 



new . new :



  1. self

  2. prototype self

  3. self this

  4. self ,



, new :



function custom_new(constructor, args) {
    // https://stackoverflow.com/questions/31538010/test-if-a-variable-is-a-primitive-rather-than-an-object
    function isPrimitive(val) {
        return val !== Object(val);
    }
    const self = Object.create({});
    const constructorValue = constructor.apply(self, args) || self;
    return isPrimitive(constructorValue) ? self : constructorValue;
}
custom_new(Person, ['John', 'Doe'])


ES6 new new.target, , new, :



function Foo() {
    console.log(new.target === Foo);
}
Foo(); // false
new Foo(); // true


new.target undefined , new;





, Student Person.



  1. Student Person

  2. `Student.prototype` `Person`

  3. `Student.prototype`



function Student(firstName, lastName, grade) {
    Person.call(this, firstName, lastName);
    this.grade = grade;
}

//  1
Student.prototype = Object.create(Person.prototype, {
    constructor: {
        value:Student,
        enumerable: false,
        writable: true
    }
});
//  2
Object.setPrototypeOf(Student.prototype, Person.prototype);

Student.prototype.isGraduated = function() {
    return this.grade === 0;
}

const student = new Student('Judy', 'Doe', 7);




( , .. this ), ( )

1 , .. Object.setPrototypeOf .



 



, , Person Student: 



class Person {
    constructor(firstName, lastName) {  
        this.firstName = firstName; 
        this.lastName = lastName;
    }

    fullName() {
        return this.firstName + ' ' + this.lastName;
    }
}

class Student extends Person {
    constructor(firstName, lastName, grade) {
        super(firstName, lastName);
        this.grade = grade;
    }

    isGraduated() {
        return this.grade === 0;
    }
}


, : 



  • , new





prototype .



P.S.



1つの記事ですべての質問に答えることを期待するのは単純です。興味深い質問、歴史への遠足、私がすべて間違ったことをしたという合理的または根拠のない発言、またはエラーの修正がある場合は、コメントに書き込んでください。 




All Articles