JavaScript语法高级之属性&属性描述符

该博客围绕JavaScript展开,介绍了描述符分类,包括属性、数据和访问描述符。阐述属性描述符的元属性、定义与获取方法,以及五类属性描述符的权限控制。还提及对象不变性的几种情况,如常量属性、禁止扩展等,最后讲解属性的设置与查找算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述

一、描述符分类:

属性描述符:修饰属性的属性 ,元属性,是属性的特征;
数据描述符:具有writable value属性描述符的属性;
访问描述符:具有set和get的属性。
set&get:set中value必须写;成对出现;

<script type="text/javascript">
    /*
        属性描述符:修饰属性的属性 元属性 属性的特征

        数据描述符:具有writable 和 value属性描述符的属性
        访问描述符:具有set和get属性描述符的属性
    */

    var obj ={}
    Object.defineProperty(obj,"age",{
        /*value:30,
        writable:true,*/
        get:function(){
            return this.__age__;
        },
        set:function(val){
            this.__age__ = val;
        }
    })



    </script>

二、属性描述符

1、元属性
属性的属性 称为元属性

2、定义属性:defineProperty

<!--定义属性:defineProperty-->
    <script type="text/javascript">
        var obj={
            name:"snw"
        };
        Object.defineProperty(obj,"age",{
            value:18,
            writable:true,
            configurable:true,
            enumerable:true
        });
        console.log(obj); //Object {name: "snw", age: 18}
        console.log(obj.age);//18


        Object.defineProperty(obj,"sex",{
            value:"man"
        })
        var result =Object.getOwnPropertyDescriptor(obj,"sex");
        console.log(result);//默认值都是false
    </script>

3、获取属性描述符:getOwnPropertyDescriptor

<!--获取属性:getOwnPropertyDescriptor-->
    <script type="text/javascript">
        var a="a";
        var a;
        b="b";
        console.log(Object.getOwnPropertyDescriptor(window,"a"));
        console.log(Object.getOwnPropertyDescriptor(window,"b"));

        delete a;
        delete b;

        console.log(a);
        console.log(b);
    </script>

4、属性描述符定义
属性描述符:修饰属性的属性 ,元属性,是属性的特征。属性描述符共有以下五类:
1)writable&value :控制属性的可读写权限

<script type="text/javascript">
//      writable决定了属性值的读写权限
        var zd={};
        Object.defineProperty(zd,"wife",{
            value:"zdy",
            writable:true
        })

        //静默失败
        zd.wife="18岁的zdy";
        console.log(zd);
    </script>

2)enumerable :决定属性可枚举权限
可枚举:能否出现对象的for in循环中

<script type="text/javascript">
//      enumerable决定了属性能否出现在对象的for in循环中
        var zd={};
        Object.defineProperty(zd,"wife",{
            value:"18岁zdy",
            writable:true
        })
        Object.defineProperty(zd,"wife1",{
            value:"19岁zdy",
            writable:true
        })
        Object.defineProperty(zd,"wife2",{
            value:"20岁zdy",
            writable:true,
            enumerable:true
        })
        Object.defineProperty(zd,"wife3",{
            value:"21岁zdy",
            writable:true
        })
        Object.defineProperty(zd,"wife4",{
            value:"22岁zdy",
            writable:true,
            enumerable:true

        })


        Object.prototype.fromObjectP ="test";
        for(item in zd){
            console.log(item);
        }

        console.log(Object.getOwnPropertyDescriptor(zd.__proto__,"toString"))


    </script>

3)configurable :决定属性可配置权限
可配置:能否重新定义和能否删除(delete)

<script type="text/javascript">
/*      configurable决定了属性的可配置权限
            1.属性可否重新定义
            2.属性是否可删除

            注意:configurable为false时

                value只受writable的控制
                writable可以从true变为false
                其他的改动一律不允许

*/
        var zd={};
        Object.defineProperty(zd,"wife",{
            value:"19岁zdy",
            writable:true,
            enumerable:true
        })

        Object.defineProperty(zd,"wife",{
            value:"19岁zdy",
            writable:false,
            enumerable:false
        })

        console.log(zd);
    </script>

4)getter&setter

                对属性进行操作时,我们可以绑上自己的业务逻辑
                get:
                    对属性进行获取调用get方法
                set:
                    对属性进行设置时调用set方法
    注意:     get&setvalue&writable不能同时出现;

5、注意事项

  • value只受writable控制;writable值可以从true到flase
  • 操作符(in)可以上原型链。
  • JS中方法是浅不变形的!不会遍历原型链,只影响读写直接属性值。

6、属性存在性
1)存在性检查
方法 : obj.hasOwnProperty("toString")

    <script type="text/javascript">
        var obj={
            age:18
        }
        console.log(obj.age)
        console.log("age" in obj)
        console.log(obj.hasOwnProperty("age"))
    </script>

2) 应用:解决for in 中能够获取原型链中属性(只获取直接属性)。

