成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

YUI中對(duì)象合并的方法與原理

bitkylin / 1123人閱讀

摘要:更細(xì)致的為了應(yīng)對(duì)更為復(fù)雜的對(duì)象合并要求,提供了方法。注意到,當(dāng)兩者都為時(shí),得到的正是在配置對(duì)象合并中的一個(gè)理想結(jié)果。它們都類似于對(duì)象合并,而且有趣的是,其源碼中都調(diào)用了方法。其深合并的實(shí)現(xiàn)方法依然是遞歸。

起因:配置選項(xiàng)

“配置”(Config | Options | Settings)對(duì)大家來(lái)說(shuō)一定是非常熟悉的詞。就以一般玩的游戲?yàn)槔?,很多游戲的主界面,搭配的菜單?huì)是"start","load","config","exit"這樣的搭配。在"config"中,我們可以調(diào)整游戲參數(shù),比如音量、控制按鍵等,以更符合自己的游戲習(xí)慣。不過(guò),也有游戲并沒(méi)有"config",這些游戲其實(shí)就是只有一個(gè)不允許修改的“默認(rèn)”(Defaults)配置,而即使如此,這些游戲至少也會(huì)給你一份指南,告訴你應(yīng)該如何按照預(yù)設(shè)進(jìn)行游戲。

應(yīng)用的配置這一環(huán)節(jié)的設(shè)計(jì),其實(shí)就是要求要將配置數(shù)據(jù)從代碼中分離出來(lái)。也就是說(shuō),那些可以被修改,或者將來(lái)可能會(huì)被修改的內(nèi)容(這些內(nèi)容也是代碼),應(yīng)該和指令類的代碼區(qū)別開來(lái),多帶帶放在一個(gè)地方。這樣,源碼修改可以減少很多意外的錯(cuò)誤。

javascript編寫的封裝的功能模塊,比如常見的jQuery插件,一般都會(huì)這樣分離出配置數(shù)據(jù)。下面是[slidesjs][]的使用范例:

$("#slides").slidesjs({
    width: 940,
    height: 528
});

這里的{width: 940, height: 528}即是配置數(shù)據(jù)。不過(guò),只是這些數(shù)據(jù)是不能獨(dú)立支撐起完整的功能的。在封裝的代碼之內(nèi)的,還隱藏著完整的初始配置數(shù)據(jù),這就是默認(rèn)配置。而像上面這樣在實(shí)際使用時(shí)傳入的配置數(shù)據(jù),一般叫做用戶配置。它們之間的關(guān)系是,如果同時(shí)包含對(duì)某一選項(xiàng)的配置值,用戶配置會(huì)覆蓋掉默認(rèn)配置。

比如在Sublime Text中,就是這種設(shè)計(jì)(Default和User):

可以想到,實(shí)際功能運(yùn)行時(shí),使用的配置數(shù)據(jù)既不是默認(rèn)配置,也不是用戶配置,而是這兩個(gè)配置的結(jié)合。在javascript中,配置數(shù)據(jù)都是對(duì)象(Object)的形式,因此,我們需要做對(duì)象合并

在YUI的核心包(yui-core)中,就提供了對(duì)象合并有關(guān)的方法。

YUI中的對(duì)象合并方法 淺合并的Y.merge()

YUI提供了合并一個(gè)或更多對(duì)象到一個(gè)新的合并對(duì)象上的方法Y.merge(),在這里先使用它。假如有一個(gè)封裝的功能模塊(簡(jiǎn)單的游戲?),然后內(nèi)部通過(guò)Y.merge()進(jìn)行配置對(duì)象的合并:

var myModule = function(userConfig){
    var defaults = {
        volume: 0,
        quality: "normal",
        control: {
            left: "left",
            right: "right",
            attack: "space"
        }  
    };

    var config = Y.merge(defaults, userConfig);

    // use the merged config to run this module...
};

對(duì)應(yīng)上面已有的默認(rèn)配置的形式,給出如下的用戶配置:

var userConfig = {
    quality: "high",
    control: {
        left: "a",
        right: "d",
        extra: "z"
    }
};

這里通過(guò)Y.merge()合并得到的config,輸出結(jié)果是:

{
    volume: 0,
    quality: "high",
    control: {
        left: "a",
        right: "d",
        extra: "z"
    }
}

可以看到,volumequality的屬性合并都達(dá)到了預(yù)想的要求。但是,屬性control卻像是忽略了默認(rèn)值的部分,并不符合預(yù)想結(jié)果。這是因?yàn)?,屬?b>control的值并不是基本數(shù)據(jù)類型,而是引用數(shù)據(jù)類型(例如對(duì)象、數(shù)組或函數(shù)),因此這里的配置對(duì)象是包含多層次的復(fù)雜配置對(duì)象。Y.merge()并沒(méi)有處理這樣的情況,它的源碼如下:

