原型和原型链

  一直以来,对于原型和原型链一直都是处于明白但是讲不清楚地情况,所以准备写篇博客梳理下

  在使用JavaScript这门语言时,我们经常会看到构造函数,原型、原型链、prototype、__proto__ 等等词汇,对于有些新手JavaScript开发者会感觉很疑惑。

  JavaScript是一门面向对象的语言,但是在es6的class出来之前,我们一直都是用构造函数来实例化对象。

function Cat() {
    this.color = 'orange'
}

var cat = new Cat()
console.log(cat.color)     // orange

  prototype
  每个函数都有一个prototype属性,它的值是一个对象

function Cat() {
    this.color = 'orange'
}

console.log(Cat.prototype)

  控制台打印

  __proto__

  在 JavaScript 中,每个实例对象都有一个私有属性 [[Prototype]],该属性指向了这个实例对象的原型,你可以通过 ES6 的 Object.getPrototypeOf() 来访问该属性,许多浏览器也对 [[Prototype]] 进行了实现,也就是我们经常见到的 __proto__,__proto__ 指向了实例对象的原型,它也是一个对象。

function Cat() {
    this.color = 'orange'
}

var cat = new Cat()
console.log(cat.__proto__)
console.log(Object.getPrototypeOf(cat) === cat.__proto__)  // true

  控制台打印

  实例对象的 __proto__ 与创建该实例对象的构造函数的 prototype 是相等的,构造函数的 prototype 指向调用该构造函数而创建的实例对象的原型

function Cat() {
    this.color = 'orange'
}

var cat = new Cat()

console.log(cat.__proto__ === Cat.prototype)   // true

  对于构造函数的 prototype 和实例对象的 __proto__ 的关系,我们用张图来展示下

 

  constructor

  每个原型对象都有一个 constructor 属性,指向相关联的构造函数,所以构造函数和构造函数的 prototype 是可以相互指向的。实例对象也可以访问constructor 属性指向其构造函数。

 

  

  原型链

function Cat() {
    this.color = 'orange'
}

Cat.prototype.age = 4

var cat = new Cat()

console.log(cat.color)    // orange
console.log(cat.age)      // 4

  在构造函数中,我并没有设置有关 age 的属性,只是把 age 设置在了实例原型上,然后我们通过实例对象也能访问到 age 属性。在 JavaScript 中,如果想访问某个属性,首先会在实例对象(cat)的内部寻找,如果没找到,就会在该对象的原型(cat.__proto__,即 Cat.prototype)上找,我们知道,对象的原型也是对象,它也有原型,如果在对象的原型上也没有找到目标属性,则会在对象的原型的原型(Cat.prototype.__proto__)上寻找,以此内推,直到找到这个属性或者到达了最顶层。在原型上一层一层寻找,这便就是原型链了。

 

  实例对象原型的原型是Object.prototype,而它的原型是null,null 没有原型,所以 Object.prototype 就是原型链的最顶端。

function Cat() {
    this.color = 'orange'
}

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

  JavaScript 中的所有对象都来自 Object,Object 位于原型链的最顶端,几乎所有 JavaScript 的实例对象都是基于 Object。

 

  

  继承

  javaScript 的继承是基于原型链的,在原型链的任何位置设置属性,都能被对象访问到,原型的作用也是在此,它可以包含所有实例共享的属性和方法,就像该属性本来就在实例对象上一样。

 

function Cat() {
    this.color = 'orange'
    this.age = 4
}

Cat.prototype.getColor = function() {
    console.log(this.color)
}

Object.prototype.getAge = function() {
    console.log(this.age)
}

var cat = new Cat()

cat.getColor()       // orange
cat.getAge()

var a = ['hello', 'world']
function f() {}

console.log(a.__proto__ === Array.prototype)      // true
console.log(f.__proto__ === Function.prototype)   // true

参考:https://www.yuque.com/fe9/basic/zk5e4f

posted @ 2019-06-24 21:17  张石磊博客  阅读(577)  评论(0)    收藏  举报