10种JavaScript代码复用模式

模式1:原型继承
function object(o) {function F() {}F.prototype = o;return new F();}// 要继承的父对象var parent = {name: "Papa"};// 新对象var child = object(parent);// 测试console.log(child.name); // "Papa"// 父构造函数function Person() {// an "own" propertythis.name = "Adam";}// 给原型添加新属性Person.prototype.getName = function () {return this.name;};// 创建新personvar papa = new Person();// 继承var kid = object(papa);console.log(kid.getName()); // "Adam"// 父构造函数function Person() {// an "own" propertythis.name = "Adam";}// 给原型添加新属性Person.prototype.getName = function () {return this.name;};// 继承var kid = object(Person.prototype);console.log(typeof kid.getName); // "function",因为是在原型里定义的console.log(typeof kid.name); // "undefined", 因为只继承了原型
/* 使用新版的ECMAScript 5提供的功能 */var child = Object.create(parent);var child = Object.create(parent, {age: { value: 2} // ECMA5 descriptor});console.log(child.hasOwnProperty("age")); // true
// 首先,定义一个新对象manvar man = Object.create(null);// 接着,创建包含属性的配置设置// 属性设置为可写,可枚举,可配置var config = {writable: true,enumerable: true,configurable: true};// 通常使用Object.defineProperty()来添加新属性(ECMAScript5支持)// 现在,为了方便,我们自定义一个封装函数var defineProp = function (obj, key, value) {config.value = value;Object.defineProperty(obj, key, config);}defineProp(man, 'car', 'Delorean');defineProp(man, 'dob', '1981');defineProp(man, 'beard', false);
var driver = Object.create( man );defineProp (driver, 'topSpeed', '100mph');driver.topSpeed // 100mph
模式2:复制所有属性进行继承
/* 浅拷贝 */function extend(parent, child) {var i;child = child || {};for (i in parent) {if (parent.hasOwnProperty(i)) {child[i] = parent[i];}}return child;}var dad = { name: "Adam" };var kid = extend(dad);console.log(kid.name); // "Adam"var dad = {counts: [1, 2, 3],reads: { paper: true }};var kid = extend(dad);kid.counts.push(4);console.log(dad.counts.toString()); // "1,2,3,4"console.log(dad.reads === kid.reads); // true
/* 深拷贝 */function extendDeep(parent, child) {var i,toStr = Object.prototype.toString,astr = "[object Array]";child = child || {};for (i in parent) {if (parent.hasOwnProperty(i)) {if (typeof parent[i] === 'object') {child[i] = (toStr.call(parent[i]) === astr) ? [] : {};extendDeep(parent[i], child[i]);} else {child[i] = parent[i];}}}return child;}var dad = {counts: [1, 2, 3],reads: { paper: true }};var kid = extendDeep(dad);kid.counts.push(4);console.log(kid.counts.toString()); // "1,2,3,4"console.log(dad.counts.toString()); // "1,2,3"console.log(dad.reads === kid.reads); // falsekid.reads.paper = false;
模式3:混合(mix-in)
function mix() {var arg, prop, child = {};for (arg = 0; arg < arguments.length; arg += 1) {for (prop in arguments[arg]) {if (arguments[arg].hasOwnProperty(prop)) {child[prop] = arguments[arg][prop];}}}return child;}var cake = mix({ eggs: 2, large: true },{ butter: 1, salted: true },{ flour: '3 cups' },{ sugar: 'sure!' });console.dir(cake);
// Carvar Car = function (settings) {this.model = settings.model || 'no model provided';this.colour = settings.colour || 'no colour provided';};// Mixinvar Mixin = function () { };Mixin.prototype = {driveForward: function () {console.log('drive forward');},driveBackward: function () {console.log('drive backward');}};// 定义的2个参数分别是被混入的对象(reciving)和从哪里混入的对象(giving)function augment(receivingObj, givingObj) {// 如果提供了指定的方法名称的话,也就是参数多余3个if (arguments[2]) {for (var i = 2, len = arguments.length; i < len; i++) {receivingObj.prototype[arguments[i]] = givingObj.prototype[arguments[i]];}}// 如果不指定第3个参数,或者更多参数,就混入所有的方法else {for (var methodName in givingObj.prototype) {// 检查receiving对象内部不包含要混入的名字,如何包含就不混入了if (!receivingObj.prototype[methodName]) {receivingObj.prototype[methodName] = givingObj.prototype[methodName];}}}}// 给Car混入属性,但是值混入'driveForward' 和 'driveBackward'*/augment(Car, Mixin, 'driveForward', 'driveBackward');// 创建新对象Carvar vehicle = new Car({ model: 'Ford Escort', colour: 'blue' });// 测试是否成功得到混入的方法vehicle.driveForward();vehicle.driveBackward();
模式4:借用方法
var one = {name: 'object',say: function (greet) {return greet + ', ' + this.name;}};// 测试console.log(one.say('hi')); // "hi, object"var two = {name: 'another object'};console.log(one.say.apply(two, ['hello'])); // "hello, another object"// 将say赋值给一个变量,this将指向到全局变量var say = one.say;console.log(say('hoho')); // "hoho, undefined"// 传入一个回调函数callbackvar yetanother = {name: 'Yet another object',method: function (callback) {return callback('Hola');}};console.log(yetanother.method(one.say)); // "Holla, undefined"function bind(o, m) {return function () {return m.apply(o, [].slice.call(arguments));};}var twosay = bind(two, one.say);console.log(twosay('yo')); // "yo, another object"// ECMAScript 5给Function.prototype添加了一个bind()方法,以便很容易使用apply()和call()。if (typeof Function.prototype.bind === 'undefined') {Function.prototype.bind = function (thisArg) {var fn = this,slice = Array.prototype.slice,args = slice.call(arguments, 1);return function () {return fn.apply(thisArg, args.concat(slice.call(arguments)));};};}var twosay2 = one.say.bind(two);console.log(twosay2('Bonjour')); // "Bonjour, another object"var twosay3 = one.say.bind(two, 'Enchanté');console.log(twosay3()); // "Enchanté, another object"
模式5:默认模式
function inherit(C, P) {C.prototype = new P();}// 父构造函数function Parent(name) {this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () {return this.name;};// Child构造函数为空function Child(name) {}// 执行继承inherit(Child, Parent);var kid = new Child();console.log(kid.say()); // "Adam"var kiddo = new Child();kiddo.name = "Patrick";console.log(kiddo.say()); // "Patrick"// 缺点:不能让参数传进给Child构造函数var s = new Child('Seth');console.log(s.say()); // "Adam"
模式6:借用构造函数
// 父构造函数function Parent(name) {this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () {return this.name;};// Child构造函数function Child(name) {Parent.apply(this, arguments);}var kid = new Child("Patrick");console.log(kid.name); // "Patrick"// 缺点:没有从构造函数上继承say方法console.log(typeof kid.say); // "undefined"
模式7:借用构造函数并设置原型
// 父构造函数function Parent(name) {this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () {return this.name;};// Child构造函数function Child(name) {Parent.apply(this, arguments);}Child.prototype = new Parent();var kid = new Child("Patrick");console.log(kid.name); // "Patrick"console.log(typeof kid.say); // functionconsole.log(kid.say()); // Patrickconsole.dir(kid);delete kid.name;console.log(kid.say()); // "Adam"
模式8:共享原型
function inherit(C, P) {C.prototype = P.prototype;}// 父构造函数function Parent(name) {this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () {return this.name;};// Child构造函数function Child(name) {}inherit(Child, Parent);var kid = new Child('Patrick');console.log(kid.name); // undefinedconsole.log(typeof kid.say); // functionkid.name = 'Patrick';console.log(kid.say()); // Patrickconsole.dir(kid);
模式9:临时构造函数
/* 闭包 */var inherit = (function () {var F = function () {};return function (C, P) {F.prototype = P.prototype;C.prototype = new F();C.uber = P.prototype;C.prototype.constructor = C;}} ());function Parent(name) {this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () {return this.name;};// Child构造函数function Child(name) {}inherit(Child, Parent);var kid = new Child();console.log(kid.name); // undefinedconsole.log(typeof kid.say); // functionkid.name = 'Patrick';console.log(kid.say()); // Patrickvar kid2 = new Child("Tom");console.log(kid.say());console.log(kid.constructor.name); // Childconsole.log(kid.constructor === Parent); // false
模式10:klass
var klass = function (Parent, props) {var Child, F, i;// 1.// 新构造函数Child = function () {if (Child.uber && Child.uber.hasOwnProperty("__construct")) {Child.uber.__construct.apply(this, arguments);}if (Child.prototype.hasOwnProperty("__construct")) {Child.prototype.__construct.apply(this, arguments);}};// 2.// 继承Parent = Parent || Object;F = function () {};F.prototype = Parent.prototype;Child.prototype = new F();Child.uber = Parent.prototype;Child.prototype.constructor = Child;// 3.// 添加实现方法for (i in props) {if (props.hasOwnProperty(i)) {Child.prototype[i] = props[i];}}// return the "class"return Child;};var Man = klass(null, {__construct: function (what) {console.log("Man's constructor");this.name = what;},getName: function () {return this.name;}});var first = new Man('Adam'); // logs "Man's constructor"first.getName(); // "Adam"var SuperMan = klass(Man, {__construct: function (what) {console.log("SuperMan's constructor");},getName: function () {var name = SuperMan.uber.getName.call(this);return "I am " + name;}});var clark = new SuperMan('Clark Kent');clark.getName(); // "I am Clark Kent"console.log(clark instanceof Man); // trueconsole.log(clark instanceof SuperMan); // true
总结

评论