<!--for in 
         问题:循环遍历时会获取所有属性包括原型链中属性,但是通常只获取直接属性
      解决:使用hasOwnProperty过滤掉 原型链中属性-->
    <script type="text/javascript">
//      enumerable决定了属性能否出现在对象的for in循环中
        var zd={
            son:{
                name:"xfz"
            }
        };
        Object.defineProperty(zd,"wife",{
            value:"18岁周",
            writable:true
        })
        Object.defineProperty(zd,"wife1",{
            value:"19岁周",
            writable:true
        })
        Object.defineProperty(zd,"wife2",{
            value:"20岁周",
            writable:true,
            enumerable:true
        })
        Object.defineProperty(zd,"wife3",{
            value:"21岁周",
            writable:true
        })
        Object.defineProperty(zd,"wife4",{
            value:"22岁周",
            writable:true,
            enumerable:true
        })
        Object.defineProperty(Object.prototype,"demo",{
            value:"demo",
            writable:true,
            enumerable:true
        })

        for(item in zd){
            if(zd.hasOwnProperty(item)){
                console.log(item);
            }
        }


    </script>

三、对象不变性

1、基本介绍

常量属性:默认属性为false。将属性的writable和configurable设置为false。
禁止对象扩展Object.preventExtensions(obj)**
密封对象Object.seal(obj)
冻结对象Object.freeze(obj)
深度冻结

2、代码示例:

01_常量属性.html

<script type="text/javascript">

        var math ={};
        Object.defineProperty(math,"PI",{
            value:3.141592654,
            enumerable:true
        })

    </script>

02_禁止对象的扩展.html

<script type="text/javascript">
        //对象不变性的第一个级别:禁止对象的扩展
        var obj ={
            age:18,
            name:"达姆",
            wife:{
                name:"周冬雨",
                age:18
            }
        };
        Object.defineProperty(obj,"PI",{
            value:3.141592654,
            enumerable:true
        })


        Object.preventExtensions(obj)
        obj.age=19;
        delete obj.wife.age;
        delete obj.name;
        console.log(obj)

    </script>

03_密封对象.html

<script type="text/javascript">

        var obj ={
            age:18,
            name:"达姆",
            wife:{
                name:"周冬雨",
                age:18
            }
        };
        Object.defineProperty(obj,"PI",{
            value:3.141592654,
            enumerable:true
        })

//      浅密封
        Object.seal(obj)
        obj.age=19;
        delete obj.wife.age;
        delete obj.name;
        console.log(obj)

    </script>

04_冻结对象.html

<script type="text/javascript">

        var obj ={
            age:18,
            name:"达姆",
            wife:{
                name:"周冬雨",
                age:18
            }
        };
        Object.defineProperty(obj,"PI",{
            value:3.141592654,
            enumerable:true
        })

        //冻结对象
        Object.freeze(obj)
        obj.age=19;
        delete obj.wife.age;
        delete obj.name;
        console.log(obj)

    </script>

05_深度冻结对象.html

<script type="text/javascript">

        var obj ={
            age:18,
            name:"达姆",
            wife:{
                name:"周冬雨",
                age:18
            }
        };

//      浅冻结
        Object.freeze(obj);

        //深度冻结操作:遍历每一个子元素,并分别冻结
        for(item in obj){
            //除了Object.prptotype
            if(obj[item] instanceof Object){
                Object.freeze(obj[item]);
            }
        }

        obj.wife.name="aaa";
        delete obj.wife.age;
        console.log(obj)

    </script>

四、属性的设置与获取

1、 属性查找: [[Get]]:代表的属性查找的算法
[[Get]]:

 1.在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。
 2.如果没有找到,则遍历原型链
 3.无论·如何都没找到,返回undefined

属性的设置与获取.html

<script type="text/javascript">
    /*
        属性(writable为true的数据描述符)
        属性的获取:
            先在当前对象中找 
                如果找到则使用
                如果找不到  上隐式原型链
                    如果找到使用
                    如果找不到  返回undefined

        属性的设置
            不管怎么样都影响对象的直接属性
    */




    /*[[Get]]1.在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。
        2.如果没有找到,则遍历原型链
        3.无论·如何都没找到,返回undefined
        4.如果属性是访问描述符就看get方法的逻辑!!*/




         /*
         obj.a="a";
         [[put]]1.如果属性直接存在于对象中 不在原型链上
         4.如果属性直接存在于对象中  也在原型链上
                 找到直接存在于对象中的属性
                 -数据描述符(没有setter/getter)
                        直接修改对象中的属性(注意writbale的值)
                 -访问描述符
                        直接调用set方法
         2.如果属性不直接存在于对象中也不在原型链上
                在对象的直接属性中添加一个属性(数据描述符)    
                 value:"a"
                 writable:true
                 configurable:true
                 enumerable:true

         3.如果属性不直接存在于对象中  在原型链上
                 ①.该属性是数据描述符(没有setter/getter)
                     -writbale为true
                 直接在对象中添加一个属性,我们称之为屏蔽属性
                     -writbale为false
                     报错,不会生成屏蔽属性

                 ②.该属性是访问描述符
                     调用set,不会生成屏蔽属性
        */




        /*
        3.如果属性不直接存在于对象中  在原型链上
                 ①.该属性是数据描述符(没有setter/getter)
                     -writbale为true
                            直接在对象中添加一个属性,我们称之为屏蔽属性
                     -writbale为false
                            静默失败,不会生成屏蔽属性

                 ②.该属性是访问描述符
                        调用set,不会生成屏蔽属性
        */
        var obj={};
        Object.defineProperty(Object.prototype,"age",{
            /*value:18,
            writable:false*/
            get:function(){

            },
            set:function(val){

            }
        })
        obj.age=1;
        console.log(obj,Object.prototype.age);
    </script>

