代码复用性,提高开发效率
参考:JS_Pattern.md
- 面向接口编程,而非面向实现编程。
- 优先使用对象「组合 Mixin」而非类继承。
对象创建方法
- 工厂模式创建对象,对象创建的工厂函数
Constructor
模式:构建实例的类的构造函数- ES6 的
class
语法糖:constructor
,super
,static
,set
,get
- 稳妥构造模式:对象在内部
new Object()
构建,通过修改之后,返回对象。 constructor
修复
- ES6 的
- Prototype 原型继承模式:
Object.create()
基于原型的创建
- 组合使用
Constructor
与Prototype
模式 - Builder 模式
let Book = (function() {
let privateVar = 1;
let privateMethod = () => {};
function book(name) {
this.name = name;
this.specialMethod = () => {};
}
book.prototype = {
publicMethod: () => {}
};
return book;
})();
类的继承方法
- 类式继承:
Prototype Chain
利用原型让一个引用类型继承另一个引用类型的属性和方法SubType.prototype = new SuperType()
prototype 是一种 享元模式。- 存在问题:无法向父类传递参数,并且会共享原型中父类的引用类型。
- 构造函数继承
- 存在问题:不会继承父类原型链中的方法。
function SuperClass(id) {
this.book = [];
this.id = id;
}
SuperClass.prototype.showBook = () => {};
function SubClass(id, name) {
SuperClass.call(this, id);
this.name = name;
}
- 组合继承:将类式继承和构造函数继承的功能合并。
- 原型继承:参考
js_patterns
中的Prototype
模式。 - 寄生组合式继承
- 构造函数继承实例属性
- 原型链共享属性和方法
let Child = Obejct.create(Parent); // 与后者等效
var inhert = (function () {
var F = function () {};
return function (Child, Parent) {
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.uper = Parent.prototype;
Child.prototype.constructor = Child; // Constructor 修正
}
}());
function Super(name) {
this.name = name;
}
Super.prototype.getName = () => {};
function Sub(name, time) {
Super.call(this, name);
this.time = time;
}
inhert(Sub, Super);
Sub.prototype.newMethod = () => {};
- Borrow:方法借用
- 借用父类的构造器或者方法
- 借用构造函数继承:子类的多重继承,ES6 语法糖
extends
- 理解 JS 的对象类型判定的哲学:鸭式辩型 Duck Typing:In duck typing, an object’s suitability is determined by the presence of certain methods and properties (with appropriate meaning), rather than the actual type of the object.
- 注意:不要在子类中调用父类名称
- 注意:不要继承标准类
- 注意:不要轻率使用猴子补丁
- 借用构造函数继承:子类的多重继承,ES6 语法糖
- 修改原生对象原型
- 借用父类的构造器或者方法
- Polyfills 的兼容模式
- 借用其他对象的构造器或者方法
- Mixin:组合继承,使用
_.extend
类似的方法,扩展原型链
其它
- 静态方法,挂载到 Constructor 函数上的静态方法
Method.xxx = () => {}
Object.assign() // 合并对象
- 多态的实现:
let args = arguments;
根据arguments
的情形来处理一个方法的多种调用方式。
动态修改
- Decorator 模式:装饰者模式在不修改源对象模型的情况下,向对象中注入新的方法或属性。
- 动态选型模式,在构造函数中根据上下文属性,动态定义方法
- 防止原型动态被修改
这一块请参考 JS设计模式 中和对象创建、类创建的相关知识。
ES6 Classes
class PersonClass extends AnimalClass {
// equivalent of the PersonType constructor
constructor(name, sex, job) {
super(name, sex);
this.job = job;
}
set setName(name) {
this.name = name;
}
get getName() {
return this.name;
}
static default() {
this.name = 'default';
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
}
let person = new PersonClass("Nicholas");
person.sayName(); // outputs "Nicholas"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
// direct equivalent of PersonClass
let PersonType2 = (function() {
"use strict";
function PersonType2(name) {
// make sure the function was called with new
if ((!this instanceof PersonType2)) {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(PersonType2.prototype, "sayName", {
value: function() {
console.log(this.name);
},
enumerable: false,
writable: true,
configurable: true
});
return PersonType2;
}());
- Class declarations, unlike function declarations, are not hoisted. Class declarations act like
let
declarations and so exist in the temporal dead zone until execution reaches the declaration. - All code inside of class declarations runs in strict mode automatically. There’s no way to opt-out of strict mode inside of classes.
- All methods are non-enumerable. This is a significant change from custom types, where you need to use
Object.defineProperty()
to make a method non-enumerable. - Calling the class constructor without
new
throws an error.
Ref
Babel 中继承的实现
'use strict';
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
// 做类型检测
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
// 原型链拼接,同时修正 constructor 参数
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
// 原型构造器参数修正
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var A = function A() {
_classCallCheck(this, A);
};
A.job = 'title';
var B = function (_A) {
_inherits(B, _A);
function B(a) {
// 继承检测
_classCallCheck(this, B);
// 调用父类构造器,如果有的话
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(B).call(this, a));
// 子类 Constructor 中的方法
_this.darling = 'qingnan';
return _this;
}
return B;
}(A);