构造函数、原型、原型链、继承

102 阅读3分钟

与大部分面向对象语言不同,ES6之前中并没有引入类(class)的概念,JavaScript并非通过类而是直接通过构造函数来创建实例。在介绍原型和原型链之前,我们有必要先复习一下构造函数的知识。

构造函数:

构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。另外就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。 这里说下当我们在使用new 调用一个构造函数的时候执行了哪些步骤:(面试经常问)

  1. 1.会在内存中创建一个新的对象(空对象);
  2. 2.会将这个构造函数的显示原型(prototype)赋值给这个对象的隐式原型(proto);
  3. 3.构造函数内部的this会指向通过new创建出来的对象,将这个对象赋值到this;
  4. 4.执行函数内部代码体;
  5. 5.如果构造函数没有返回空对象,那么会默认返回新创建出来的这个对象。
function Person(name, age, height) {
  this.name = name
  this.age = age
  this.height = height
  this.eating = function() {
    console.log(this.name + '在吃饭~')
  }
}

const p = new Person('小方', 18, 1.88)
console.log(p) // Person { name: '小方', age: 18, height: 1.88 }
p.eating()

每创建一个Person构造函数,在Person构造函数中,为每一个对象都添加了一个sayName方法,也就是说构造函数每执行一次就会创建一个新的sayName方法。这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的,为什么不把这个方法单独放到一个地方,并让所有的实例都可以访问到呢?这就需要原型(prototype)

原型

在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。在我们js中万物皆对象,对象都会有自己的__proto__属性,Object是null

WechatIMG405.png

原型链

当我们在一个对象上查找一个属性的时候,它会沿着对象上的原型层层查找的,每一个对象上 都有一个原型对象(proto),直到原型顶部为null为止,这样原型层层连接起来,就构成了原 型链,如果能看懂这副图,那么已经完全弄懂了原型、原型链了。

WechatIMG406.png

下面我们来实现下构造函数的继承(在我们ES6之前)ES6之后有了class extend来继承,但是通过babel转换成ES5 的代码其实还是通过一下的逻辑来实现继承的:

// 这个方法其实就是Object.create()是一样的,这里我们自己封装个了一个这个方法
// 传入一个对象,在返回一个对象,让传入的这个对象是返回的这个对象的隐式原型
function createObject(o){
  function Fn() {}
  Fn.prototype = o
  return new Fn()
}
function inheritProtoType(subType, supType) {
  subType.prototype = createObject(supType.prototype)
  Object.defineProperty(subType, 'constructor', {
    configurable: true,
    writable: true,
    enumerable: false,
    value: subType
  })
}
function Person(name, age, height) {
  this.name = name
  this.age = age
  this.height = height
}
Person.prototype.eating = function() {
  console.log(this.name + '在吃东西~')
}
function Student(name, age, height, sno) {
  Person.call(this, name, age, height) 
  this.sno = sno
}
// 这一步很关键,调用的地方也有讲究,
inheritProtoType(Student,Person)

Student.prototype.studying = function() {
  console.log(this.name + '在学习~')
}
const s1 = new Student('lisi', 18, 1.88, 111)
console.log(s1)

这种方式我们也称之为寄生组合式继承。写得不好希望大家多多指教