简介
类的观点,本身在javascript的言语上是不存在的, 但由于近来人们运用ES6语法,TS言语上都邑有的
class extends
继续的观点, 下面我们须要运用原生js, 连系原型链,完成类的 继续,多态
ES5完成继续
- 原型继续
- 借用组织函数继续
- mixin 复制继续
- 寄生继续
原型继续体式格局
原型继续, 重要应用对象的原型链 __proto__
, 每个对象都具有__proto__
, 它指向的是组织函数的prototype
原型对象.
一个对象的属性或函数的寻觅会阅历以下几个步骤。
以定义 var o = {};
, 实行 var toString = o.toString
为例.
- 实行
var tmp = o
,作为暂时援用 (为了形貌运用) - 尝试搜检
tmp
是不是自定义toString()
,假如存在自定义属性则马上实行。假如当前对象无定义该属性, 进入第3步 - 尝试搜检
tmp
是不是运用Object.defineProperty
定义toString
的属性形貌, 假如存在定义,则直接援用,假如不存在则进入第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);
长处:
- 可以运用 instanceof 检测是不是是某一个父类
- 原型链完成体式格局
瑕玷:
- 没法借用父类组织函数
借用组织函数
// 模仿挪用父类函数
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
长处:
- 可以借用父类组织函数
- 具有链式挪用函数
瑕玷:
- 子类组织函数须要挪用父类组织函数
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();
长处:
- 完成简朴,只须要举行复制属性和要领
瑕玷:
- 处置惩罚对象都为对象, 没有处置惩罚组织函数
- 没法完成子类挪用父类的场景
寄生继续
寄生继续属于重写, 新增父类建立的对象的属性, 返回扩大的对象
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);
长处:
- 连系原型属性和实例属性完成计划
瑕玷:
- 没法同享属性, 每个新的对象都建立新的实例属性和要领
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自带的语法。 class
与 class 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的class
与 class extends
也是运用的原型链体式格局完成继续关联。 super
是一个关键词, 实际上是指向父类的prototype
, 在constructor
运用super()
, 可以挪用父类的组织函数, 运用super.method()
可以挪用父类的原型要领
。
原型属性采纳ES5的defineProperty
定义属性形貌来完成。
小结
现在JS的运用场景愈来愈广, 面向对象编程的运用也愈来愈多, 前端已Node.js都有须要用到类与继续。 同时这也是多年来稳定的前端JS考题。