资讯专栏INFORMATION COLUMN

js知识梳理1:理解对象的属性特性

13651657101 / 2303人阅读

摘要:对象直接量的默认值表示能否通过循环返回属性。同样密封对象操作是不可逆的。代表未冻结已冻结属性特性规则总结如果对象是不可拓展的,则可以编辑已有的自有属性,但不能给它添加新属性。

写在前面

注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者。有发现什么问题的,欢迎留言指出。

1.数据属性

数据属性的4个特性:

Configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为访问器属性。对象直接量里默认值true。

Enumerable:表示能否通过for-in循环返回属性。对象直接量里默认值true。

Writable:表示能否修改属性的值。对象直接量里默认值true。

Value:包含这个属性的数据值。对象直接量里默认值undefined。

//查看对象直接量的属性的属性特性默认值
var people = {
    name:"jaychou",
    sayName:function () {
        console.log(this.name);
    }
};
/**{value: "jaychou", writable: true, enumerable: true, configurable: true}*/
console.log(Object.getOwnPropertyDescriptor(people,"name"));
/**{value: ƒ, writable: true, enumerable: true, configurable: true}*/
console.log(Object.getOwnPropertyDescriptor(people,"sayName"));
//getOwnPropertyDescriptor对于继承属性和不存在的属性,返回undefined

要修改属性默认的特性,使用Object.defineProperty()方法,接收3个参数:对象,属性名字和描述符对象。

//修改属性默认特性:
Object.defineProperty(person,"job",{
    emumerable:false,//不可枚举
    value:"singer",
    writable:false,//不可写
    configurable:true
});
/**{name: "jaychou", sayName: ƒ, job: "singer"}*/
console.log(person);
for(var prop in person){
    //打印name,sayName
    console.log(prop);
}
//会报错
try{
    person.job = "director";
}catch (e) {
    //Cannot assign to read only property "job" of object
    console.log(e);
}

可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false之后就会有限制了:

Object.defineProperty(person,"height",{
    configurable:false,//不可配置
    writable:true,
    value:172
});
try{
    Object.defineProperty(person,"height",{
        configurable:true,//出错
        enumerable:true,//出错
        value:175,//正常
        writable:false,//writable从true变false可以,false变true也会出错
    });
}catch (e) {
    //Cannot redefine property: height at Function.defineProperty
    console.log(e);
}
try{
    delete person.height;
}catch (e) {
    //设置成不可配置后也不可删除:Cannot delete property "height" of #
    console.log(e);
}

另外,调用 Object.defineProperty()方法时,如果不指定,configurable、enumerable 和 writable 特性的默认值都是 false。如果是修改已有属性,则无此限制。

2.存储器属性

存储器属性不包含数据值,只包含包含 getter 和 setter 函数(非必需)。 在读取存储器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入存储器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。4个属性特性如下:

Configurable:①表示能否通过delete删除属性从而重新定义,②能否修改属性的特性,③能否把属性修改为数据属性。对象直接量的默认值true

Enumerable:表示能否通过for-in循环返回属性。对象直接量的默认值true

Get:在读取属性时调用的函数。对象直接量默认值undefined

Set:在写入属性时调用的函数。对象直接量的默认值undefined

定义存储器属性最简单的方法是使用对象直接量语法的拓展写法:

var p = {
    x:3.0,
    y:4.0,
    //r是可读写的存取器属性
    get r(){return Math.sqrt(this.x*this.x+this.y*this.y);},
    set r(newValue){
        var oldvalue = Math.sqrt(this.x*this.x+this.y*this.y);
        var ratio = newValue/oldvalue;
        this.x *= ratio;
        this.y *= ratio;
    },
    //theta是只读存取器属性
    get theta(){return Math.atan2(this.y,this.x);}
}
console.log(p.r);
p.r = 25;

使用Object.defineProperty()方法定义存储器属性:

