JavaScript 面向对象(二)

103 阅读3分钟

通过构造函数创建对象

前面讲过,创建对象主要有两种方式,一种是通过字面量的方式来创建对象,另一种是通过构造函数的方式。这里我们讲一下通过构造函数创建对象

构造函数并不是一种特殊的函数,而是使用 new 关键字调用普通函数则叫构造函数,

构造函数操作逻辑

使用 new 调用构造函数的操作逻辑如下:

  • 在内存中创建一个新对象
  • 这个新对象内部的[[Prototype]]特性被赋值为构造函数的 prototype 属性
  • 构造哈数内部的 this 被赋值为这个新对象(即 this 指向新对象)
  • 执行构造函数内部的代码(给新对象添加属性)
  • 如果构造函数返回非空对象,则返回该对象,否则,返回刚创建的新对象

例子

function Person(name) {
  this.name = name;
}

Person.prototype.sayName = function () {
  console.log('我的名字叫: ' + this.name);
}

var a = new Person('knight');
a;
a.sayName();

image1.png

在上面的的例子中,我们声明了一个 Person() ,并在其原型上添加 sayName() , 然后通过 new 实例化对象并赋值给 a

我们之所以将 sayName() 添加在 Person 的原型上,是为了重用这个方法

继承

JavaScript 中继承主要是通过原型链来实现的,其基本思想是通过原型继承多个引用类型的属性和方法。

组合继承

组合继承的基本思路是使用原型链继承原型上的属性和方法,而通过调用父类构造函数继承实例属性。

function SuperType(name) {
  this.name = name;
}

SuperType.prototype.sayName = function () {
  console.log('我的名字叫: ' + this.name);
}

function SubType(name, age) {
  SuperType.call(this, name)
  this.age = age;
}

SubType.prototype = new SuperType();
SubType.prototype.sayAge = function () {
  console.log('我的年龄是: ' + this.age);
}

var a = new SubType('knigt', 18);
a;
a.sayName();
a.sayAge();

image2.png

但是这种方式的主要问题是实例化了两次父类,造成了效率问题,并且原型因为是实例化的父类,所以有多余的属性。

寄生式继承

寄生式继承背后的思路类似于寄生构造器函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。

function createAnother(obj) {
  let clone = Object.create(obj);
  clone.sayHi = function () {
    console.log('Hi');
  } 
  return clone
}

let obj = {
  name: 'knight',
}
var a = createAnother(obj);
a;
a.sayHi();

image3.png

这种方式适合主要关注对象,不在乎类型和构造函数的场景,且在工厂方法中给对对象添加方法使工厂函数难以复用。

寄生式组合继承

寄生式组合继承糅合了寄生式继承和组合式继承的优点,

function inheritPrototype(subType, superType) {
  let prototype = Object.create(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

function SuperType(name) {
  this.name = name;
}

SuperType.prototype.sayName = function () {
  console.log('我的名字叫: ' + this.name);
}

function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;
}

inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function () {
  console.log('我的年龄是: ' + this.age);
}

var a = new SubType('knigt', 18);
a;
a.sayName();
a.sayAge();

image4.png

Object.create()

Object.create() 可传入两个参数,第一个参数作为新对象原型的对象,第二个参数传入属性描述符,给新对象定义额外属性的对象(第二个可选)

function SuperType(name) {
  this.name = name;
}

var obj = new SuperType('knight');

var a = Object.create(obj, {age: {value: 18}});
a;

image5.png