欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

你必須了解的JavaScript中的屬性描述對象詳解(下)

 更新時間:2022年12月22日 14:01:13   作者:程序小猿2  
JavaScript提供了一個內部數(shù)據(jù)結構,用來描述對象的屬性,控制它的行為,比如該屬性是否可寫、可遍歷等等。這個內部數(shù)據(jù)結構稱為“屬性描述對象”。本文主要帶大家了解一下JavaScript中你必須了解的屬性描述對象,需要的可以參考一下

元屬性

value

value屬性是目標屬性的值。

var obj = {};
obj.p = 123;

Object.getOwnPropertyDescriptor(obj,'p').value
// 123

Object.defineProperty(obj,'p',{value:246});
obj.p //246

上面代碼是通過value屬性,讀取或改寫obj.p的例子。

writable

writable屬性是一個布爾值,決定了目標屬性的值(value)是否可以被改變。

var obj = {};

Object.defineProperty(obj, 'a',{
    value:37,
    writable:false
});

obj.a //37
obj.a = 25;
obj.a //37

上面代碼中,obj.awritable屬性是false。然后,改變obj.a的值,不會有任何效果。

注意,正常模式下,對writablefalse的屬性賦值不會報錯,只會默默失敗。但是,嚴格模式下會報錯,即使對a屬性重新賦予一個同樣的值。

// ‘use strict'
var obj = {};

Object.defineProperty(obj,'a',{
    value:37,
    writable:false
});

obj.a = 37;
// Uncaught TypeError: Cannot assign to read only property 'a' of object

上面代碼是嚴格模式,對obj.a任何賦值行為都會報錯。

如果原型對象的某個屬性的writablefalse,那么子對象將無法自定義這個屬性。

var proto = Object.defineProperty({},'foo',{
    value:'a',
    writable:false
});

var obj = Object.create(proto);

obj.foo = 'b';
obj.foo //'a'

上面代碼中,proto是原型對象,它的foo屬性不可寫。obj對象繼承proto,也不可以再自定義這個屬性了。如果是嚴格模式,這樣做還會拋出一個錯誤。

但是,有一個規(guī)避方法,就是通過覆蓋屬性描述對象,繞過這個限制。原因是這種情況下,原型鏈會被完全忽視。

var proto = Object.defineProperty({},'foo',{
    value:'a',
    writable:false
});

var obj = Object.create(proto);
Object.defineProperty(obj,'foo',{
    value:'b'
});

obj.foo //"b"

enumerable

enumerable(可遍歷性)返回一個布爾值,表示目標屬性是否可遍歷。

JavaScript 的早期版本,for...in循環(huán)是基于in運算符的。我們知道,in運算符不管某個屬性是對象自身的還是繼承的,都會返回true。

var obj = {};
'totring' in obj //true

上面代碼中,toString不是obj對象自身的屬性,但是in運算符也返回true,這導致了toString屬性也會被for...in循環(huán)遍歷。

這顯然不太合理,后來就引入了“可遍歷性”這個概念。只有可遍歷的屬性,才會被for...in循環(huán)遍歷,同時還規(guī)定toString這一類實例對象繼承的原生屬性,都是不可遍歷的,這樣就保證了for...in循環(huán)的可用性。

具體來說,如果一個屬性的enumerablefalse,下面三個操作不會取到該屬性。

  • for..in循環(huán)
  • Object.keys方法
  • JSON.stringify方法

因此,enumerable可以用來設置“秘密”屬性。

var obj = {};

Object.defineProperty(obj,'x',{
    value:123;
    enumerable:false
});

obj.x //123

for(var key in obj){
    console.log(key);
}
//undefined

Object.keys(obj) //[]
JSON.stringify(obj) //"{}"

上面代碼中,obj.x屬性的enumerablefalse,所以一般的遍歷操作都無法獲取該屬性,使得它有點像“秘密”屬性,但不是真正的私有屬性,還是可以直接獲取它的值。

注意,for...in循環(huán)包括繼承的屬性,Object.keys方法不包括繼承的屬性。如果需要獲取對象自身的所有屬性,不管是否可遍歷,可以使用Object.getOwnPropertyNames方法。

另外,JSON.stringify方法會排除enumerablefalse的屬性,有時可以利用這一點。如果對象的 JSON 格式輸出要排除某些屬性,就可以把這些屬性的enumerable設為false。

configurable

configurable(可配置性)返回一個布爾值,決定了是否可以修改屬性描述對象。也就是說,configurablefalse時,valuewritable、enumerableconfigurable都不能被修改了。

var obj = Object.defineProperty({},'p',{
    value:1,
    writable:false,
    enumerable:false,
    configurable:false
});