var book = {
    _year:2004,
    edition:1
};
Object.defineProperty(book,"year",{
    get:function () { return this._year; },
    set:function (newValue) {
        if(newValue>2004){
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    }
})
/**{get: ƒ, set: ƒ, enumerable: false, configurable: false}*/
console.log(Object.getOwnPropertyDescriptor(book,"year"));

如例子所示,使用存储器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。还有一种常见就是现在流行的类似于Vue的响应式原理,就是把data中的属性都使用defineProperty修改为存储器属性,可以监听到数据的变化。

3.定义多个属性

经常要创建或修改多个属性,这时候可以使用Object.defineProperties()方法,它接收2个参数,要添加或修改属性的对象和一个映射表,包含名称和属性描述符。

var book1 = {};
Object.defineProperties(book1,{
   _year:{
       value:"2008"
   },
   editor:{
       enumerable:true,
       value:"2"
   },
   year:{
       get:function () {
           return this._year;
       },
       set:function (newValue) {
           this._year = newValue;
           this.edition += newValue - 2004;
       }
   }
});
4.对象的可扩展性

对象的可拓展性表示是否可以给对象添加新属性。所有内置对象和自定义对象都是显式可扩展的,宿主对象的可扩展性是由Javascript引擎定义的。

1.查询对象可拓展性
var teacher = {age:25};
//true:代表可拓展
console.log(Object.isExtensible(teacher));
2.转换为不可拓展(“锁定对象”)
Object.preventExtensions(teacher);
//false
console.log(Object.isExtensible(teacher));
try{
    teacher.subject = "math";
}catch (e) {
    //TypeError: Cannot add property subject, object is not extensible
    console.log(e);
}

转换成不可拓展的操作是不可逆的,而且只能影响到对象本身的可拓展性,如果给一个不可拓展对象的原型添加属性,这个不可拓展对象同样会继承这些新属性。

5.密封对象

密封对象比锁定对象更高一层,除了不可拓展以外,对象的所有自身属性都设置成了不可配置的。同样密封对象操作是不可逆的。

var tea1 = {subject:"math"};
//false:代表未密封
console.log(Object.isSealed(tea1));
Object.seal(tea1);
try{
    Object.defineProperty(tea1,"subject",{
        //enumerable:false,//出错
        //configurable:true,//出错
        writable:false//和上面说的一样,writable从true变成false可以,false变成true则出错
    });
}catch (e) {
    console.log("出错..");
    console.log(e);
}
//true:已密封
console.log(Object.isSealed(tea1));
6.冻结对象

冻结比密封对象多的效果是:可以将它自有的所有数据属性设置为只读(如果对象的存取器属性具有setter方法,存取器属性将不受影响,仍可以通过给属性赋值调用它们)。

var tea2 = {subject:"Chinese"};
//false:代表未冻结
console.log(Object.isFrozen(tea2));
Object.freeze(tea2);
try{
    tea2.subject = "math";
}catch (e) {
    //TypeError: Cannot assign to read only property "subject" of object
    console.log(e);
}
//true:已冻结
console.log(Object.isFrozen(tea2));
7.属性特性规则总结

如果对象是不可拓展的,则可以编辑已有的自有属性,但不能给它添加新属性。

如果属性是不可配置的,则不能修改它的可配置性和可枚举性。

如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性。

如果数据属性是不可配置的,则不能将它转换为存取器属性。

如果数据属性是不可配置的,则不能将它的可写性从false修改为true,但可以从true修改为false。

如果数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(做法:先将它标记为可写的,然后修改它的值,最后转换为不可写的)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108374.html

相关文章

  • js知识梳理5:关于函数要点梳理(1)

    摘要:构造函数调用会使用新创建的对象作为调用上下文。函数的参数相关可选形参当传入的实参比函数声明时指定的形参数量要少,剩下的形参都将设置为值实参多则会自动省略。它们的第一个实参是要调用函数的母对象,它是调用上下文,函数体内通过引用它。 写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的...

    付伦 评论0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....

    izhuhaodev 评论0 收藏0
  • 理解JavaScript核心知识点:This

    摘要:关键字计算为当前执行上下文的属性的值。毫无疑问它将指向了这个前置的对象。构造函数也是同理。严格模式无论调用位置,只取显式给定的上下文绑定的,通过方法传入的第一参数,否则是。其实并不属于特殊规则,是由于各种事件监听定义方式本身造成的。 this 是 JavaScript 中非常重要且使用最广的一个关键字,它的值指向了一个对象的引用。这个引用的结果非常容易引起开发者的误判,所以必须对这个关...

    TerryCai 评论0 收藏0
  • 从浏览器多进程到JS单线程,JS运行机制最全面一次梳理

    摘要:如果看完本文后,还对进程线程傻傻分不清,不清楚浏览器多进程浏览器内核多线程单线程运行机制的区别。因此准备梳理这块知识点,结合已有的认知,基于网上的大量参考资料,从浏览器多进程到单线程,将引擎的运行机制系统的梳理一遍。 前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正。 ----------超长文+多图预警,需要花费不少时间。---------- 如果看完本文后,还...

    wanghui 评论0 收藏0
  • 从输入URL到页面加载过程?如何由一道题完善自己前端知识体系!

    摘要:前言见解有限,如有描述不当之处,请帮忙指出,如有错误,会及时修正。为什么要梳理这篇文章最近恰好被问到这方面的问题,尝试整理后发现,这道题的覆盖面可以非常广,很适合作为一道承载知识体系的题目。 前言 见解有限,如有描述不当之处,请帮忙指出,如有错误,会及时修正。 为什么要梳理这篇文章? 最近恰好被问到这方面的问题,尝试整理后发现,这道题的覆盖面可以非常广,很适合作为一道承载知识体系的题目...

    kel 评论0 收藏0

发表评论

0条评论

13651657101

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<