原型和原型链


构造函数创建对象

function Person(){

}
var person = new Person();
person.name = 'Kevin';
console.log(person.name);//Kevin

Person是个构造函数,使用new创建了一个实例对象person.

prototype

每个函数都有一个prototype属性,也是函数才有的属性

function Person(){

}
Person.prototype.name='Kevin'
var person1=new Person()
var person2=new Person()
console.log(person1.name)//Kevin
console.log(person2.name)//Kevin

函数的prototype属性指向的是一个对象,这个对象时调用该构造函数而创建的实例的原型,也就是例子中的person1person2的原型。

https://pics.images.ac.cn/image/5f2245bf9c241.html

__proto__

这是每一个JavaScript对象(除了null)都具有的一个属性,它指向该对象的原型。

function Person(){

}
var person=new Person()
console.log(person.__proto__===Person.prototype)

https://pics.images.ac.cn/image/5f22459171f27.html

constructor

这是原型指向构造函数的属性,每一个原型都有一个constructor属性指向关联的构造函数。

function Person(){

}
console.log(Person===Person.prototype.constructor)//true

https://pics.images.ac.cn/image/5f2245663030a.html

总结

function Person() {

}

var person = new Person();

console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
// 顺便学习一个ES5的方法,可以获得对象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true

实例和原型

当读取实例对象中的属性,读取不到时就回去查找实例对象的原型中的属性,如果还是没找到就会去原型的原型中找,直到找到顶层为止

function Person() {

}

Person.prototype.name = 'Kevin';

var person = new Person();

person.name = 'Daisy';
console.log(person.name) // Daisy

delete person.name;
console.log(person.name) // Kevin

原型的原型

原型也是一个对象,既然是对象就用原始的方法创建它

var obj = new Object();
obj.name = 'Kevin'
console.log(obj.name) // Kevin

其实原型对象就是由Object构造函数生成的

https://pics.images.ac.cn/image/5f22451b737a7.html

原型链

Object.prototype的原型是null,也就是没有原型,所以查找到Object.prototype就可以停止查找了

console.log(Object.prototype.__proto__ === null) // true

https://pics.images.ac.cn/image/5f2244c7b8b8c.html

图中由相互关联的原型组成的链状结构就是原型链,也就是__proto__蓝色的一条线

补充

最后,补充三点大家可能不会注意的地方:

constructor

function Person() {

}
var person = new Person();
console.log(person.constructor === Person); // true

当获取 person.constructor 时,其实 person中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === Person.prototype.constructor

__proto__

绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype中,实际上,它是来自于Object.prototype,与其说是一个属性,不如说是一个getter/setter,当使用 obj.__proto__ 时,可以理解成返回了Object.getPrototypeOf(obj)

真的是继承吗?

最后是关于继承,前面我们讲到“每一个对象都会从原型‘继承’属性”,实际上,继承是一个十分具有迷惑性的说法,引用《你不知道的JavaScript》中的话,就是:

继承意味着复制操作,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。


文章作者: XiaoQi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 XiaoQi !
 上一篇
this全面解析 this全面解析
this 关键字是 JavaScript 中最复杂的机制之一。它是一个很特别的关键字,被自动定义在 所有函数的作用域中。但是即使是非常有经验的 JavaScript 开发者也很难说清它到底指向 什么。 实际上,JavaScript 中 t
2020-07-31
下一篇 
git常用命令 git常用命令
git常用命令git是一个版本管理系统VCS,它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点将更新记录恢复回来。 git工作流程工作目录 被git管理的项目目录 暂存区 临时存放被修改文件 git仓库 用于存放
2020-06-25
  目录