10種JavaScript代碼復(fù)用模式

模式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"// 父構(gòu)造函數(shù)function Person() {// an "own" propertythis.name = "Adam";}// 給原型添加新屬性Person.prototype.getName = function () {return this.name;};// 創(chuàng)建新personvar papa = new Person();// 繼承var kid = object(papa);console.log(kid.getName()); // "Adam"// 父構(gòu)造函數(shù)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",因?yàn)槭窃谠屠锒x的console.log(typeof kid.name); // "undefined", 因?yàn)橹焕^承了原型
/* 使用新版的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);// 接著,創(chuàng)建包含屬性的配置設(shè)置// 屬性設(shè)置為可寫,可枚舉,可配置var config = {writable: true,enumerable: true,configurable: true};// 通常使用Object.defineProperty()來添加新屬性(ECMAScript5支持)// 現(xiàn)在,為了方便,我們自定義一個封裝函數(shù)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:復(fù)制所有屬性進(jìn)行繼承
/* 淺拷貝 */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個參數(shù)分別是被混入的對象(reciving)和從哪里混入的對象(giving)function augment(receivingObj, givingObj) {// 如果提供了指定的方法名稱的話,也就是參數(shù)多余3個if (arguments[2]) {for (var i = 2, len = arguments.length; i < len; i++) {receivingObj.prototype[arguments[i]] = givingObj.prototype[arguments[i]];}}// 如果不指定第3個參數(shù),或者更多參數(shù),就混入所有的方法else {for (var methodName in givingObj.prototype) {// 檢查receiving對象內(nèi)部不包含要混入的名字,如何包含就不混入了if (!receivingObj.prototype[methodName]) {receivingObj.prototype[methodName] = givingObj.prototype[methodName];}}}}// 給Car混入屬性,但是值混入'driveForward' 和 'driveBackward'*/augment(Car, Mixin, 'driveForward', 'driveBackward');// 創(chuàng)建新對象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"// 傳入一個回調(diào)函數(shù)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:默認(rèn)模式
function inherit(C, P) {C.prototype = new P();}// 父構(gòu)造函數(shù)function Parent(name) {this.name = name || 'Adam';}// 給原型添加say功能Parent.prototype.say = function () {return this.name;};// Child構(gòu)造函數(shù)為空function Child(name) {}// 執(zhí)行繼承inherit(Child, Parent);var kid = new Child();console.log(kid.say()); // "Adam"var kiddo = new Child();kiddo.name = "Patrick";console.log(kiddo.say()); // "Patrick"// 缺點(diǎn):不能讓參數(shù)傳進(jìn)給Child構(gòu)造函數(shù)var s = new Child('Seth');console.log(s.say()); // "Adam"
模式6:借用構(gòu)造函數(shù)
// 父構(gòu)造函數(shù)function Parent(name) {this.name = name || 'Adam';}// 給原型添加say功能Parent.prototype.say = function () {return this.name;};// Child構(gòu)造函數(shù)function Child(name) {Parent.apply(this, arguments);}var kid = new Child("Patrick");console.log(kid.name); // "Patrick"// 缺點(diǎn):沒有從構(gòu)造函數(shù)上繼承say方法console.log(typeof kid.say); // "undefined"
模式7:借用構(gòu)造函數(shù)并設(shè)置原型
// 父構(gòu)造函數(shù)function Parent(name) {this.name = name || 'Adam';}// 給原型添加say功能Parent.prototype.say = function () {return this.name;};// Child構(gòu)造函數(shù)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;}// 父構(gòu)造函數(shù)function Parent(name) {this.name = name || 'Adam';}// 給原型添加say功能Parent.prototype.say = function () {return this.name;};// Child構(gòu)造函數(shù)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:臨時構(gòu)造函數(shù)
/* 閉包 */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構(gòu)造函數(shù)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.// 新構(gòu)造函數(shù)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.// 添加實(shí)現(xiàn)方法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
總結(jié)

評論
圖片
表情
