【ES5新特性二】新增对象属性特性

一、Object 属性描述符相关方法

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

Object.getOwnPropertyDescriptor() 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符。

原生JavaScipt案例合集
JavaScript +DOM基础
JavaScript 基础到高级
Canvas游戏开发

在ES3.1中,只要对象能够访问到,就可以任意的去操作该对象,访问对象、添加属性、修改属性和删除属性,如下:

console.group("ES3对象操作");
var stu = {
    name:"张三",
    sex:"男",
    age:23
}
console.log("原对象stu:",stu);
// 添加分数属性
stu.score = 100;
console.log("添加分数属性后stu:",stu);
// 删除年龄属性
delete stu.age;
console.log("删除年龄属性后stu:",stu);
// 修改性别属性
stu.sex = "女";
console.log("修改性别属性后stu:",stu);
console.groupEnd();

在ES5中,为对象拓展了一个叫做“特性”的东西,为对象中属性的可访问行进行了限制 如设置属性是否可以被枚举的特性enumerable [ɪ’njʊmərəbl],属性值为布尔值

console.group("ES5限制枚举特性");
// 使用for...in 枚举(一一列举)对象的属性
for(var i in stu){
    
    
    console.log(i);//没有限制枚举的情况下,正常获取对象的每一个属性
}

// console.log("====== 开始限制某个独立属性的枚举 ======")

// // 使用ES5中对象的特性 enumerable限制枚举 属性值设置为false则对象属性不可枚举 默认true可枚举
// Object.defineProperty(stu,"score",{
    
    
//     // 设置score属性不可枚举
//     enumerable:false
// })
// for(var i in stu){
    
    
//     console.log(i);//限制枚举的情况下,不能正常获取对象限制枚举的属性
// }

console.log("====== 限制多个属性的枚举 ======")

Object.defineProperties(stu,{
    
    
    "name":{
    
    
        enumerable:false
    },
    "sex":{
    
    
        enumerable:false
    }
})
for(var i in stu){
    
    
    console.log(i);//限制枚举的情况下,不能正常获取对象限制枚举的属性
}
console.groupEnd();

总结:对象中的属性默认可以被枚举;但使用ES5方法限制枚举后,被限制枚举后的属性就不可以再次枚举了

对象中存在的属性描述符有两种主要类型:数据描述符和访问器描述符。数据描述符是一个具有可写或不可写值的属性。访问器描述符是由 getter/setter 函数对描述的属性。描述符只能是这两种类型之一,不能同时为两者。
数据描述符和访问器描述符都是对象。它们共享以下可选键(请注意:在使用 Object.defineProperty() 定义属性的情况下,下述所有键都是默认值):

  • configurable
    当设置为 false 时,
    该属性的类型不能在数据属性和访问器属性之间更改,且
    该属性不可被删除,且
    其描述符的其他属性也不能被更改(但是,如果它是一个可写的数据描述符,则 value 可以被更改,writable 可以更改为 false)。
    默认值为 false。

  • enumerable
    当且仅当该属性在对应对象的属性枚举中出现时,值为 true。默认值为 false。
    数据描述符还具有以下可选键值:

  • value
    与属性相关联的值。可以是任何有效的 JavaScript 值(数字、对象、函数等)。默认值为 undefined。

  • writable
    如果与属性相关联的值可以使用赋值运算符更改,则为 true。默认值为 false。
    访问器描述符还具有以下可选键值:

  • get
    用作属性 getter 的函数,如果没有 getter 则为 undefined。当访问该属性时,将不带参地调用此函数,并将 this 设置为通过该属性访问的对象(因为可能存在继承关系,这可能不是定义该属性的对象)。返回值将被用作该属性的值。默认值为 undefined。

  • set
    用作属性 setter 的函数,如果没有 setter 则为 undefined。当该属性被赋值时,将调用此函数,并带有一个参数(要赋给该属性的值),并将 this 设置为通过该属性分配的对象。默认值为 undefined。

如果描述符没有 value、writable、get 和 set 键中的任何一个,它将被视为数据描述符。如果描述符同时具有 [value 或 writable] 和 [get 或 set] 键,则会抛出异常。

这些属性不一定是描述符本身的属性。继承的属性也会被考虑在内。为了确保这些默认值得到保留,你可以预先冻结描述符对象原型链中的现有对象,明确指定所有选项,或使用 Object.create(null) 指向 null。

