抒情介绍
在下一次面试中再次收到关于原型的一堆问题后,我意识到我已经略微忘记了原型制作的复杂性,因此决定重新学习。我碰到了很多关于作者灵感,他“感觉”原型的方式而写的文章,或者该文章只是关于该主题的一个单独部分,而没有提供正在发生的事情的完整描述。
事实证明,从ES5甚至是我以前听说过的ES6的过去,都有很多不明显的东西。事实证明,浏览器控制台的输出可能与实际情况不符。
什么是原型
JS中的对象具有自己的和继承的属性,例如,在以下代码中:
var foo = { bar: 1 };
foo.bar === 1 // true
typeof foo.toString === "function" // true
对象foo具有自己的属性bar和值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 :
- self
- prototype self
- self this
- 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.
- Student Person
- `Student.prototype` `Person`
- `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.
期望一篇文章回答所有问题会很天真。如果您有有趣的问题,对历史的游览,对我所做的一切都做错了的合理或毫无根据的陈述,或者对错误的更正,请在评论中写下。