JS proto 和 prototype
SilentLove 人气:0首先我们先记住几个知识点:
- 每个函数都有一个
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
加载全部内容