@bornkiller
2015-05-27T14:27:16.000000Z
字数 2937
阅读 2931
javascript
高级语言基本上都有类的概念,而javascript
因为各种原因相对比较特别,并没有明确的class
类声明方式(ES6),而是通过构造函数变相实现。推荐《javascript高级程序设计》,对类继承有详细介绍。书中涉及继承方式多达数种,意味着继承的灵活性。但灵活性,有时也意味着复杂性。总结来说,继承方案本文介绍即可覆盖大部分场景。
javascript
的世界,可以认为变量(原始类型[1],引用类型)皆对象[2]。当声明一个普通变量,即可调用多种方法。
love = ['one', 'two', 'three']
["one", "two", "three"]
love.slice(1,2)
["two"]
Object.keys(love)
["0", "1", "2"]
这里声明一个数组,即可调用slice
方法。既然未手工定义slice
方法,为么能够使用,就需要需要提到原型继承。
对象可访问变量由两部分构成,属性和原型对象。属性优先级高于原型对象,如上所述,love
数组的可枚举属性为"0", "1", "2",当调用slice
方法时,会先在属性里面寻找slice
键对应的值,此例中显然不存在。未找到,则到_proto_
指针指向的原型对象中寻找。love
变量指向的原型对象即为Array.prototype
,键命中,所以不会undefined
。注意的一点,原型对象也是对象,即原型对象也存在_proto_
指针指向相应原型对象,在原型对象中匹配键时,也遵循先属性,后原型的法则。这样的匹配方式就实现了原型链[3]。
某些场合中,父类仅对子类的prototype
存在影响,此时应考虑使用对象继承。假设Organization
类和Employee
类。
function Organization(boss, belief) {
this.boss = boss;
this.belief = belief;
}
Organization.prototype.speak = function() {
console.log("%s powers the company, who believes \"%s\"", this.boss, this.belief);
};
function Employee(name, age, belief) {
this.name = name;
this.age = age;
}
如果Employee
指代自由职业员工,即同时充当公司跟雇员的身份,又不需要公司运作方式(原型方法),则Organization
的仅属性对该类产生影响,则继承方式如下,可以称之为“属性继承”。
function Employee(name, age, belief) {
Organization.call(this, name, belief);
this.name = name;
this.age = age;
}
如果Employee
指代特定公司的员工,则Organization
的属性跟原型同时对该类产生影响,则继承方式如下,原型直接指定公司信息。如此,Employee
实例都默认具备相同的公司信息。
Employee.prototype = new Organization('bruce wayen', 'make business easy');
Employee.prototype.constructor = Employee;
对于这种相关属性写死的方式,还有另外一种实现方式:
Employee.prototype = Object.create(Organization.prototype, {
name: {
configurable: true,
enumerable: true,
writable: true,
value: 'bruce wayen'
},
belief: {
configurable: true,
enumerable: true,
writable: true,
value: 'make business easy'
}
});
Employee.prototype.constructor = Employee;
针对上述的自由职业者问题,通过直接扩充Employee
的属性,在构造函数内部直接指定公司信息,但需要公司运作方式(原型方法),则实现如下:
function Employee(name, age, belief) {
this.name = name;
this.boss = name;
this.age = age;
this.belief = belief
}
Employee.prototype = Organization.prototype;
Employee.prototype.constructor = Employee;
伪类继承与传统的面向对象语言更为相似,同时继承属性和原型,则自由工作者,又需要公司运作方式,则可以在不调整原始代码的基础上,如下实现:
function Employee(name, age, belief) {
Organization.call(this, name, belief);
this.name = name;
this.age = age;
}
Employee.prototype = Organization.prototype;
Employee.prototype.constructor = Employee;
如果你使用Nodejs
的话,大部分应用场景都会使用伪类继承,如下代码为gulp
脚本部分代码,即使用伪类继承方式。
var Orchestrator = require('orchestrator');
function Gulp() {
Orchestrator.call(this);
}
util.inherits(Gulp, Orchestrator);
目前为止,iojs 2.0+以基本实现class
功能。
"use strict";
class Organization {
constructor(boss, belief) {
this.boss = boss;
this.belief = belief;
}
speak() {
console.log("%s powers the company, who believes \"%s\"", this.boss, this.belief);
}
}
class Employee extends Organization {
constructor(name, age, belief) {
super(name, belief);
this.name = name;
this.age = age;
}
}
use strict
必不可少,否则会抛出异常。之前以为class
是完全新面向对象语法,后来确认更像是语法糖的东西,实现伪类继承。
记录比较零散,如有机会,阅读《javascript高级程序设计》
可以收获更多,暂且记录到这里。