原型链和继承

2018-08-15  本文已影响0人  苦瓜_6

类、 prototype__proto__、实例、constructor之间的关联

1. prototype 和 constructor

我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。
在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向 prototype属性所在函数的指针。

对于构造函数来说,生成实例的时候,这个原型对象prototype 会自动成为实例对象的原型

2. __proto__

每个实例对象(object )都有一个私有属性(称之为 proto)指向它的原型对象(prototype)。

图片来自MDN.png
function Cat(name){
    this.name = name;
}
Cat.prototype.sayName = function(){
    console.log('My name is :' + this.name);
}
var cat1 = new Cat('Munchkin')
cat1.sayName();
Cat.prototype.constructor === Cat // true
Cat.prototype === cat1.__proto__  // true
cat1.__proto__.constructor === Cat.prototype.constructor // true
image.png

原型链

JavaScript 规定,每个函数都有一个 prototype 属性,该属性指向一个对象。
对于构造函数来说,生成实例的时候,这个原型对象prototype 会自动成为实例对象的原型
每个实例对象(object )都有一个私有属性(称之为 __proto__)指向它的原型对象(prototype)。
该原型对象也有一个自己的原型对象 ,层层向上直到一个对象的原型对象为 null,这就形成了一个“原型链”。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

所有对象的原型都可以最终追溯到 Object.prototype,即Object构造函数的prototype属性。
原型链的尽头是null , null 没有任何属性和方法,也没有自己的原型。

一点点补充: 函数与对象的恩怨

所以:

Function.__proto__.__proto__ === Object.prototype  // true
 Object.__proto__ === Function.prototype // true

与原型和原型链相关的一些方法

instanceof

1. 作用
instanceof 运算符返回一个布尔值,表示对象是否为某个构造函数的实例。

2. 使用方法
实例对象 instanceof 构造函数

3. 原理
它会检查右边构造函数的原型对象(prototype),是否在左边实例对象的原型链上。
大概就是这样子:

function _instanceof(obj,Fn) {
 if(obj.__proto__){
    if(obj.__proto__ === Fn.prototype) {
    return true
  } else {
    return _instanceof(obj.__proto__,Fn)
  }
 } else {
   return false
 }
}

let arr = [];

_instanceof(arr, Array ); // true
_instanceof(arr, Object ); // true

3. tips

Object.create(null) instanceof Object // false
Object.create()

Object.create(proto, [propertiesObject])

Object.create()方法创建一个拥有指定原型和若干个指定属性的对象。

如果想生成一个不继承任何属性的对象,可以将Object.create() 的参数设为 null

hasOwnProperty

obj.hasOwnProperty(prop)

实例对象的 hasOwnProperty 方法返回一个布尔值,用于判断某个属性定义在对象自身还是定义在原型链上。

eg.

({}).hasOwnProperty('toString')    //  false

hasOwnProperty 方法使JavaScript 中唯一一个处理对象属性时,不会遍历原型链的方法。


继承

extends 关键字实现继承
  class Animal {
    constructor() {
      this.body = '肉体'
    }
    eat() {
      console.log('eat')
    }
  }
  class Human extends Animal {
    constructor(name) {
      super() // 子类中存在构造函数的话,则需要在使用“this”之前首先调用 super()
      this.name = name
    }
    cook() {
      console.log('cook')
    }
  }
  var p1 = new Human('xx')
原型链实现继承
使用Object.create()
function Animal() {
  this.body = 'body'
}
Animal.prototype.eat = function () {
  console.log('eat')
}

function Human(name) {
  Animal.call(this)
  this.name = name
}

Human.prototype = Object.create(Animal.prototype);
Human.prototype.constructor = Human; // 这一步不能省! 修改原型对象的同时,也要记得修改constructor属性的指向!
Human.prototype.cook = function () {
  console.log('cook')
}

var p1 = new Human('xx')
p1.__proto__.constructor === Human // true
不使用Object.create()
function Animal() {
  this.body = 'body'
}
Animal.prototype.eat = function () {
  console.log('eat')
}

function Human(name) {
  Animal.call(this)
  this.name = name
}

// Human.prototype.__proto__ = Animal.prototype // 非法,用下面三句话代替
var F = function() {}
F.prototype = Animal.prototype;
Human.prototype = new F()

Human.prototype.constructor = Human; // 这一步不能省! 修改原型对象的同时,也要记得修改constructor属性的指向!
Human.prototype.cook = function () {
  console.log('cook')
}

var p1 = new Human('xx')
上一篇下一篇

猜你喜欢

热点阅读