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

資訊專(zhuān)欄INFORMATION COLUMN

JS凍結(jié)對(duì)象的《人間詞話》 完美實(shí)現(xiàn)究竟有幾層境界?

高勝山 / 2227人閱讀

摘要:王國(guó)維在人間詞話里談到了治學(xué)經(jīng)驗(yàn),他說(shuō)古今之成大事業(yè)大學(xué)問(wèn)者,必經(jīng)過(guò)三種之境界。其中談到中凍結(jié)一個(gè)對(duì)象幾種由淺入深的實(shí)踐。王國(guó)維已先自表明,吾人可以無(wú)勞糾葛。總結(jié)本文先后介紹了關(guān)于凍結(jié)一個(gè)對(duì)象的三種進(jìn)階方法。

王國(guó)維在《人間詞話》里談到了治學(xué)經(jīng)驗(yàn),他說(shuō):“古今之成大事業(yè)、大學(xué)問(wèn)者,必經(jīng)過(guò)三種之境界?!?/p>

巧合的是,最近受 git chat / git book 邀請(qǐng),做了一個(gè)分享。
其中談到JS中凍結(jié)一個(gè)對(duì)象幾種由淺入深的實(shí)踐。想想也暗合國(guó)學(xué)大師所謂的三重境界。

這篇文章由淺入深討論JS中對(duì)象的一些鎖定特性。但都是一些基礎(chǔ)語(yǔ)法的實(shí)現(xiàn),相信即便是前端小白也可以大體領(lǐng)會(huì)。不過(guò)需要讀者預(yù)先了解JS中對(duì)象的特性,尤其是對(duì)象自身屬性的描述符:configurable、writable...

另外,如果您對(duì)JS中對(duì)象操作、不可變數(shù)據(jù)、函數(shù)式編程感興趣,同樣推薦我的其他一些相關(guān)文章:

如何優(yōu)雅安全地在深層數(shù)據(jù)結(jié)構(gòu)中取值

從JS對(duì)象開(kāi)始,談一談“不可變數(shù)據(jù)”和函數(shù)式編程

解析Twitter前端架構(gòu) 學(xué)習(xí)復(fù)雜場(chǎng)景數(shù)據(jù)設(shè)計(jì)

等等。

昨夜西風(fēng)凋碧樹(shù) 獨(dú)上高樓 望盡天涯路

第一種境界:“昨夜西風(fēng)凋碧樹(shù),獨(dú)上高樓,望盡天涯路?!?br>該詞句出自晏殊的《蝶戀花》,原意是說(shuō),“我”上高樓眺望所見(jiàn)的更為蕭颯的秋景,西風(fēng)黃葉,山闊水長(zhǎng),案書(shū)何達(dá)?

王國(guó)維此句中解成:做學(xué)問(wèn)成大事業(yè)者,首先要有執(zhí)著的追求,登高望遠(yuǎn),瞰察路徑,明確目標(biāo)與方向,了解事物的概貌。

我們就從最基本的場(chǎng)景說(shuō)起,究竟為什么要凍結(jié)一個(gè)對(duì)象?

場(chǎng)景一:
我們?cè)炝艘粋€(gè)輪子,對(duì)外暴露一個(gè)對(duì)象,開(kāi)放出來(lái)給第三方使用。同時(shí)需要保證這個(gè)對(duì)外暴露的對(duì)象完全安全,不能被業(yè)務(wù)代碼所改寫(xiě)覆蓋或下鉤子(hook)函數(shù)。

場(chǎng)景二:
如果你看過(guò)Vue 2.* 版本源碼,你會(huì)發(fā)現(xiàn)凍結(jié)一個(gè)對(duì)象的操作頻繁出現(xiàn)。

我們先來(lái)看凍結(jié)對(duì)象的第一層實(shí)現(xiàn) —— 擴(kuò)展特性鎖:

他包含了兩個(gè)基本方法:

Object.isExtensible

Object.preventExtensions

如果一個(gè)對(duì)象可以添加新的屬性,則這個(gè)對(duì)象是可擴(kuò)展的。擴(kuò)展特性鎖就是讓這個(gè)對(duì)象變的不可擴(kuò)展,也就是不能再有新的屬性。

Object.isExtensible

MDN上內(nèi)容概述:

概述
    Object.isExtensible() 方法判斷一個(gè)對(duì)象是否是可擴(kuò)展的(是否可以在它上面添加新的屬性)。
語(yǔ)法
    Object.isExtensible(obj)
參數(shù)
    obj 需要檢測(cè)的對(duì)象

例如,我們正常使用對(duì)象字面量聲明的對(duì)象都是可擴(kuò)展的:

var person1 = {};
person1.name = "Lucas";
console.log(person1);
// {name: "Lucas"}

同時(shí):

Object.isExtensible(person1) === true; // true

你可能要問(wèn)了,那么使用Object.create方法聲明的對(duì)象,并對(duì)該對(duì)象屬性進(jìn)行配置是什么情況呢?
我們知道,用上面對(duì)象字面量聲明的對(duì)象相當(dāng)于:

var person1 = Object.create({},{
    "name":{
        value : "Lucas",
        configurable : true, //不可配置
        enumerable : true , //可枚舉
        writable : true //可寫(xiě)
    }
});

即便嘗試將configurable設(shè)置為false:

var person1 = Object.create({},{
    "name":{
        value : "Lucas",
        configurable : false, //不可配置
        enumerable : true, //可枚舉
        writable : true //可寫(xiě)
    }
});

仍然得到:

Object.isExtensible(person1) === true; // true
Object.preventExtensions

當(dāng)然,我們還是有方法可以使得一個(gè)對(duì)象變的不可擴(kuò)展。

MDN上內(nèi)容概述:

概述
    Object.preventExtensions() 方法讓一個(gè)對(duì)象變的不可擴(kuò)展,也就是永遠(yuǎn)不能再添加新的屬性。
語(yǔ)法
    Object.preventExtensions(obj)
參數(shù)
    obj 將要變得不可擴(kuò)展的對(duì)象

幾個(gè)注意點(diǎn)包括但不限于:

不可擴(kuò)展的對(duì)象的屬性通常仍然可以被刪除。

嘗試給一個(gè)不可擴(kuò)展對(duì)象添加新屬性的操作將會(huì)失敗,不過(guò)可能是靜默失敗,也可能會(huì)拋出 TypeError 異常(嚴(yán)格模式下)。

Object.preventExtensions 只能阻止一個(gè)對(duì)象不能再添加新的自身屬性,仍然可以為該對(duì)象的原型添加屬性。

比如:

var person1 = {
    name: "Lucas"
}

Object.preventExtensions(person1);
person1.age = 18;
// 非嚴(yán)格模式下,這里不會(huì)有報(bào)錯(cuò),屬于靜默失敗
person1.age // undefined
// 擴(kuò)展新屬性失敗了

仍然可以向原型鏈添加屬性:

person1.__proto__.age = 18;
person1.age // 18
// 可以從原型鏈上取到

同樣也可以復(fù)寫(xiě)一些屬性:

person1.name = "Eros";
person1.name // "Eros"

也可以刪除已有屬性:

person1.name; //  "Eros",
delete person1.name;
person1.name; // undefined

通過(guò)以上方法,我們實(shí)現(xiàn)了對(duì)一個(gè)對(duì)象屬性擴(kuò)展的凍結(jié)。但是同樣也認(rèn)識(shí)到,這并不是全面的保護(hù):例如可以隨意改動(dòng)去覆蓋已有屬性,在對(duì)象原型鏈上增加屬性也還是難以屏蔽。

衣帶漸寬終不悔 為伊消得人憔悴

第二種境界:“衣帶漸寬終不悔,為伊消得人憔悴?!?br>這引用的是北宋柳永《蝶戀花》最后兩句詞,原詞是表現(xiàn)作者對(duì)愛(ài)的艱辛和愛(ài)的無(wú)悔。若把“伊”字理解為詞人所追求的理想和畢生從事的事業(yè),亦無(wú)不可。王國(guó)維則別有用心,以此兩句來(lái)比喻成大事業(yè)、大學(xué)問(wèn)者,不是輕而易舉,隨便可得的,必須堅(jiān)定不移,經(jīng)過(guò)一番辛勤勞動(dòng),廢寢忘食,孜孜以求,直至人瘦帶寬也不后悔。

下面介紹一個(gè)更深一層的做法:密封特性。

密封對(duì)象是指那些不能添加新的屬性,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性(enumerable)、可配置性(configurable)、可寫(xiě)性(writable),但可能可以修改已有屬性的值的對(duì)象。

他同樣包含了兩個(gè)基本方法:

Object.isSealed

Object.seal

Object.isSealed

MDN上內(nèi)容概述:

概述 
    Object.isSealed() 方法判斷一個(gè)對(duì)象是否是密封的(sealed)。
語(yǔ)法 
    Object.isSealed(obj)
參數(shù)
    obj 將要檢測(cè)的對(duì)象

正常對(duì)象字面量聲明的對(duì)象是不被密封的:

var person1 = {
    name: "Lucas"
}

Object.isSealed(person1); // false

當(dāng)將這個(gè)對(duì)象禁止擴(kuò)展時(shí),它也不會(huì)變成密封的:

var person1 = {
    name: "Lucas"
}
Object.preventExtensions(person1);
Object.isSealed(person1); // false

但是在此基礎(chǔ)上,使用Object.defineProperty方法,把屬性變得不可配置(configurable),則這個(gè)對(duì)象也就成了密封對(duì)象:

var person1 = {
    name: "Lucas"
}

Object.defineProperty(person1, "name", {configurable : false});

Object.isSealed(person1); // true

此時(shí),我們有:

Object.getOwnPropertyDescriptor(person1, "name");
// 得到:
Object {
    value: "Lucas", 
    writable: true, 
    enumerable: true, 
    configurable: false
}

根據(jù)這個(gè)getOwnPropertyDescriptor,我們可以更加深入的理解密封特性:被密封的對(duì)象,就是在不可擴(kuò)展基礎(chǔ)上講屬性描述符configurable設(shè)置為false; 同時(shí),被密封的對(duì)象,仍然有機(jī)會(huì)改變屬性的值。只不過(guò)對(duì)于此對(duì)象本身而言,不可以再擴(kuò)展新的屬性,不可以更改已有屬性的配置信息。

Object.seal

相對(duì)應(yīng)我們也有一個(gè)方法將一個(gè)對(duì)象密封。

MDN上內(nèi)容概述:

概述
    Object.seal() 方法可以讓一個(gè)對(duì)象密封,并返回被密封后的對(duì)象。
語(yǔ)法
    Object.seal(obj)
參數(shù)
    obj 將要被密封的對(duì)象

比如:

var person1 = {
    name: "Lucas"
}
Object.getOwnPropertyDescriptor(person1, "name");
// 得到:
Object {
    value: "Lucas", 
    writable: true, 
    enumerable: true, 
    configurable: true
}

將此對(duì)象密封后:

Object.seal(person1);
Object.getOwnPropertyDescriptor(person1, "name");
// 得到:
Object {
    value: "Lucas", 
    writable: true, 
    enumerable: true, 
    configurable: false
}

也就是說(shuō):

person1.age = 18;
person1.age; // undefined
// 擴(kuò)展新屬性失敗

// 同時(shí)調(diào)用defineProperty失敗
Object.defineProperty(person1,"name",{get : function(){return "g";}});
// 拋出異常

任何除更改屬性值以外的操作,非嚴(yán)格模式下都會(huì)靜默失敗,如上并如下:

delete person1.name;
person1.name; // "Lucas"

而更改屬性值可以成功:

person1.name = "Eros";
person1.name; // "Eros"

怎么理解這樣的現(xiàn)象呢?牢記,被密封的對(duì)象擁有如下的屬性描述符:

Object {
    value: "Lucas", 
    writable: true, 
    enumerable: true, 
    configurable: false
}

而刪除屬性屬于configurable,更改屬性才屬于writable;

一點(diǎn)延伸

借助于此,我們其實(shí)已經(jīng)可以完成凍結(jié)對(duì)象的第三重境界:達(dá)到即密封又不可修改原屬性值。因?yàn)榭梢赃@樣做:

var person1 = {name: "Lucas"};
Object.defineProperty(person1, "name", {configurable: false, writable: false});
Object.preventExtensions(o);

總結(jié)下就是設(shè)置:

configurable: false + writable: false + preventExtensions

或者因?yàn)?/p>

configurable: false+ preventExtensions = seal

所以也可以設(shè)置:

seal + writable: false

眾里尋他千百度,驀然回首,那人卻在,燈火闌珊處

第三種境界:“眾里尋他千百度,驀然回首,那人卻在,燈火闌珊處?!?br>這是引用南宋辛棄疾《青玉案》詞中的最后四句。梁?jiǎn)⒊Q(chēng)此詞“自憐幽獨(dú),傷心人別有懷抱”。這是借詞喻事,與文學(xué)賞析已無(wú)交涉。王國(guó)維已先自表明,“吾人可以無(wú)勞糾葛”。他以此詞最后的四句為“境界”之第三,即最終最高境界。