二、关联知识点回顾

  • JS中的三类对象:

    • 内置对象(native object)是由ECMAScript规范定义的对象或者类。例如:函数对象、数组对象、日期对象、正则表达式对象等等
    • 宿主对象(host object) 是由js编译器所嵌入的宿主环境(web浏览器)所定义的。比如客户端js中表示网页结构的HTMLElement对象就是宿主环境创建的对象。宿主环境定义的对象可以直接使用的话,我们也可以把它们当做内置对象。
    • 自定义对象(user-defined object) 由运行中的js创建的对象。
  • JS中的两类属性:

    • 自有属性(own property) 直接在对象当中定义的属性,区别于继承属性。
    • 继承属性(inherited property) 在对象原型中定义的属性。
  • JS中属性描述符对象(属性的特性描述)

    ES5中定义了一个属性描述符对象(property descriptor),这个对象属性和他们所描述的属性特性是同名的。

    • value:属性的值。
    • writable:可写性,是否可以设置值。
    • enumerable:可枚举性,遍历对象时该属性会不会出现。
    • configurable:可配置性。1. 通过设置为true,可以从对象删除通过特性定义的属性。如果是false,则不可以被删除。 2. 如果设置为true时,配置了指定数量的相关属性特性。那么下次可以进行任意的新特性的增加。如果设置为false,那么就不能对应这个属性已经有的特性基础上配置新的属性特性。但是可以继续修改已有的特性对应的那个值。

三、对象属性新增特性描述符

3.1 通过value特性配置值

在ES3.1中,只要对象能够访问到,就可以任意的去操作该对象,访问对象、添加属性、修改属性和删除属性,如下:

// console.group("ES3对象操作");
// var stu = {
//     name:"张三",
//     sex:"男",
//     age:23
// }
// console.log("原对象stu:",stu);
// // 添加分数属性
// stu.score = 100;
// console.log("添加分数属性后stu:",stu);
// // 删除年龄属性
// delete stu.age;
// console.log("删除年龄属性后stu:",stu);
// // 修改性别属性
// stu.sex = "女";
// console.log("修改性别属性后stu:",stu);
// console.groupEnd();

在ES5中,为对象的属性配置值

console.group("ES5添加属性的值");
// 创建一个空对象
var stu = {
    
    }
// ES5方法为空对象添加属性和属性值
Object.defineProperty(stu,'name',{
    
    
    // 配置值 添加属性值
    value:"张翠花"
})
// 访问对象  通过这种方式添加的属性
console.log("stu:",stu);//stu: {name: "张翠花"}
// 删除属性  不能使用 delete 删除配置的属性
delete stu.name;
console.log("stu:",stu);//stu: {name: "张翠花"}
// 访问属性  可以访问配置的属性
console.log("stu.name:",stu.name);//stu.name: 张翠花
// 修改属性  不可以使用 obj.att  或  obj[att]方 式修改属性
stu.name = "张无忌";
// 访问属性  可以访问配置的属性
console.log("stu.name:",stu.name);//stu.name: 张翠花
//枚举属性   不可以被枚举
for(var i in stu){
    
    
    console.log(i);
} 
console.groupEnd();

// ES5,修改对象属性
var obj = {
    
    type:"未知"};
console.log(obj.type);//未知
Object.defineProperty(obj,"type",{
    
    
    value:"狗"
});
console.log(obj.type);//狗
obj.type = "猫";
console.log(obj.type);//猫
delete obj.type;
console.log(obj.type);//undefined

总结:

  1. 当一个对象中没有任何原有属性,通过特性的方式 Object.definePeoperty方式添加的属性,里面属性的所有特性都是false:即:通过这种方式添加的属性不能够删除、修改和枚举。
  2. 如果一个对象中天生自带某个属性,此时对象属性的所有特性属性值为true: 即:只要对象能访问到,不管什么方式,都可以进行任意的操作

3.2 通过writable特性配置可读写性

// 创建一个对象
var obj = {type:"未知"}

// 将对象的属性type设置为不可写特性(即:不可修改)
Object.defineProperty(obj,"type",{
    // 设置属性是否可写  true默认可写  false不可写
    writable:false
})

console.log("修改前属性type:",obj.type);//修改前属性type: 未知

// 尝试使用普通的方式进行修改  结果不可修改
obj.type = "猫";

console.log("修改后属性type:",obj.type);//修改后属性type: 未知

3.3 通过enumerable配置可枚举性

// 创建一个对象
var obj = {
    type:"未知",
    color:"白色"
}

// 默认情况下,对象的属性可以被枚举
for(var i in obj){
    console.log(i);
}

// 设置属性color特性 不可枚举
Object.defineProperty(obj,"color",{
     // 默认true可被枚举  设置false不可被枚举
    enumerable:false
})

// 设置color不可枚举后,尝试枚举,color不再出现
for(var i in obj){
    console.log(i);
}

3.4 通过 configurable配置相关配置

var obj = {
    name: "张三",
    age: 23
}

console.log("初始对象:", obj)

