前段时间看了一遍文章:JavaScript深入之从原型到原型链,感觉通俗易懂,为了加深印象,自己手敲一遍也便于以后复习。
构造函数创建对象
function Person() {}
let person = new Person();
person.name = 'Cheese';
console.log(person.name)
Person是一个构造函数,我们new了一个实例对象person
prototype : 函数才有的属性
每个函数都有一个prototype属性,举个例子:
function Person() {}
Person.prototype.name = 'Cheese';
let person1 = new Person();
let person2 = new Person();
console.log(person1.name)
console.log(person2.name)
问题 函数Person的prototype属性的指向是什么?是函数的原型吗?
答 函数的prototype属性指向了一个对象,这个对象就是调用该构造函数而创建的实例的原型,也就是person1,person2的原型。
问题 什么是原型?
答 每一个JavaScript对象(null除外)在创建的时候就与之关联的另一个对象,这个对象就是我们说的原型,每一个对象都会从原型继承属性。
画个图来表示构造函数和原型之间的关系更直观一些:
图中 Object.prototype 表示实例原型
__proto__ : 每个 javaScript 对象(null除外)都具有的一个属性
通过之前讲到的 Object.prototype 实例原型我们知道了构造函数和原型之间的关系,接下来就要看看实例和实例原型之间的关系,因此我们要知道__proto__属性,这是javaScript(null除外)对象都具有的一个属性,这个属性会指向该对象的原型。
在控制台输出一下: person.__proto__ === Person.prototype,结果为true
function Person() {}
let person = new Person();
console.log(person.__proto__ === Person.prototype);
于是我们就知道了:
到这里我们就知道了构造函数,原型,实例,实例原型之间的关系。
constructor
通过上面的关系图我们知道实例和构造函数都可以指向原型,那原型是否可以指向实例和构造函数呢?
由于一个构造函数可以生成多个实例,所以原型不能指向实例,但是可以通过constructor 指向构造函数。
依旧在控制台输出:
function Person() {}
console.log(Person === Person.prototype.constructor);
于是我们又可以完善上面的关系图了:
总结
function Person() {}
var person = new Person();
console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
实例和原型
当读取实例的属性时,如果找不到就回查找与之关联的原型中的属性,如果还是找不到就去找原型的原型,一直找到最顶层。
同样在控制台举个例子:
function Person() {}
Person.prototype.name = 'Cheese';
let person = new Person();
person.name = 'Cheese_Q';
console.log(person.name)
delete person.name;
console.log(person.name)
我们给实例对象person添加了name属性,打印person.name时自然就是我们添加的属性,name的值为Cheese_Q,而当我们删除了我们添加的name属性再读取person.name时,从person实例中找不到name属性,就会从person的原型,也就是person.__proto__,实例原型Person.prototype中找,于是就找到了属性name。
原型的原型
原型也是一个对象,既然是一个对象我们就是了new一个,其实原型就是通过Object构造函数生成的
let obj = new Object();
obj.name = 'Cheese'
console.log(obj.name)
于是:
原型链
在上图的基础上,继续深挖,Object.protype的原型又是什么呢?
打印试试:
console.log(Object.prototype.__proto__)
null表示“没有对象”,也就是说Object.protype没有原型
致此这张关系图就画完了,由相互关联的原型组成的链状结构就是原型链。也就是红色的这条线: