亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > JavaScript > 正文

深入理解JavaScript系列(46):代碼復用模式(推薦篇)詳解

2024-05-06 16:16:02
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了深入理解JavaScript系列(46):代碼復用模式(推薦篇)詳解,本文講解了原型繼承、復制所有屬性進行繼承、混合(mix-in)、借用方法等模式,需要的朋友可以參考下
 

介紹

本文介紹的四種代碼復用模式都是最佳實踐,推薦大家在編程的過程中使用。

模式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" property
    this.name = "Adam";
}
// 給原型添加新屬性
Person.prototype.getName = function () {
    return this.name;
};
// 創建新person
var papa = new Person();
// 繼承
var kid = object(papa);
console.log(kid.getName()); // "Adam"


// 父構造函數
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",因為是在原型里定義的
console.log(typeof kid.name); // "undefined", 因為只繼承了原型


同時,ECMAScript5也提供了類似的一個方法叫做Object.create用于繼承對象,用法如下:

 

 

復制代碼代碼如下:

/* 使用新版的ECMAScript 5提供的功能 */
var child = Object.create(parent);

 

var child = Object.create(parent, {
    age: { value: 2} // ECMA5 descriptor
});
console.log(child.hasOwnProperty("age")); // true

 

而且,也可以更細粒度地在第二個參數上定義屬性:

復制代碼代碼如下:

// 首先,定義一個新對象man
var 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

但是有個地方需要注意,就是Object.create(null)創建的對象的原型為undefined,也就是沒有toString和valueOf方法,所以alert(man);的時候會出錯,但alert(man.car);是沒問題的。

 

模式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

 

代碼的最后一行,你可以發現dad和kid的reads是一樣的,也就是他們使用的是同一個引用,這也就是淺拷貝帶來的問題。

我們再來看一下深拷貝:

復制代碼代碼如下:

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


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

 

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


mix函數將所傳入的所有參數的子屬性都復制到child對象里,以便產生一個新對象。

 

那如何我們只想混入部分屬性呢?該個如何做?其實我們可以使用多余的參數來定義需要混入的屬性,例如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個參數分別是被混入的對象(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');

// 創建新對象Car
var 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"

// 傳入一個回調函數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添加了一個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"

 

總結

就不用總結了吧。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品一区二区三区不| 欧美人在线视频| 亚洲三级免费看| 欧美激情网友自拍| 欧美在线视频播放| 欧美成人小视频| 国产va免费精品高清在线| 日韩成人免费视频| 久久精品国产综合| 日韩极品精品视频免费观看| 国产精品爽黄69| 日韩av在线精品| 中文字幕少妇一区二区三区| 亚洲免费人成在线视频观看| 欧美黑人一区二区三区| 日韩中文字幕第一页| 91久久久久久国产精品| 国产精品成av人在线视午夜片| 欧美成年人视频| 欧美野外wwwxxx| 好吊成人免视频| 久久久亚洲天堂| 欧美性视频精品| 2020国产精品视频| 91麻豆桃色免费看| 91在线观看免费高清| 亚洲欧美制服综合另类| 亚洲va国产va天堂va久久| 精品国产一区二区三区久久| 欧美日韩亚洲一区二区三区| 久久精品电影网| 丝袜亚洲欧美日韩综合| 福利一区视频在线观看| 国产精品草莓在线免费观看| 国产日韩欧美黄色| 亚洲精品99久久久久| 欧美激情性做爰免费视频| 啪一啪鲁一鲁2019在线视频| 亚洲综合av影视| 久久视频在线观看免费| 亚洲变态欧美另类捆绑| 国产精品日韩在线播放| 第一福利永久视频精品| 欧美日韩在线另类| 国产日本欧美一区二区三区| 亚洲另类激情图| 国产成人精品久久亚洲高清不卡| 日韩小视频网址| 欧美黑人巨大精品一区二区| 中文字幕国产亚洲| 久久久精品一区二区| 欧美性生活大片免费观看网址| 9.1国产丝袜在线观看| 欧美日韩中文字幕在线视频| 国产成人一区二区| 亚洲欧美日韩在线一区| 亚洲欧洲在线播放| 不卡av电影在线观看| 亚洲欧洲日本专区| 色婷婷久久av| 深夜福利日韩在线看| 亚洲一区二区三区在线免费观看| 欧美性极品少妇精品网站| 成人性生交大片免费观看嘿嘿视频| 68精品久久久久久欧美| 久久亚洲综合国产精品99麻豆精品福利| 久久躁日日躁aaaaxxxx| 国产精品美女主播| …久久精品99久久香蕉国产| 亚洲性生活视频在线观看| 亚洲精品一区二区久| 国产精品久久久久av免费| 欧美日韩激情网| 亚洲精品久久久久久下一站| 青草热久免费精品视频| 成人福利在线视频| 国模叶桐国产精品一区| 色综合色综合久久综合频道88| 国产精品永久免费观看| 国产成人精品日本亚洲专区61| 成人欧美一区二区三区在线湿哒哒| 日韩中文理论片| 欧美一级淫片播放口| 日产精品久久久一区二区福利| 91精品久久久久久| 欧美最猛性xxxxx(亚洲精品)| 亚洲成人国产精品| 国产成人福利夜色影视| 亚洲欧洲午夜一线一品| 久久免费精品日本久久中文字幕| 欧美性极品xxxx娇小| 欧美性猛交xxxx黑人猛交| 久久手机免费视频| 欧美电影在线播放| 欧美成人精品不卡视频在线观看| 97在线精品视频| 欧美激情第99页| 亚洲成人av片| 国产精品看片资源| 国产日产亚洲精品| 热门国产精品亚洲第一区在线| 国外成人免费在线播放| 欧美主播福利视频| 国模极品一区二区三区| 国产成人精品在线| 免费97视频在线精品国自产拍| 欧美丰满片xxx777| www.欧美精品| 国产精品自产拍在线观| 国产精品wwww| 国产91成人在在线播放| 亚洲天堂男人天堂女人天堂| 日本久久久a级免费| 国产精品成人va在线观看| 在线观看日韩av| 97香蕉超级碰碰久久免费的优势| 成人激情视频在线观看| 日韩精品视频在线观看网址| 91av视频导航| 成人激情黄色网| 欧美在线xxx| 亚洲欧美国产一区二区三区| 免费99精品国产自在在线| 日韩av色在线| 亚洲电影第1页| 国产精品99久久久久久久久久久久| 日韩欧美成人区| www.精品av.com| 欧美一区二区色| 成人福利在线观看| 国模私拍视频一区| 国产精品国产自产拍高清av水多| 亚洲www在线| 国产精品wwww| 国产精品视频不卡| 国产精品久久久久福利| 精品欧美激情精品一区| 精品国产一区二区三区久久狼5月| 国产精品精品一区二区三区午夜版| 国产精品直播网红| 亚洲欧美日韩区| www.xxxx欧美| 亚洲图片在区色| 欧美日韩免费网站| 亚洲欧美色婷婷| 精品夜色国产国偷在线| 亚洲高清不卡av| 国产午夜精品理论片a级探花| 欧美最顶级丰满的aⅴ艳星| 国产伦精品一区二区三区精品视频| 国产一区二区三区精品久久久| 亚洲最大中文字幕| 亚洲aa在线观看| 狠狠操狠狠色综合网| 国产精品色婷婷视频| 日韩免费在线看| 美女精品久久久| 欧美一区第一页| 在线免费看av不卡| 亚洲曰本av电影| 5566成人精品视频免费| 免费97视频在线精品国自产拍| 91精品中国老女人| 欧美成人sm免费视频|