JavaScript的原型链算是JS比较难的一个点了。断断续续学习了一段时间,进过自己的思考,好像总结了一套自己的理解。
原型链总图:
Js是通过对象创建对象,所以每个对象都有它的对象原型。
一、函数对象:
function Person() {
}
let UserMan = new Function();
Person和UserMan都是函数对象,他们的proto都指向函数原型对象。
console.log(UserMan.proto==Person.proto) //true
二、数组对象
let arr = new Array();
arr为数组对象,它的proto都指向数组原型对象。
三、简单对象(可理解为字典或结构体)
1、通过Object创建对象
let obj = new Object();
obj为简单对象
console.log(obj.proto=={}.proto) //true
2、直接字面量创建对象
let user = {
name : 'han',
introduce : function(){ console.log(this.name); }
};
user为简单对象
console.log(user.proto=={}.proto) //true
简单对象没有特定的原型对象,它的proto直接指向顶层原型对象了。
3、通过Object.create创建对象
let maleUser = Object.create(user);
maleUser.__proto__ —> user
let person = {name:"alex",age:"19"};
let man = Object.create(person);
man.name = "johnny";
console.log(man.name); //johnny
console.log(man.__proto__.name); //Alex
以user作为原型,创建一个对象。
通过Object.create创建的对象,就相当于copy了一份原型对象。
4、通过函数对象创建对象
function Person() {
}
let person = new Person();
四、prototype
理顺了上面各种对象后,下面开始引入prototype属性。它是函数对象特有的一个属性。
为什么函数对象需要这样一个属性呢?
我们通过Person函数对象创建一个对象person
let person = new Person();
person.name = “abc”;
这里的person明显就是简单对象,就是说这里通过了函数对象创建出来了简单对象。我们知道,每个对象肯定有原型,那person的原型是什么呢,肯定不是创建它的函数对象,所以函数对象里面必须有一个属性存储创建的对象的原型。这里就通过prototype属性来存储创建对象的原型。
console.log(person.proto.proto=={}.proto) //true
回看上面的以user作为原型,创建一个对象。
那么person应该是以{}作为原型,创建的一个对象。
相当于:
let per = {};
let person = Object.create(per);
person.__proto__ —> per
拓展
更泛的理解是,通过new方式创建对象的函数对象或包装类,都是用prototype存储其对象真正的原型。
Function函数构造器new出来的是函数对象,所以它的Function.prototype值为函数原型对象
console.log(Function.prototype==Person.proto) //true
Array函数构造器new出来的是数组对象,所有其Array.prototype值为数组原型对象
console.log(Array.prototype==[].proto) //true
Object函数构造器new出来的是简单对象,所有其Object.prototype值为简单原型对象
console.log(Object.prototype=={}.proto) //true