JavaScript深入浅出__proto__和prototype
作者: SilentLove
首先我们先记住几个知识点:
- 每个函数都有一个
prototype
属性 - 每个对象都有一个
__proto__
属性(null除外) - 函数也是对象
构造函数和实例
首先我们通过下面的例子了解些基本的概念
function Person() { } var person1 = new Person()
- 使用 new 创建对象的函数就是构造函数、创建出的对象就是构造函数的实例对象
- 本例中:Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person1
- 构造函数大写只是约定俗成的习惯,实际上任何可以使用 new 运算符的函数都可以是构造函数
prototype
function Person() { } Person.prototype.name = 'Person' var person1 = new Person() console.log(person1.name) // Person console.log(Person.prototype)
- Person 的
prototype
属性指向的是Person.prototype
的原型对象 - 在这个例子中可以看出,person1 本身并没有 name 属性,访问的其实是 Person 中
prototype
的 name - 从这里可以得出必然有一种关系把
person1
和Person
关联起来,使得person1可以访问到Person中prototype的属性值
带着上面的疑问我们继续下面的例子
__proto__
和prototype
的关系
function Person() { } Person.prototype.name = 'Person' var person1 = new Person() console.log(person1) console.log(person1.__proto__.name === Person.prototype.name) // true console.log(person1.__proto__ === Person.prototype) // true
一开始我们就提到,每个对象都有一个__proto__
属性(null除外),通过这个例子我们发现person1的__proto__属性下有个name属性,正好是Person.prototype.name
的值,由此我们可以看出实例person1是通过__proto__访问的构造函数Person的prototype属性
根据上面的结论,我们很容易得出以下关系图
由此我们很容易得出,多个示例对象之间通过__proto__
进行关联,可以通过__proto__
共享Person.prototype上的属性
constructor
既然构造函数和实例都可以指向原型,那么原型是否有属性指向构造函数或者实例呢? 通过上面的例子,我们发现除了__proto__
,还有一个constructor
属性
function Person() { } Person.prototype.name = 'Person' var person1 = new Person() console.log(Person) // ƒ Person() {} console.log(Person.prototype.constructor) // ƒ Person() {} console.log(person1.__proto__.constructor) // ƒ Person() {} // 由此我们发现`constructor`属性指向的是Person构造函数本身,不难得出以下结论 console.log(Person === Person.prototype.constructor) // true
由此我们可以得出以下关系图:
原型对象的原型
- 原型也是一个对象,一开始就提到,每个对象都有一个
__proto__
属性(null除外),因此原型对象也是有__proto__
的 - 实际上原型对象就是通过 Object 构造函数生成的
var prototypeObj = new Object() console.log(prototypeObj.__proto__ === Object.prototype) // true
到此我们可以得出一个新的关系图
到这里大家可能就有疑惑了,这样不就无限循环了吗,Object.protoType
的__proto__
又是什么呢?
console.log(Object.protoType.__proto__) // null console.log(Object.protoType.__proto__ === null) // true
所以 Object.prototype 为null,属性查找到这里也就结束了
原型链
由上面的例子我们得知,在查找对象的属性时,优先查找实例对象的属性,查找不到时就会通过__proto__
查找 prototype
原型对象的属性,还查不到会通过prototype的__proto__
继续查找,直到Object.protoType.__proto__
为止
图中由__proto__
组成的红色链路就是我们所说的原型链
扩展知识
关于 Object 和 Function
既然函数也是对象,对象都有 __proto__
,那么 Object
和 Function
的 __proto__
属性又是什么呢?
- Object对象是由Function构造函数创建的
- Function的原型对象
Function.prototype
是由Object构造函数创建的 - 【按照原型的定义,可以理解为】Function对象是由Function构造函数本身创建
根据原型链的相关知识,实例对象的 __proto__
指向构造函数的原型对象 prototype
// Object对象由Function构造函数创建 Object.__proto__ === Function.prototype // true // Function的原型对象`Function.prototype`是由Object创建 Function.prototype.__proto__ === Object.prototype // true // Function由Function本身创建(按照原型的定义可以简单这么去理解,这里不做深究) Function.__proto__ === Function.prototype // true Object.getPrototypeOf(Function) === Function.prototype // true
由此我们可以得出最终的关系图:
关于 getPrototypeOf
、isPrototypeOf
、instanceof
function Person() { } var person1 = new Person() // Object.getPrototypeOf(obj) 返回obj实例对象的原型(obj.__proto__) console.log(Object.getPrototypeOf(person1) === Person.prototype) // true // Object.isPrototypeOf(obj),如果obj.__proto__和Object.prototype在一条原型链上(或者理解为Object为obj的构造函数或父级构造函数),则返回true console.log(Object.prototype.isPrototypeOf(person1)) // true console.log(Object.prototype.isPrototypeOf(Person.prototype)) // true console.log(Person.prototype.isPrototypeOf(person1)) // true // (obj instanceof Object) 同isPrototypeOf类似,obj.__proto__和Object.prototype在一条原型链上,则返回true console.log(person1 instanceof Person) // true console.log(person1 instanceof Object) // true
总结
- 每个函数都有一个
prototype
属性,值是一个原型对象 - 每个对象都有一个
__proto__
属性(null除外),指向构造函数的原型prototype
- 构造函数的原型对象的
constructor
指向构造函数本身 - 原型对象是由
Object
构造函数实例化产生的,所以原型对象的__proto__
指向Object的原型对象Object.prototype
Object
构造函数的原型对象为null
function Person() {} var person = new Person() console.log(person.__proto__ === Person.prototype) // true console.log(Person === Person.prototype.constructor) // true console.log(Object.prototype.__proto__ === null) // true // 推导person.constructor等于person.__proto__.constructor等于Person.prototype.constructor console.log(person.constructor === Person.prototype.constructor) // true
到此这篇关于JavaScript深入浅出__proto__和prototype的文章就介绍到这了,更多相关JS proto 和 prototype内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!