Object.defineProperty(obj,'p',{value:2})
//TypeError:Cannot redefine property:p

Object.defineProperty(obj,'p',{writable:true})
//TypeError:Cannot redefine property:p

Object.definetyProperty(obj,'p',{enumerable:true})
//TypeError:Cannot redefine property:p

Object.defineProperty(obj,'p',{configurable:true})
//TypeError:Cannot redefine property:p

上面代碼中,obj.pconfigurablefalse。然后,改動value、writable、enumerableconfigurable,結果都報錯。

注意,writable只有在false改為true會報錯,true改為false是允許的。

var obj = Object.defineProperty({},'p',{
    writable:true,
    configurable:false
});

Object.defineProperty(obj,'p',{writable:false})
//修改成功

至于value,只要writableconfigurable有一個為true,就允許改動。

var o1 = Object.defineProperty({},'p',{
    value:1,
    writable:true,
    configurable:false
});

Object.defineProperty(o1,'p',{value:2})
//修改成功

var o2 = Object.defineProperty({},'p',{
    value:1,
    writable:false,
    configurable:true
});

Object.defineProperty(o2,'p',{value:2})
//修改成功

另外,writablefalse時,直接目標屬性賦值,不報錯,但不會成功。

var obj = Object.defineProperty({},'p',{
    value:1,
    writable:false,
    configurable:false
});

obj.p = 2;
obj.p //1

上面代碼中,obj.pwritablefalse,對obj.p直接賦值不會生效。如果是嚴格模式,還會報錯。

可配置性決定了目標屬性是否可以被刪除(delete)。

var obj = Object.defineProperties({},{
    p1:{ value:1,configurable:true},
    p2:{ value:2,configurable:false}
});

delete obj.p1 // true
delete obj.p2 // false

obj.p1 //undefined
obj.p2 //2

上面代碼中,obj.p1configurabletrue,所以可以被刪除,obj.p2就無法刪除。

存取器

除了直接定義以外,屬性還可以用存取器(accessor)定義。其中,存值函數(shù)稱為setter,使用屬性描述對象的set屬性;取值函數(shù)稱為getter,使用屬性描述對象的get屬性。

一旦對目標屬性定義了存取器,那么存取的時候,都將執(zhí)行對應的函數(shù)。利用這個功能,可以實現(xiàn)許多高級特性,比如定制屬性的讀取和賦值行為。

var obj = Object.defineProperty({},'p',{
    get:function(){
        return 'getter';
    },
    set:function(value){
        console.log('setter:' + value);
    }
});

obj.p //"getter"
obj.p = 123 //"setter: 123"

上面代碼中,obj.p定義了getset屬性。obj.p取值時,就會調用get;賦值時,就會調用set。

JavaScript 還提供了存取器的另一種寫法。

// 寫法二
var obj = {
    get p() {
        return 'getter';
    },
    set p(value) {
        console.log('setter: ' + value);
    }
};

上面兩種寫法,雖然屬性p的讀取和賦值行為是一樣的,但是有一些細微的區(qū)別。第一種寫法,屬性pconfigurableenumerable都為false,從而導致屬性p是不可遍歷的;第二種寫法,屬性pconfigurableenumerable都為true,因此屬性p是可遍歷的。實際開發(fā)中,寫法二更常用。

注意,取值函數(shù)get不能接受參數(shù),存值函數(shù)set只能接受一個參數(shù)(即屬性的值)。

存取器往往用于,屬性的值依賴對象內部數(shù)據(jù)的場合。