2、属性设置:[[Put]]:代表的属性设置的算法

[[put]]:

  1.如果属性直接存在于对象中 不在原型链上
    找到直接存在于对象中的属性
        -数据描述符(没有setter/getter)
           直接修改对象中的属性(注意writbale的值)
        -访问描述符
            直接调用set方法

    2.如果属性不直接存在于对象中也不在原型链上
        在对象的直接属性中添加一个属性(数据描述符)    
             value:"a"
             writable:true
             configurable:true
             enumerable:true

    3.如果属性不直接存在于对象中  在原型链上
         ①.该属性是数据描述符(没有setter/getter)
             -writbale为true
                直接在对象中添加一个属性,我们称之为屏蔽属性
             -writbale为false
                 报错,不会生成屏蔽属性

         ②.该属性是访问描述符
               调用set,不会生成屏蔽属性


    4.如果属性直接存在于对象中  也在原型链上
      找到直接存在于对象中的属性
            -数据描述符(没有setter/getter)
               直接修改对象中的属性(注意writbale的值)
            -访问描述符
                直接调用set方法

01如果属性直接存在于对象中,不在原型链上.html

<script type="text/javascript">
//  如果属性直接存在于对象中 不在原型链上
        console.log(Object.prototype)


//      -数据描述符(没有setter/getter)
//          直接修改对象中的属性(注意writbale的值)
        var obj={
            a:"a"
        }

        Object.defineProperty(obj,"a",{
            writable:false
        })

        obj.a="b";
        console.log(obj.a)

//  -访问描述符
//          直接调用set方法
        var obj2={
            a:"a"
        }

        Object.defineProperty(obj2,"a",{
            get :function(){
                return this._a_;
            },
            set :function(val){
                this._a_ = val;
            }
        })

        obj2.a="b";
        console.log(obj2)
        console.log(obj2.a)
    </script>

02如果属性不直接存在于对象中也不在原型链上.html

<script type="text/javascript">
//  如果属性不直接存在于对象中也不在原型链上
        console.log(Object.prototype)
        var obj={}
        obj.a="a";
        console.log(obj.a)

        var result =Object.getOwnPropertyDescriptor(obj,"a");
        console.log(result);
    </script>

03如果属性不直接存在于对象中 在原型链上.html

    <script type="text/javascript">
//  如果属性不直接存在于对象中  在原型链上
        Object.prototype.a="prototypeA";
        console.log(Object.prototype);
        var result = Object.getOwnPropertyDescriptor(Object.prototype,"a");
        console.log(result);

//      ①.该属性是数据描述符(没有setter/getter)
//          -writbale为true
//          直接在对象中添加一个属性,我们称之为屏蔽属性
        var obj={};
        obj.a="a";
        console.log(obj,"------------------------------")


//          -writbale为false
//          报错,不会生成屏蔽属性
        Object.defineProperty(Object.prototype,"a",{
            writable:false
        });
        console.log(Object.prototype);
        var result = Object.getOwnPropertyDescriptor(Object.prototype,"a");
        console.log(result);

        var obj2={};
        obj2.a="a";
        console.log(obj2,"------------------------------")


//      ②.该属性是访问描述符
//          调用set,不会生成屏蔽属性
        Object.defineProperty(Object.prototype,"a",{
//          get:function(){
//              
//          },
            set:function(val){

            }
        });
        console.log(Object.prototype);
        var result = Object.getOwnPropertyDescriptor(Object.prototype,"a");
        console.log(result);

        var obj3={};
        obj3.a="a";
        console.log(obj3,"------------------------------")


    </script>

04如果属性直接存在于对象中 也在原型链上.html

<script type="text/javascript">
//  如果属性直接存在于对象中  也在原型链上
        Object.prototype.a="prototypeA";
        console.log(Object.prototype)

        var obj={
            get a(){
                return this._a_;
            },
            set a(val){
                this._a_="_a_";
            }
        }
        obj.a="b";
        console.log(obj)
        console.log(Object.prototype)
    </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值