這雖不是辛棄疾的原意,但也可以引出悠悠的遠(yuǎn)意:做學(xué)問(wèn)、成大事業(yè)者,要達(dá)到第三境界,必須有專(zhuān)注的精神。反復(fù)追尋、研究,下足功夫,自然會(huì)豁然貫通,有所發(fā)現(xiàn),有所發(fā)明,就能夠從必然王國(guó)進(jìn)入自由王國(guó)。

上邊那種凍結(jié)對(duì)象的方法,其實(shí)也有原生實(shí)現(xiàn),可謂:“眾里尋他千百度,驀然回首,那人卻在,燈火闌珊處”

我們這里所說(shuō)的一個(gè)對(duì)象的凍結(jié)(frozen)是指它不可擴(kuò)展,所有屬性都是不可配置的(non-configurable),且所有數(shù)據(jù)屬性(data properties)都是不可寫(xiě)的(non-writable)。

或者說(shuō),凍結(jié)對(duì)象是指那些不能添加新的屬性,不能修改已有屬性的值,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫(xiě)性的對(duì)象。也就是說(shuō),這個(gè)對(duì)象永遠(yuǎn)是不可變的。

同樣,包含了兩個(gè)基本方法:

Object.isFrozen

Object.freeze

Object.isFrozen

MDN上內(nèi)容概述:

概述
    Object.isFrozen() 方法判斷一個(gè)對(duì)象是否被凍結(jié)(frozen)。
語(yǔ)法
    Object.isFrozen(obj)
參數(shù)
    obj 被檢測(cè)的對(duì)象
Object.freeze 方法

MDN上內(nèi)容概述:

概述
    Object.freeze() 方法可以?xún)鼋Y(jié)一個(gè)對(duì)象。
語(yǔ)法
    Object.freeze(obj)
參數(shù)
    obj 將要被凍結(jié)的對(duì)象

可以先理解為,這是最高一層的凍結(jié)對(duì)象:

var person1 = {
    name: "Lucas"
}

Object.freeze(person1);

此時(shí),我們有:

Object.getOwnPropertyDescriptor(person1, "name")

Object {
    value: "Lucas", 
    writable: false, 
    enumerable: true, 
    configurable: false
}

// 對(duì)凍結(jié)對(duì)象的任何操作都會(huì)失敗
person1.name = "Eros"; // 改寫(xiě)屬性值,非嚴(yán)格模式下靜默失敗;
person1.age = 18; // 擴(kuò)展屬性值,非嚴(yán)格模式下靜默失敗;
Object.defineProperty(person1,"name",{value: "Eros"}); // 使用defineProperty會(huì)直接報(bào)錯(cuò)

改寫(xiě)屬性值,擴(kuò)展新屬性,調(diào)用defineProperty,全部都會(huì)失敗。

但是,這種層面的凍結(jié),只是淺凍結(jié)。如果對(duì)象里面還嵌套有對(duì)象,那么這個(gè)內(nèi)部對(duì)象絲毫不受影響。

var person1 = {
    name: "Lucas",
    family: {
        brother: "Eros"
    }
}

Object.freeze(person1);

person1.family.brother = "Tim";
person1.family.brother // "Tim"
終極實(shí)現(xiàn)

那么,如果我們想深層次凍結(jié)一個(gè)對(duì)象呢?思路和深拷貝暗合,使用遞歸:

Object.prototype.deepFreeze = Object.prototype.deepFreeze || function (o){
    var prop, propKey;
    Object.freeze(o); // 首先凍結(jié)第一層對(duì)象
    for (propKey in o){
        prop = o[propKey];
        if(!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)){
            continue;
        }
        deepFreeze(prop); // 遞歸
    }
}

這樣子,我們?cè)倩剡^(guò)頭來(lái)看:

var person1 = {
    name: "Lucas",
    family: {
        brother: "Eros"
    }
}

Object.deepFreeze(person1);

person1.family.brother = "Tim";
person1.family.brother // "Eros"

已經(jīng)達(dá)到了深層次對(duì)象屬性的凍結(jié)。

總結(jié)

本文先后介紹了關(guān)于凍結(jié)一個(gè)對(duì)象的三種進(jìn)階方法。他們層層遞進(jìn),卻又相互關(guān)聯(lián)。關(guān)系如圖:

