什么是原型?什么是原型链?
以下面的代码为例子
function Person() {
}
Person.prototype.name = 'KK';
var person1 = new Person()
var person2 = new Person()
console.log(person1.name) //kk
console.log(person2.name) //kk
console.log(Person === Person.prototype) //false
console.log(Person.prototype.constructor === Person) //true
console.log(person1._proto_ === Person.prototype) //false
console.log(person1 === Person.prototype)//false
当创建一个函数(除了bind函数外)时,这个函数就包含了一个prototype的属性,它指向由该构造函数创建的实例的原型(指向实例的原型,Person指向Person.prototype)。
当创建一个对象(除了null)时(每一个对象都会与之相关的原型对象相关联),这个对象会包含一个_proto_的属性,它指向对象的原型(或者叫实例的属性)(person1、person2都指向Person.prototype)。
对象的原型(Person.prototype)也是一个对象,它内部包含一个constructor属性,这个属性指向构造函数(Person)。既然原型是对象,也可以通过Object(所有对象都继承自Object类)来创建:
var obj = new Object()
obj.name="yy"
console.log(obj.name) //yy
此时实例obj的原型对象是通过Object的构造函数创建的。
回到Person构造函数,分别打印最上面例子的Person.prototype、Person.prototype.constructor、person1._proto_、person1.constructor、Person、Person.constructor的值分别为:
Person.prototype和person1._proto_:
一个对象里面包含:constructor为Person函数的属性、_proto_为Object的对象。
Person.prototype.constructor和person1.constructor、Person:
一个函数:值为Person函数。
Person.constructor:
一个函数:值为Function函数。
如图打印的结果:
Person.prototype:
Person.prototype.constructor:
person1._proto_:
person1.constructor、Person.constructor、Person:
可以看到Person.prototype里面不仅仅包含了指向Person构造函数的constructor属性,还包含了一个指向Object对象的对象_proto_。Js中所有的对象(Array、Function、Date等等)都是基于Object创建(函数也是一个对象),都是Object的实例,所以对象中的_proto_必定指向Object构造函数创建的实例的原型(Object.prototype,或者说Object类型的原型对象)。
对象上的_proto_与_proto_属性构成了原型链。
Object是最顶层的一层对象,其原型上没有对象,即Object.prototype的指向为Null。
构造函数/Object/原型/实例与Function的关系?
当打印Person时,打印的是 function Person() {},我们知道,函数名只是函数的一个引用。
函数也是一个对象,那么通过这个对象就能读取到constrctor的属性。
当打印Person.constructor时,打印的是Function() {}。可以知道function Person() {}是构造函数Function的实例。
那么就应该有Person.constrctor等于Function:
function Person() {
}
console.log(
Function.prototype , Person.constructor,
Function, Function.constructor,
Function.prototype.constructor
)
//ƒ () { [native code] } ƒ Function() { [native code] }
//ƒ Function() { [native code] } ƒ Function() { [native code] }
//ƒ Function() { [native code] }
console.log(Person.constructor === Function) //true
console.log(Person.constructor === Function.constructor)//true
Function、Object、实例、原型、构造函数之间的关系,看如下图:
这里有一个关于Function很关键的两个点:
- 一个函数实例是一个构造函数,也是一个对象,这个对象包含一个指向Function原型对象的属性_proto_。
- 所有类型都继承至Object,包括函数类型,所以Function的原型对象上包含一个指向Object原型对象的属性_proto_。
Object.create创建对象原型
一般创建一个新对象时会采用Object.create(null)来创建一个原型对象为null的对象,这样的对象更安全。
Object.create是用来创建以特定对象为原型对象的新对象,例如:
const person = {
isHuman: false,
nameObject: {
name: 'yy',
age: 12
},
printIntroduction: function () {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
me.name = "Matthew"; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction();
me.nameObject.name = "beier"
console.log(me)
结果:
而person的值
利用Object.create来实现继承:
// Shape - 父类(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父类的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子类(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
更多:
Proxy实例也可以作为其他对象的原型
var proxy = new Proxy({}, {
get: function(target, propKey) {
return 35;
}
});
let obj = Object.create(proxy);
obj.time // 35
总结
原型,即一个包含了指向构造函数的constrctor属性,及该函数的实例都具备的公共属性的对象。
原型链,即对象的原型指向另外一个对象的原型,这样的原型与原型之间构成的链就是原型链。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。