【JS基本】对象继续的定义与完成

简介

类的观点,本身在javascript的言语上是不存在的, 但由于近来人们运用ES6语法,TS言语上都邑有的
class extends 继续的观点, 下面我们须要运用原生js, 连系原型链,完成类的 继续,多态

ES5完成继续

  1. 原型继续
  2. 借用组织函数继续
  3. mixin 复制继续
  4. 寄生继续

原型继续体式格局

原型继续, 重要应用对象的原型链 __proto__, 每个对象都具有__proto__, 它指向的是组织函数的prototype 原型对象.

一个对象的属性或函数的寻觅会阅历以下几个步骤。
以定义 var o = {};, 实行 var toString = o.toString 为例.

  1. 实行 var tmp = o,作为暂时援用 (为了形貌运用)
  2. 尝试搜检 tmp 是不是自定义toString(),假如存在自定义属性则马上实行。假如当前对象无定义该属性, 进入第3步
  3. 尝试搜检 tmp 是不是运用 Object.defineProperty 定义toString 的属性形貌, 假如存在定义,则直接援用,假如不存在则进入第4步
  4. 尝试搜检 tmp 是不是存在 __proto__,假如存在,则将tmp = o.__proto__, 实行第2步; 假如不存在,则返回 undefined, 属性查找完毕;

详细案例

function Animal () {
  throw new Error('抽象类, 不允许直接实例化');
}
Animal.prototype.voice = function () {
  console.log('the ' + this.name + ' sound');
}

function Dog () {
  this.name = 'dog';
}
Dog.prototype = Object.create(Animal.prototype);

// 显现指向
Dog.prototype.constructor = Dog;

var dog = new Dog();

dog.voice(); // the dog sound
console.log(dog instanceof Dog);
console.log(dog instanceof Animal);

// 隐世指向 Animal.prototype.constructor
console.log(dog.__proto__.constructor === Animal);

长处:

  1. 可以运用 instanceof 检测是不是是某一个父类
  2. 原型链完成体式格局

瑕玷:

  1. 没法借用父类组织函数

借用组织函数

// 模仿挪用父类函数
Object.prototype.super = function (proto, name) {
  var args = Array.from(arguments).slice(1);
  var proto = proto.__proto__;
  while (proto && null == proto[name]) {
    proto = proto[name];
  }
  if (proto && typeof proto[name] === 'function') {
    return proto[name].apply(this, args);
  }
  console.warn('the instance have not super ' + name + ' function');
};
function Animal (name) {
  this.name = name;
}

Animal.prototype.voice = function () {
  console.log(this.name + ' sound');
};

function Dog (name, type) {
  Animal.apply(this, [name]);
  this.type = type;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Animal;

Dog.prototype.voice = function () {
  console.log('the dog type is ' + this.type);
  this.super(Animal.prototype, 'voice');
};

var dog = new Dog('二哈', '哈士奇');
dog.voice();
// the dog type is 哈士奇
// 二哈 sound

长处:

  1. 可以借用父类组织函数
  2. 具有链式挪用函数

瑕玷:

  1. 子类组织函数须要挪用父类组织函数

mixin复制继续

依托对象拷贝属性的体式格局, 赋予一个源对象未有的属性赋值


function mixin(source, target) {
  for (var name in target) {
    if (!source[name]) {
      source[name] = target[name];
    }
  }
  return source;
}

var Animal = {
  name: 'animal',
  voice: function () {
    console.log('the name is ' , this.name);
    console.log('voice~~');
  }
};
var Cat = mixin({
  name: 'cat',  
  sound: function () {
    return this.voice();
  }
}, Animal);

var helloKitty = mixin({
  name: 'hello keitty'
}, Cat);

helloKitty.sound();

长处:

  1. 完成简朴,只须要举行复制属性和要领

瑕玷:

  1. 处置惩罚对象都为对象, 没有处置惩罚组织函数
  2. 没法完成子类挪用父类的场景

寄生继续

寄生继续属于重写, 新增父类建立的对象的属性, 返回扩大的对象

function Animal() {
  this.speed = 10;
}

Animal.prototype.run = function () {
  console.log('speed is ' + this.speed);
}

function Cat () {
  var animal = new Animal();
  var runFn = animal.run;

  animal.speed = 20;  
  animal.run = function () {
    console.log('the cat will run');
    runFn.apply(this, arguments);
  };
  return animal;
}
var cat = new Cat();
console.log(cat instanceof Cat);

长处:

  1. 连系原型属性和实例属性完成计划

瑕玷:

  1. 没法同享属性, 每个新的对象都建立新的实例属性和要领

Object.create

Object.create 是ES5定义的要领, 比拟于字面量对象,组织函数对象, 又一种新的建立对象的体式格局。

var prototype = {foo: 1};
var o = Object.create(prototype);
console.log(o.foo); // 1
o.foo = 100;
console.log(o.foo); // 100
delete o.foo;
console.log(o.foo); // 1
console.log(o.__proto__ === prototype); // true

从上面可以瞥见, Object.create 传入一个对象,同时会返回一个新的对象,而这个新的对象的__proto__指向传入对象

Object.create(null)

返回一个无原型链的空对象, 对象的一切属性均为实例属性

Object.create 的 polyfill

// 简化版 polyfill
Object.create = Object.create || function (proto) {
  function F() {}
  F.prototype = proto;
  return new F();
};

ES6 的 class extends

说完ES5的完成体式格局,我们来聊聊ES6自带的语法。 classclass extends

ES6里的类

参照别的言语,如 java, 类中存在静态属性, 静态要领, 实例属性,实例要领.

声明一个类

class Rectangle {
  // 类的组织函数
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
let rect = new Reactangle(320, 240);
console.log(rect.height, rect.width);

注重: 类不存在声明提早的观点,必须先定义后运用

运用 extends 建立子类

class Animal { 

  constructor(name) {
    // 实例属性
    this.name = name;
  }
  // 原型属性形貌
  get fullname () {
    console.log(this.name);
  }

  // 原型要领
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

// 静态属性
Animal.name = 'Animal';

class Dog extends Animal {
  construcotr(name) {
    // 挪用父类组织函数
    super(name);
  }
  speak() {
    console.log(this.name + ' barks.');
  }
  // 静态要领只合适建立东西函数
  // 返回 undefined
  static eat() {
    return this;
  }
}

var d = new Dog('Mitzie');
// 'Mitzie barks.'
d.speak();

实际上ES6的classclass extends 也是运用的原型链体式格局完成继续关联。 super 是一个关键词, 实际上是指向父类的prototype, 在constructor 运用super(), 可以挪用父类的组织函数, 运用super.method() 可以挪用父类的原型要领
原型属性采纳ES5的defineProperty定义属性形貌来完成。

小结

现在JS的运用场景愈来愈广, 面向对象编程的运用也愈来愈多, 前端已Node.js都有须要用到类与继续。 同时这也是多年来稳定的前端JS考题。

相干学问引荐

    原文作者:wayneli
    原文地址: https://segmentfault.com/a/1190000014212372
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