在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 代碼復(fù)用模式(推薦篇)
代碼復(fù)用模式(避免篇)
S.O.L.I.D 五大原則之接口隔離原則 ISP
設(shè)計(jì)模式之狀態(tài)模式
JavaScript 核心(晉級(jí)高手必讀篇)
設(shè)計(jì)模式之建造者模式
JavaScript 與 DOM(上)——也適用于新手
設(shè)計(jì)模式之中介者模式
設(shè)計(jì)模式之裝飾者模式
設(shè)計(jì)模式之模板方法
設(shè)計(jì)模式之外觀模式
強(qiáng)大的原型和原型鏈
設(shè)計(jì)模式之構(gòu)造函數(shù)模式
揭秘命名函數(shù)表達(dá)式
深入理解J avaScript 系列(結(jié)局篇)
執(zhí)行上下文(Execution Contexts)
函數(shù)(Functions)
《你真懂 JavaScript 嗎?》答案詳解
設(shè)計(jì)模式之適配器模式
設(shè)計(jì)模式之組合模式
設(shè)計(jì)模式之命令模式
S.O.L.I.D 五大原則之單一職責(zé) SRP
編寫(xiě)高質(zhì)量 JavaScript 代碼的基本要點(diǎn)
求值策略
閉包(Closures)
對(duì)象創(chuàng)建模式(上篇)
This? Yes,this!
設(shè)計(jì)模式之代理模式
變量對(duì)象(Variable Object)
S.O.L.I.D 五大原則之里氏替換原則 LSP
面向?qū)ο缶幊讨话憷碚?/span>
設(shè)計(jì)模式之單例模式
Function 模式(上篇)
S.O.L.I.D 五大原則之依賴(lài)倒置原則 DIP
設(shè)計(jì)模式之迭代器模式
立即調(diào)用的函數(shù)表達(dá)式
設(shè)計(jì)模式之享元模式
設(shè)計(jì)模式之原型模式
根本沒(méi)有“JSON 對(duì)象”這回事!
JavaScript 與 DOM(下)
面向?qū)ο缶幊讨?ECMAScript 實(shí)現(xiàn)
全面解析 Module 模式
對(duì)象創(chuàng)建模式(下篇)
設(shè)計(jì)模式之職責(zé)鏈模式
S.O.L.I.D 五大原則之開(kāi)閉原則 OCP
設(shè)計(jì)模式之橋接模式
設(shè)計(jì)模式之策略模式
設(shè)計(jì)模式之觀察者模式
代碼復(fù)用模式(推薦篇)
作用域鏈(Scope Chain)
Function 模式(下篇)
設(shè)計(jì)模式之工廠模式

代碼復(fù)用模式(推薦篇)

介紹

本文介紹的四種代碼復(fù)用模式都是最佳實(shí)踐,推薦大家在編程的過(guò)程中使用。

模式 1:原型繼承

原型繼承是讓父對(duì)象作為子對(duì)象的原型,從而達(dá)到繼承的目的:

function object(o) {
    function F() {
    }  
    F.prototype = o;
    return new F();
}    
// 要繼承的父對(duì)象
var parent = {
    name: "Papa"
};  
// 新對(duì)象
var child = object(parent);  
// 測(cè)試
console.log(child.name); // "Papa"  
// 父構(gòu)造函數(shù)
function Person() {
    // an "own" property
    this.name = "Adam";
}
// 給原型添加新屬性
Person.prototype.getName = function () {
    return this.name;
};
// 創(chuàng)建新person
var papa = new Person();
// 繼承
var kid = object(papa);
console.log(kid.getName()); // "Adam"  
// 父構(gòu)造函數(shù)
function Person() {
    // an "own" property
    this.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)橹焕^承了原型

同時(shí),ECMAScript5 也提供了類(lèi)似的一個(gè)方法叫做 Object.create 用于繼承對(duì)象,用法如下:

/* 使用新版的ECMAScript 5提供的功能 */
var child = Object.create(parent);  
var child = Object.create(parent, {
    age: { value: 2} // ECMA5 descriptor
});
console.log(child.hasOwnProperty("age")); // true

而且,也可以更細(xì)粒度地在第二個(gè)參數(shù)上定義屬性:

// 首先,定義一個(gè)新對(duì)象man
var man = Object.create(null);  
// 接著,創(chuàng)建包含屬性的配置設(shè)置
// 屬性設(shè)置為可寫(xiě),可枚舉,可配置
var config = {
    writable: true,
    enumerable: true,
    configurable: true
};  
// 通常使用Object.defineProperty()來(lái)添加新屬性(ECMAScript5支持)
// 現(xiàn)在,為了方便,我們自定義一個(gè)封裝函數(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

但是有個(gè)地方需要注意,就是 Object.create(null)創(chuàng)建的對(duì)象的原型為 undefined,也就是沒(méi)有 toString 和 valueOf 方法,所以 alert(man);的時(shí)候會(huì)出錯(cuò),但 alert(man.car);是沒(méi)問(wèn)題的。

模式 2:復(fù)制所有屬性進(jìn)行繼承

這種方式的繼承就是將父對(duì)象里所有的屬性都復(fù)制到子對(duì)象上,一般子對(duì)象可以使用父對(duì)象的數(shù)據(jù)。

先來(lái)看一個(gè)淺拷貝的例子:

/* 淺拷貝 */
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

代碼的最后一行,你可以發(fā)現(xiàn) dad 和 kid 的 reads 是一樣的,也就是他們使用的是同一個(gè)引用,這也就是淺拷貝帶來(lái)的問(wèn)題。

我們?cè)賮?lái)看一下深拷貝:

/* 深拷貝 */
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); // false
kid.reads.paper = false;

深拷貝以后,兩個(gè)值就不相等了,bingo!

模式 3:混合(mix-in)

混入就是將一個(gè)對(duì)象的一個(gè)或多個(gè)(或全部)屬性(或方法)復(fù)制到另外一個(gè)對(duì)象,我們舉一個(gè)例子:

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);

mix 函數(shù)將所傳入的所有參數(shù)的子屬性都復(fù)制到 child 對(duì)象里,以便產(chǎn)生一個(gè)新對(duì)象。

那如何我們只想混入部分屬性呢?該個(gè)如何做?其實(shí)我們可以使用多余的參數(shù)來(lái)定義需要混入的屬性,例如 mix(child,parent,method1,method2)這樣就可以只將 parent 里的 method1 和 method2 混入到 child 里。上代碼:

// Car 
var Car = function (settings) {
    this.model = settings.model || 'no model provided';
    this.colour = settings.colour || 'no colour provided';
};  
// Mixin
var Mixin = function () { };
Mixin.prototype = {
    driveForward: function () {
        console.log('drive forward');
    },
    driveBackward: function () {
        console.log('drive backward');
    }
};  
// 定義的2個(gè)參數(shù)分別是被混入的對(duì)象(reciving)和從哪里混入的對(duì)象(giving)
function augment(receivingObj, givingObj) {
    // 如果提供了指定的方法名稱(chēng)的話(huà),也就是參數(shù)多余3個(gè)
    if (arguments[2]) {
        for (var i = 2, len = arguments.length; i < len; i++) {
            receivingObj.prototype[arguments[i]] = givingObj.prototype[arguments[i]];
        }
    }
    // 如果不指定第3個(gè)參數(shù),或者更多參數(shù),就混入所有的方法
    else {
        for (var methodName in givingObj.prototype) {
            // 檢查receiving對(duì)象內(nèi)部不包含要混入的名字,如何包含就不混入了
            if (!receivingObj.prototype[methodName]) {
                receivingObj.prototype[methodName] = givingObj.prototype[methodName];
            }
        }
    }
}  
// 給Car混入屬性,但是值混入'driveForward' 和 'driveBackward'*/
augment(Car, Mixin, 'driveForward', 'driveBackward');  
// 創(chuàng)建新對(duì)象Car
var vehicle = new Car({ model: 'Ford Escort', colour: 'blue' });  
// 測(cè)試是否成功得到混入的方法
vehicle.driveForward();
vehicle.driveBackward();

該方法使用起來(lái)就比較靈活了。

模式 4:借用方法

一個(gè)對(duì)象借用另外一個(gè)對(duì)象的一個(gè)或兩個(gè)方法,而這兩個(gè)對(duì)象之間不會(huì)有什么直接聯(lián)系。不用多解釋?zhuān)苯佑么a解釋吧:

var one = {
    name: 'object',
    say: function (greet) {
        return greet + ', ' + this.name;
    }
};  
// 測(cè)試
console.log(one.say('hi')); // "hi, object"  
var two = {
    name: 'another object'
};  
console.log(one.say.apply(two, ['hello'])); // "hello, another object"  
// 將say賦值給一個(gè)變量,this將指向到全局變量
var say = one.say;
console.log(say('hoho')); // "hoho, undefined"  
// 傳入一個(gè)回調(diào)函數(shù)callback
var 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添加了一個(gè)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"