var obj ={
    $n : 5,
    get next(){ return this.$n++ },
    set next(n){
        if(n >= this.$n)this.$n = n;
        else throw new Error('新的值必須大于當前值‘);
    }
 };
 
 obj.next //5
 
 obj.next = 10;
 obj.next //10
 
 obj.next = 5;
 //Uncaught Error:新的值必須大于當前值

上面代碼中,next屬性的存值函數(shù)和取值函數(shù),都依賴于內部屬性$n。

對象的拷貝

有時,我們需要將一個對象的所有屬性,拷貝到另一個對象,可以用下面的方法實現(xiàn)。

var extend = function(to,from){
    for(var property in from){
        to[property] = from[property];
    }
    
    return to;
}

extend({},{
    a:1
})
//{a:1}

上面這個方法的問題在于,如果遇到存取器定義的屬性,會只拷貝值。

extend({},{
    get a() { return 1 }
})
//{a:1}

為了解決這個問題,我們可以通過Object.defineProperty方法來拷貝屬性。

var extend = function (to, from) {
    for (var property in from) {
        if (!from.hasOwnProperty(property)) continue;
        Object.defineProperty(
            to,
            property,
            Object.getOwnPropertyDescriptor(from, property)
        );
    }
    return to;
}
extend({}, { get a(){ return 1 } })
// { get a(){ return 1 } })

上面代碼中,hasOwnProperty那一行用來過濾掉繼承的屬性,否則可能會報錯,因為Object.getOwnPropertyDescriptor讀不到繼承屬性的屬性描述對象。

控制對象狀態(tài)

有時需要凍結對象的讀寫狀態(tài),防止對象被改變。JavaScript 提供了三種凍結方法,最弱的一種是Object.preventExtensions,其次是Object.seal,最強的是Object.freeze。

Object.preventExtensions()

Object.preventExtensions方法可以使得一個對象無法再添加新的屬性。

var obj = new Object();
Object.preventExtensions(obj);

Object.defineProperty(obj,'p',{
    value:'hello'
});
// TypeError:Cannot define property:p,object is not extensible.

obj.p = 1;
obj.p .. undefined

上面代碼中,obj對象經(jīng)過Object.preventExtensions以后,就無法添加新屬性了。

Object.isExtensible()

Object.isExtensible方法用于檢查一個對象是否使用了Object.preventExtensions方法。也就是說,檢查是否可以為一個對象添加屬性。

var obj = new Object();

Object.isExtensible(obj) // true
Object.preventExtensions(obj);
Object.isExtensible(obj) // false

上面代碼中,對obj對象使用Object.preventExtensions方法以后,再使用Object.isExtensible方法,返回false,表示已經(jīng)不能添加新屬性了。

Object.seal()

Object.seal方法使得一個對象既無法添加新屬性,也無法刪除舊屬性。

var obj = { p:'hello' };
Object.seal(obj);

delete obj.p;
obj.p //"hello"

obj.x = 'world';
obj.x // undefined

上面代碼中,obj對象執(zhí)行Object.seal方法以后,就無法添加新屬性和刪除舊屬性了。

Object.seal實質是把屬性描述對象的configurable屬性設為false,因此屬性描述對象不再能改變了。

var obj = {
    p: 'a'
};

// seal方法之前
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
// value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }

Object.seal(obj);

// seal方法之后
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
// value: "a",
// writable: true,
// enumerable: true,
// configurable: false
// }

Object.defineProperty(o, 'p', {
    enumerable: false
})
// TypeError: Cannot redefine property: p

上面代碼中,使用Object.seal方法之后,屬性描述對象的configurable屬性就變成了false,然后改變enumerable屬性就會報錯。

Object.seal只是禁止新增或刪除屬性,并不影響修改某個屬性的值。

var obj = {p:'a'};
Object.seal(obj);
obj.p = 'b';
obj.p //'b'

上面代碼中,Object.seal方法對p屬性的value無效,是因為此時p屬性的可寫性由writable決定。

Object.isSealed()

Object.isSealed方法用于檢查一個對象是否使用了Object.seal方法。

var obj = { p: 'a' };

Object.seal(obj);
Object.isSealed(obj) // true

這時,Object.isExtensible方法也返回false。

var obj = { p: 'a' };

Object.seal(obj);
Object.isExtensible(obj) // false

Object.freeze()

Object.freeze方法可以使得一個對象無法添加新屬性、無法刪除舊屬性、也無法改變屬性的值,使得這個對象實際上變成了常量。

var obj = {  
    p: 'hello'
};
    
Object.freeze(obj);

obj.p = 'world';
obj.p // "hello"

obj.t = 'hello';
obj.t // undefined

delete obj.p // false
obj.p // "hello"

上面代碼中,對obj對象進行Object.freeze()以后,修改屬性、新增屬性、刪除屬性都無效了。這些操作并不報錯,只是默默地失敗。如果在嚴格模式下,則會報錯。

Object.isFrozen()

Object.isFrozen方法用于檢查一個對象是否使用了Object.freeze方法。

var obj = {  
    p: 'hello'
};

Object.freeze(obj);
Object.isFrozen(obj) // true

使用Object.freeze方法以后,Object.isSealed將會返回true,Object.isExtensible返回false

var obj = {  
    p: 'hello'
};
Object.freeze(obj);

Object.isSealed(obj) // true
Object.isExtensible(obj) // false

Object.isFrozen的一個用途是,確認某個對象沒有被凍結后,再對它的屬性賦值。

var obj = {  
    p: 'hello'
};

Object.freeze(obj);
if (!Object.isFrozen(obj)) {  
    obj.p = 'world';
}

上面代碼中,確認obj沒有被凍結后,再對它的屬性賦值,就不會報錯了。

局限性

上面的三個方法鎖定對象的可寫性有一個漏洞:可以通過改變原型對象,來為對象增加屬性。

var obj = new Object();
Object.preventEctensions(obj);

var proto = Object.getPrototypeOf(obj);
proto.t = 'hello';
obj.t
//hello

上面代碼中,對象obj本身不能新增屬性,但是可以在它的原型對象上新增屬性,就依然能夠在obj上讀到。

一種解決方案是,把obj的原型也凍結住。

var obj = new Object();
Object.preventExtensions(obj);

var proto = Object.getPrototypeOf(obj);
Object.preventExtensions(proto);

proto.t = 'hello';
obj.t //undefined

另外一個局限是,如果屬性值是對象,上面這些方法只能凍結屬性指向的對象,而不能凍結對象本身的內容。

var obj = {
    foo:1,
    bar:['a','b']
};
Object.freeze(obj);

obj.bar.push('c');
obj.bar // ["a',"b","c"]

上面代碼中,obj.bar屬性指向一個數(shù)組,obj對象被凍結以后,這個指向無法改變,即無法指向其他值,但是所指向的數(shù)組是可以改變的。

以上就是你必須了解的JavaScript中的屬性描述對象詳解(下)的詳細內容,更多關于JavaScript屬性描述對象的資料請關注腳本之家其它相關文章!

相關文章

  • uniapp?App端使用高德地圖超詳細步驟

    uniapp?App端使用高德地圖超詳細步驟

    地圖現(xiàn)在已經(jīng)滲入到生活的方方面面,給生活帶了極大的編譯,那么我們如何才能在項目中引入地圖呢?這篇文章主要給大家介紹了關于uniapp?App端使用高德地圖超詳細步驟的相關資料,需要的朋友可以參考下
    2023-11-11
  • JavaScript實現(xiàn)簡易加法計算器

    JavaScript實現(xiàn)簡易加法計算器

    這篇文章主要介紹了JavaScript實現(xiàn)簡易加法計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • JS實現(xiàn)按比例縮放圖片的方法(附C#版代碼)

    JS實現(xiàn)按比例縮放圖片的方法(附C#版代碼)

    這篇文章主要介紹了JS實現(xiàn)按比例縮放圖片的方法,結合實例形式較為詳細的分析了JavaScript實現(xiàn)等比例縮放圖片的原理與具體實現(xiàn)技巧,并附上C#版的圖片縮放代碼做對比參考,需要的朋友可以參考下
    2015-12-12
  • JavaScript實現(xiàn)隨機生成驗證碼及校驗

    JavaScript實現(xiàn)隨機生成驗證碼及校驗

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)隨機生成驗證碼及校驗,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • javascript實現(xiàn)無法關閉的彈框

    javascript實現(xiàn)無法關閉的彈框

    本文分享了javascript實現(xiàn)無法關閉的彈框的實例代碼,感興趣的朋友可以看下
    2016-11-11
  • 解決layui的input獨占一行的問題

    解決layui的input獨占一行的問題

    今天小編就為大家分享一篇解決layui的input獨占一行的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • Javascript的構造函數(shù)和constructor屬性

    Javascript的構造函數(shù)和constructor屬性

    我們知道,默認情況下,對一個函數(shù)前面使用new,可以構造出一個對象。每一個對象都有一個constructor屬性,這個constructor屬性指向構造出該對象的函數(shù)。
    2010-01-01
  • JS解決?Array.fill()參數(shù)為對象指向同一個引用地址的問題

    JS解決?Array.fill()參數(shù)為對象指向同一個引用地址的問題

    這篇文章主要介紹了JS解決?Array.fill()參數(shù)為對象指向同一個引用地址問題,解決方案使用map返回出不同的引用的地址,fill參數(shù)可隨意填寫(不為空),主要是map函數(shù)中返回的數(shù)據(jù),需要的朋友可以參考下
    2023-02-02
  • Javascript節(jié)點關系實例分析

    Javascript節(jié)點關系實例分析

    這篇文章主要介紹了Javascript節(jié)點關系,實例分析了javascript操作父子節(jié)點及兄弟節(jié)點的相關技巧,需要的朋友可以參考下
    2015-05-05
  • javascript代碼壓縮工具的原理

    javascript代碼壓縮工具的原理

    JavaScript代碼壓縮對代碼進行一系列優(yōu)化處理,從而減小代碼的體積,提高網(wǎng)頁的加載速度,JavaScript代碼壓縮的原理包含去除代碼中的空格、注釋、不必要的換行符等無用字符,壓縮變量名、壓縮函數(shù)名等操作,將一些常見的操作(如+、-、*、/)轉換成更短的操作符(如@、^、#、|)
    2023-12-12

最新評論