JavaScript基础专题之原型与原型链(一)

构造函数建立对象

function Person(){

}
let person1 = new Person()
let person2 = new Person()
person1.name = 'james'
person2.name = 'kobe'

复制代码

咱们经过new来建立一个person实例,咱们能够看到不一样的实例拥有本身的属性。

proto

咱们能够看到每一个对象下都会有__proto__的属性,这个属性会指向该对象的原型数组

function Person(){

}
Person.prototype.name = 'chris'
let person = new Person()
let person1 = new Person()
let person2 = new Person()

person1.name = 'james'
person2.name = 'kobe'
复制代码

咱们看到 __proto__下会出现prototype的name属性,那么 __proto__prototype关系又是什么呢?

prototype

每一个函数都有具备 prototype属性,就是咱们常常在用到的prototypebash

Person.prototype.name = 'chris'
复制代码

那么问题来了,那这个函数的 prototype 属性到底指向的是什么呢?是这个函数的原型吗? 其实,函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而建立的实例的原型,也就是这个例子中的 person1 和 person2 的原型。函数

那原型是什么呢?能够这样理解:每个JavaScript对象(null除外)在建立的时候就会与之关联另外一个对象,这个对象就是咱们所说的原型,每个对象都会从原型所谓的继承属性。post

如图:ui

经过实例的__proto__和构造函数的prototype的对比,咱们不难发现person 和 Person.prototype 的关系spa

person.__proto__ === Person.prototype  //true
复制代码

如图:prototype

既然实例对象和构造函数均可以指向原型,那么原型是否有属性指向构造函数或者实例呢?翻译

constructor

不难发现,每一个构造函数都有 constructor这个属性, 经过控制台咱们会发现constructor 属性指向关联的构造函数code

constructor

指向本身实例.png

这样咱们就了解了构造函数、实例原型、和实例之间的关系,接下来咱们讲讲实例和原型的关系:cdn

实例下的原型

咱们知道若是读取不到实例的属性时,就会查找与对象关联的原型中的属性,若是还查不到,就去找原型的原型,一直找到最顶层为止。

function Person() {

}

Person.prototype.name = 'chris';

var person = new Person();

person.name = 'james';
console.log(person.name) // james 拿到实例的name属性

delete person.name;
console.log(person.name) // chris 拿到原型的name属性
复制代码

可是万一尚未读取到呢?原型下的原型又是什么呢?

原型下的原型

经过上面的知识咱们知道person.__proto__Person.protype相等,那么Person.prototype.__proto__下又是什么呢?很显然就是对象实例的__proto__

function Person(){}
let person = new Person()
let obj = new Object()
Person.prototype.__proto__ === obj.__proto__//true
Person.prototype.__proto__ === Object.prototype//true
obj.__proto__.__proto__ //null
复制代码

let obj = new Object();
obj.__proto__.name = 'chris'
obj.name = 'Kevin'
console.log(obj.name) // Kevin
delete obj.name
console.log(obj.name) // chris
复制代码

原型链

既然咱们知道Object的原型,那 Object.prototype的原型呢?

咱们能够看到返回一个 null,表达的就是已经没有原型了。

最终就是原型和原型链的结构

一些补充

  1. 关于Funtion中的原型 咱们能够会发现Function.prototype有些特殊
Function.prototype === Function.__proto__  //true
复制代码

这样看上去实例的原型和原型的原型是相等的,便是鸡也是蛋。 咱们能够参考MDN关于__proto__的解释:

__proto__的读取器(getter)暴露了一个对象的内部 [[Prototype]] 。对于使用对象字面量建立的对象,这个值是 Object.prototype。对于使用数组字面量建立的对象,这个值是 Array.prototype。对于functions,这个值是Function.prototype。对于使用 new fun 建立的对象,其中fun是由js提供的内建构造器函数之一(ArrayBooleanDateNumberObjectString 等等),这个值老是fun.prototype。对于用js定义的其余js构造器函数建立的对象,这个值就是该构造器函数的prototype属性。

例子

Object.__proto__ === Function.prototype//true
Object.__proto__ === Function.__proto__ //true
复制代码

引用冴羽的理解

至于为何Function.__proto__ === Function.prototype,我认为有两种可能:一是为了保持与其余函数一致,二是就是代表一种关系而已。 简单的说,就是先有的Function,而后实现上把原型指向了Function.prototype,可是咱们不能倒过来推测由于Function.__proto__ === Function.prototype,因此Function调用了本身生成了本身。

总结

  1. 实例对象的__proto__始终指向构造函数的prototype

  2. 只有构造函数才拥有prototype属性,对象(除了null)都拥有__proto__属性

  3. 每个原型对象都有一个constructor属性指向它们的构造函数

  4. 要读取属性时,先读取实例上的属性,读取不到会在原型链上寻找相应属性

  5. 原型链按照__proto__的指向下一级对象

  6. 原型链的尽头始终是null

  7. 构造函数实例化之后,既是构造函数函数,也是对象

function Foo() {

}

const obj = new Foo()


Foo.prototype === obj.__proto__ //true
obj.constructor === Foo //true
Foo.prototype.__proto__ === Object.prototype //true
Object.prototype.__proto__ === null //true
Object.constructor === Function  //true
复制代码

JavaScript基础专题系列

JavaScript基础专题系列目录地址:

JavaScript基础专题之原型与原型链(一)

JavaScript基础专题之执行上下文和执行栈(二)

新手写做,若是有错误或者不严谨的地方,请大伙给予指正。若是这篇文章对你有所帮助或者有所启发,还请给一个赞,鼓励一下做者,在此谢过。

相关文章
相关标签/搜索