@bornkiller
2015-05-27T06:27:16.000000Z
字数 2937
阅读 3321
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高级程序设计》可以收获更多,暂且记录到这里。