文章部分概念粘取了MDN語(yǔ)法介紹和Tomson的文章。

在《文學(xué)小言》一文中,王國(guó)維把上述三境界說(shuō)成“三種之階級(jí)”。并說(shuō):“未有不閱第一第二階級(jí)而能遽躋第三階級(jí)者,文學(xué)亦然。此有文學(xué)上之天才者,所以又需莫大之修養(yǎng)也。”

與大家共勉。

Happy coding!

PS: 作者Github倉(cāng)庫(kù),歡迎通過(guò)代碼各種形式交流。

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

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

相關(guān)文章

  • JS凍結(jié)對(duì)象人間詞話完美實(shí)現(xiàn)究竟幾層境界?

    摘要:王國(guó)維在人間詞話里談到了治學(xué)經(jīng)驗(yàn),他說(shuō)古今之成大事業(yè)大學(xué)問(wèn)者,必經(jīng)過(guò)三種之境界。其中談到中凍結(jié)一個(gè)對(duì)象幾種由淺入深的實(shí)踐。王國(guó)維已先自表明,吾人可以無(wú)勞糾葛。總結(jié)本文先后介紹了關(guān)于凍結(jié)一個(gè)對(duì)象的三種進(jìn)階方法。 王國(guó)維在《人間詞話》里談到了治學(xué)經(jīng)驗(yàn),他說(shuō):古今之成大事業(yè)、大學(xué)問(wèn)者,必經(jīng)過(guò)三種之境界。 巧合的是,最近受 git chat / git book 邀請(qǐng),做了一個(gè)分享。其中談到J...

    YorkChen 評(píng)論0 收藏0
  • 2017-06-07 前端日?qǐng)?bào)

    摘要:程序員英語(yǔ)提升指南深入理解內(nèi)部機(jī)制即將到來(lái),現(xiàn)在該考慮新的打包方案了嘛凍結(jié)對(duì)象的人間詞話完美實(shí)現(xiàn)究竟有幾層境界關(guān)于響應(yīng)式的另一種思考 程序員英語(yǔ)提升指南 深入理解 Node Stream 內(nèi)部機(jī)制 ES6 modules 即將到來(lái),現(xiàn)在該考慮新的打包方案了嘛? JS 凍結(jié)對(duì)象的《人間詞話》 完美實(shí)現(xiàn)究竟有幾層境界? 關(guān)于響應(yīng)式的另一種思考 Best websites a program...

    rose 評(píng)論0 收藏0
  • 「能寫(xiě)代碼」是愚公移山,「會(huì)寫(xiě)代碼」是女?huà)z補(bǔ)天

    摘要:從能力上分,一個(gè)是搬運(yùn)工,一個(gè)是設(shè)計(jì)者能寫(xiě)代碼是愚公移山為什么說(shuō)能寫(xiě)代碼是愚公移山呢我們中國(guó)大部分程序員都應(yīng)該處于一個(gè)初級(jí)程序員的水平,怎么講只有少數(shù)的程序員處于中高級(jí)水平。 導(dǎo)語(yǔ):你知道普通程序員和優(yōu)秀程序員之間的差距嗎?其實(shí)答案很簡(jiǎn)單,那就是「愚公移山」和「女?huà)z補(bǔ)天」之間的區(qū)別。 之所以提這個(gè)話題,跟前兩天在微信群里的討論有關(guān),年后本該是跳槽、找工作的高峰月份,各公司面試邀約應(yīng)該很...

    ghnor 評(píng)論0 收藏0
  • 遷移學(xué)習(xí)在圖像分類(lèi)中簡(jiǎn)單應(yīng)用策略

    摘要:地址為什么使用遷移學(xué)習(xí)根據(jù)聯(lián)合創(chuàng)始人斯坦福副教授吳恩達(dá)介紹,遷移學(xué)習(xí)將會(huì)成為機(jī)器學(xué)習(xí)商業(yè)成就的下一驅(qū)動(dòng)力。遷移學(xué)習(xí)是一種機(jī)器學(xué)習(xí)技術(shù),允許在特定的數(shù)據(jù)集上再利用已訓(xùn)練的卷積神經(jīng)網(wǎng)絡(luò),并將其調(diào)整或遷移到其他數(shù)據(jù)集。 GitHub 地址:https://github.com/miguelgfierro/sciblog_support/blob/master/A_Gentle_Introducti...

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

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

0條評(píng)論

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