// 普通对象属性可以访问、修改、新增、删除、枚举
Object.defineProperties(obj, {
    name: {
        value: "李四",
        // 如果要修改的这个属性,原本就存在于对象中。那么对应的属性特性默认全部为true,可操作的
    },
    gender: {
        value: "男",
        // 如果这个属性,在原对象中不存在,那么此时作为新增属性。它的属性特性默认全部为false,不可操作的,但是可以访问这个属性 

        // 配置可被枚举
        enumerable: true,
        // 配置可以被修改
        // writable: true,
        // 可配置性:1. 通过设置为true,可以从对象删除通过特性定义的属性。 
        // 2. 如果设置为true时,配置了指定数量的相关属性特性。那么下次可以进行任意的新特性的增加。如果设置为false,那么就不能对应这个属性已经有的特性基础上配置新的属性特性。但是可以继续修改已有的特性对应的那个值。
        // configurable: true
    }
})

Object.defineProperty(obj, 'gender', {
    value: "女",
    writable: true
})

// 枚举
for (let k in obj) {
    console.log(k)
}

3.5 存值器set和取值器get

<body>
<h2>单项数据绑定:通过修改JS中的数据,页面呈现最新修改的数据信息。这是一种映射关系,把JS数据的变化映射到DOM结构上</h2>
<div id="box">数据单项绑定呈现位置</div>
<input type="text" id="ipt">
</body>
<script src="./js/jquery-1.12.3.min.js"></script>
<script>
    // 创建对象
    // var obj = {
    //     des:"把Model的变化映射到DOM结构上"
    // }

    // 获取元素
    // var box = document.getElementById("box");

    // // 设置元素的内部文本
    // box.innerHTML = obj.des;

    // 普通的方式,修改对象的值,查看页面DOM数据变化
    // obj.des = "新的数据";//页面不会发生改变,除非通过innerHTML重新写入

    // 通过set方法设置单项绑定
    // Object.defineProperty(obj,'des',{
    //     //赋值器
    //     set:function(value){
    //         // 当设置或修改新的值时,将最新的值输出到页面
    //         box.innerHTML = value;
    //         // 备用属性赋值
    //         this.oDes = value;
    //     },
    //     // 取值器
    //     get:function(){
    //         return this.oDes;
    //     }
    // });

    // 再次修改以下值试试
    // obj.des = "新的值";//发现页面内容更新了


    // 现在我们做这样一个修改,页面添加一个输入框,随着输入框内容的输入,上面呈现输入框中的内容,修改如下:
    // 创建对象
    var obj = {
        des:"把Model的变化映射到DOM结构上"
    }

    // 获取元素
    var box = document.getElementById("box");
    var ipt = document.getElementById("ipt");

    // 设置元素的内部文本
    box.innerHTML = obj.des;
    Object.defineProperty(obj,'des',{
        //赋值器
        set:function(value){
            // 当设置或修改新的值时,将最新的值输出到页面
            box.innerHTML = value;
            // 备用属性赋值
            this.oDes = value;
        },
        // 取值器
        get:function(){
            return this.oDes;
        }
    });

    // 新的值来自于页面输入框 触发正在输入事件
    // ipt.oninput = function(){
    //     if(this.value === ""){
    //         box.innerHTML = "把Model的变化映射到DOM结构上";
    //     }else{
    //         obj.des = this.value;
    //     }
    // }
    
    // 含有输入法时,不能检测中文,改造并使用jQuery(使用js也可)如下:

3.6 对象所有特性相关应用:

// 创建一个对象
var obj = {
    name:"张三",
    age:25
}

// 设置多属性特性value
Object.defineProperties(obj,{
    // 设置属性name的特性
    name:{
        // 配置值 设置或修改值
        value:"张三丰",
        // 是否可写配置 设置值为false后不可以再通过普通方式修改值
        writable:false,
        // 是否可枚举配置 设置值为false后 不可以枚举属性
        enumerable:false,
        // 是否可配置设置,设置为false后不能使用任何方式重复修改设置
        configurable:false
    },

    // 设置属性age的特性
    age:{
        // 存值器
        set:function(value){
            this.oAge = value;
        },
        // 取值器
        get:function(){
            return this.oAge;
        },
        // 设置是否可枚举  设置false后,age属性不再被获取,只显示备用属性
        enumerable:false,
        // 注意:一旦设置set/get方法就是设置了设置值或修改值的配置,
        // 一旦设置了set特性方法,就不能再设置相同功能的特性 writeable 与 value,否则配置冲突报错
        // 设置是否可写
        // writable:false,
        // 配置新的值
        // value:"张君宝"
    }
})

// 尝试修改obj中的属性
obj.name = "张翠华";
obj.age = 23;

console.log(obj)

// 尝试枚举
for(var i in obj){
    console.log(i,obj[i])
}

猜你喜欢

转载自blog.csdn.net/qq_39335404/article/details/132575644