Y.merge = function () {
    var i      = 0,
        len    = arguments.length,
        result = {},
        key,
        obj;
 
    for (; i < len; ++i) {
        obj = arguments[i];
 
        for (key in obj) {
            if (hasOwn.call(obj, key)) {
                result[key] = obj[key];
            }
        }
    }
 
    return result;
};

其中hasOwnObject.prototype.hasOwnProperty。從上面的源碼可以看出,Y.merge()只對(duì)直接屬性(層級(jí)數(shù)為1)進(jìn)行賦值,并沒(méi)有分析屬性的值類別。因此,在前面的對(duì)象合并中,configcontrol屬性,實(shí)際上就和userConfigcontrol是同一個(gè)引用,如果在config上修改control對(duì)象,則也會(huì)改變userConfigcontrol對(duì)象。

不過(guò),Y.merge()仍然是很有價(jià)值的對(duì)象合并方法。如果是單層次的配置對(duì)象,它足以實(shí)現(xiàn)預(yù)想的要求,這是它很有用的一個(gè)模式。此外,請(qǐng)注意這個(gè)方法創(chuàng)建了一個(gè)空對(duì)象result用作最終返回,而不是直接對(duì)參數(shù)進(jìn)行操作,所以,Y.merge()方法不會(huì)影響作為參數(shù)的任一對(duì)象。

更細(xì)致的Y.mix()

為了應(yīng)對(duì)更為復(fù)雜的對(duì)象合并要求,YUI提供了方法Y.mix()。Y.mix()不能像Y.merge()那樣同時(shí)合并2個(gè)以上的對(duì)象,它的合并對(duì)象數(shù)目限定為2個(gè),對(duì)應(yīng)前2個(gè)參數(shù),此外的參數(shù)都用作合并模式、方法的設(shè)置。Y.mix()搭配其多種模式和配置的控制,可以實(shí)現(xiàn)相當(dāng)精細(xì)的兩個(gè)對(duì)象的合并(方法叫做"mix",所以也稱為混合吧)。

Y.mix()的源碼較多,不直接貼在本文中。YUI官方的注釋寫得很詳細(xì),不過(guò)在這里我也說(shuō)一些我自己的理解。它的源碼形式是:

Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
    // Y.mix() detail
);

Y.mix()有很多參數(shù)。前2個(gè)參數(shù)receiversupplier如字面意思,分別對(duì)應(yīng)合并操作的接收者和提供者。其余4個(gè)參數(shù)的意義分別是:

overwrite,默認(rèn)為false。如果為true則會(huì)開啟屬性覆蓋。也就是說(shuō),默認(rèn)情況下,提供者的屬性是不會(huì)覆蓋接受者的同名屬性的。

whitelist,白名單。可以指定一個(gè)數(shù)組,只有當(dāng)提供者的屬性名包含于白名單數(shù)組內(nèi)時(shí),屬性才會(huì)被拷貝到接受者。

mode,混合模式。可選值0、1、2、3、4分別對(duì)應(yīng)5個(gè)模式。默認(rèn)值為0,是object to object的合并方式。

merge,默認(rèn)為false。如果為true,對(duì)象上的值為引用數(shù)據(jù)類型的屬性(也就是,當(dāng)這是一個(gè)多層次的復(fù)雜對(duì)象時(shí)),每一個(gè)層級(jí)上的對(duì)象都會(huì)依次被合并,而不是被忽略(overwritefalse)或被直接覆蓋(overwritetrue)。

上面的參數(shù)中,overwritemerge的意義比較重要,其他的則一般使用null或默認(rèn)值。為了理解overwritemerge,直接進(jìn)行不同搭配的合并測(cè)試(配置變量和前文一樣)。測(cè)試代碼和結(jié)果如下:

// overwrite = false , merge = false | Y.mix()的最簡(jiǎn)單形式,默認(rèn)值
var config = Y.mix(defaults, userConfig);
// 結(jié)果輸出:
// {volume => 0, quality => normal, control => {left => left, right => right, attack => space}}

// overwrite = true , merge = false
var config = Y.mix(defaults, userConfig, true, null, 0, false);
// 結(jié)果輸出:
// {volume => 0, quality => high, control => {left => a, right => d, extra => e}}

// overwrite = false , merge = true
var config = Y.mix(defaults, userConfig, false, null, 0, true);
// 結(jié)果輸出:
// {volume => 0, quality => normal, control => {left => left, right => right, attack => space, extra => e}}

// overwrite = true , merge = true
var config = Y.mix(defaults, userConfig, true, null, 0, true);
// 結(jié)果輸出:
// {volume => 0, quality => high, control => {left => a, right => d, attack => space, extra => e}}

可以看出,4個(gè)結(jié)果各不相同。從這些結(jié)果的具體情況,可以分析體會(huì)overwritemerge的意義。注意到,當(dāng)兩者都為true時(shí),得到的正是在配置對(duì)象合并中的一個(gè)理想結(jié)果。而當(dāng)overwrite = true, merge = false時(shí),得到的結(jié)果和Y.merge()相同。

閱讀Y.mix()的源碼,可以了解到,merge決定是否進(jìn)行深合并。深合并的實(shí)現(xiàn)原理是遞歸,也就是對(duì)那些需要多層次合并的屬性值(對(duì)象、數(shù)組),再次調(diào)用Y.mix()。overwrite決定是否進(jìn)行覆蓋,這就類似于電腦里做復(fù)制操作時(shí),會(huì)提示同名文件是否覆蓋的選項(xiàng)。

對(duì)于用作配置數(shù)據(jù)的對(duì)象而言,預(yù)期的最佳的合并方式就是允許覆蓋,而且進(jìn)行深合并。因此,Y.mix(defaults, userConfig, true, null, 0, true)即可以得到最適當(dāng)?shù)暮喜⒑蟮呐渲脭?shù)據(jù)。

需要注意的是,Y.mix()直接對(duì)接收者進(jìn)行操作,并返回接收者。所以,和Y.merge()不同,它一定會(huì)影響到作為第一個(gè)參數(shù)的對(duì)象。

如果可以確定配置數(shù)據(jù)是單層次的簡(jiǎn)單配置對(duì)象,那么使用Y.merge()要更簡(jiǎn)單方便。

更多的工具

YUI除了核心包內(nèi)的上面兩個(gè)方法外,還在oop模塊中提供了一些處理對(duì)象的附加工具。其中包括了Y.extend()(單詞意義:擴(kuò)展),Y.augment()(單詞意義:增強(qiáng)),Y.aggregate()(單詞意義:聚合)。它們都類似于對(duì)象合并,而且有趣的是,其源碼中都調(diào)用了Y.mix()方法。

這幾個(gè)方法和前面的有哪些不同呢?本文限于篇幅,只簡(jiǎn)單說(shuō)一些。Y.aggregate()是開啟深合并的Y.mix()的一個(gè)方法糖,Y.extend()則要求參數(shù)是構(gòu)造函數(shù),它操作的是傳入對(duì)象的prototype,并通過(guò)prototype建立繼承關(guān)系(原型鏈),Y.augment()是從提供者拷貝方法到接收者,但它巧妙地隔離了所有拷貝的方法并延遲調(diào)用提供者的構(gòu)造函數(shù),直到你第一次調(diào)用被拷貝上去的新方法。

有些關(guān)系的jQuery.extend()

因?yàn)楸容^近似,所以在這里也提一下jQuery。

如果你寫過(guò)jQuery插件,你肯定知道jQuery.extend()這個(gè)方法。事實(shí)證明,不同的javascript庫(kù),在命名理念上也是各有想法,在此請(qǐng)注意,jQuery.extend()Y.extend()是完全不同的兩個(gè)方法。閱讀jQuery.extend()的源碼可知,它仍然是在做傳統(tǒng)的對(duì)象合并,而且同時(shí)允許聲明一個(gè)可選的邏輯參數(shù)deep,來(lái)指定是否進(jìn)行深合并。其深合并的實(shí)現(xiàn)方法依然是遞歸。

此外,類似于Y.mix(),jQuery.extend()也會(huì)影響到作為接收者的對(duì)象。官方文檔對(duì)此還給了明確說(shuō)明,如果希望不影響原來(lái)的對(duì)象,就使用var object = $.extend({}, object1, object2);這樣以空對(duì)象作為接收者的寫法。

結(jié)語(yǔ)

之所以想到寫這個(gè)話題,大概就是因?yàn)閅UI里有關(guān)對(duì)象合并很有幾個(gè)不同的方法,我已經(jīng)相當(dāng)被它們弄暈了。所以,果斷讀源碼,才能理清這其中的區(qū)別,也算是體會(huì)一下javascript庫(kù)設(shè)立這些不同的方法的本因吧。

默認(rèn)配置 + 用戶配置 → 實(shí)際配置,結(jié)果來(lái)看也是一個(gè)不簡(jiǎn)單的轉(zhuǎn)化計(jì)算式。

(重新編輯自我的博客,原文地址:http://acgtofe.com/posts/2014/07/object-toolkit-in-yui)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87600.html

相關(guān)文章

  • JavaScript模塊化發(fā)展

    摘要:所有依賴這個(gè)模塊的語(yǔ)句,都定義在一個(gè)回調(diào)函數(shù)中,等到所有依賴加載完成之后前置依賴,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。如果將前面的代碼改寫成形式,就是下面這樣定義了一個(gè)文件,該文件依賴模塊,當(dāng)模塊加載完畢之后執(zhí)行回調(diào)函數(shù),這里并沒(méi)有暴露任何變量。 模塊化是我們?nèi)粘i_發(fā)都要用到的基本技能,使用簡(jiǎn)單且方便,但是很少人能說(shuō)出來(lái)但是的原因及發(fā)展過(guò)程。現(xiàn)在通過(guò)對(duì)比不同時(shí)期的js的發(fā)展,將JavaScript模...

    mengbo 評(píng)論0 收藏0
  • JavaScript模塊化開發(fā)演進(jìn)歷程

    摘要:參考精讀模塊化發(fā)展模塊化七日談前端模塊化開發(fā)那點(diǎn)歷史本文先發(fā)布于我的個(gè)人博客模塊化開發(fā)的演進(jìn)歷程,后續(xù)如有更新,可以查看原文。 Brendan Eich用了10天就創(chuàng)造了JavaScript,因?yàn)楫?dāng)時(shí)的需求定位,導(dǎo)致了在設(shè)計(jì)之初,在語(yǔ)言層就不包含很多高級(jí)語(yǔ)言的特性,其中就包括模塊這個(gè)特性,但是經(jīng)過(guò)了這么多年的發(fā)展,如今對(duì)JavaScript的需求已經(jīng)遠(yuǎn)遠(yuǎn)超出了Brendan Eich的...

    anonymoussf 評(píng)論0 收藏0
  • <<編寫可維護(hù)javascript>> 筆記6(避免使用全局變量)

    摘要:執(zhí)行環(huán)境在很多方面都有其獨(dú)特之處全局變量和函數(shù)便是其中之一事實(shí)上的初始執(zhí)行環(huán)境是由多種多樣的全局變量所定義的這寫全局變量在腳本環(huán)境創(chuàng)建之初就已經(jīng)存在了我們說(shuō)這些都是掛載在全局對(duì)象上的全局對(duì)象是一個(gè)神秘的對(duì)象它表示了腳本最外層上下文在瀏覽器中 JavaScript執(zhí)行環(huán)境在很多方面都有其獨(dú)特之處. 全局變量和函數(shù)便是其中之一. 事實(shí)上, js的初始執(zhí)行環(huán)境是由多種多樣的全局變量所定義的,...

    MoAir 評(píng)論0 收藏0
  • 高性能JavaScript(文檔)

    摘要:最近在全力整理高性能的文檔,并重新學(xué)習(xí)一遍,放在這里方便大家查看并找到自己需要的知識(shí)點(diǎn)。 最近在全力整理《高性能JavaScript》的文檔,并重新學(xué)習(xí)一遍,放在這里方便大家查看并找到自己需要的知識(shí)點(diǎn)。 前端開發(fā)文檔 高性能JavaScript 第1章:加載和執(zhí)行 腳本位置 阻止腳本 無(wú)阻塞的腳本 延遲的腳本 動(dòng)態(tài)腳本元素 XMLHTTPRequest腳本注入 推薦的無(wú)阻塞模式...

    RayKr 評(píng)論0 收藏0
  • 精讀《js 模塊化發(fā)展》

    摘要:我是這一期的主持人黃子毅本期精讀的文章是。模塊化需要保證全局變量盡量干凈,目前為止的模塊化方案都沒(méi)有很好的做到這一點(diǎn)。精讀本次提出獨(dú)到觀點(diǎn)的同學(xué)有流形,黃子毅,蘇里約,,楊森,淡蒼,留影,精讀由此歸納。 這次是前端精讀期刊與大家第一次正式碰面,我們每周會(huì)精讀并分析若干篇精品好文,試圖討論出結(jié)論性觀點(diǎn)。沒(méi)錯(cuò),我們?cè)噲D通過(guò)觀點(diǎn)的碰撞,爭(zhēng)做無(wú)主觀精品好文的意見領(lǐng)袖。 我是這一期的主持人 ——...

    Freelander 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<