zoukankan      html  css  js  c++  java
  • JS中的可枚举属性与不可枚举属性

     什么是枚举?枚举是指对象中的属性是否可以遍历出来,再简单点说就是属性是否可以以列举出来。

     一、怎么判断属性是否可枚举

           在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。

           js中的基本包装类型的原型属性是不可枚举的,比如Object,Array,Number等

           这是一个例子:

    var num = new Number();
    for(var pro in num) {
       console.log("num." + pro + " = " + num[pro]);
    }
    //此处没有输出

    它的输出结果是空的,因为Number中的内置属性是不可枚举的,所以不能被 for ... in 访问到 

          每个对象都有propertyIsEnumerable()方法,这个方法可以判断出指定的属性是否可枚举。

           用法:     
           obj.propertyIsEnumerable("属性名");

    function Person(){
        this.name = "我是实例属性"
        this.age = 19;  
    }
    var p = new Person();
    console.log(p.propertyIsEnumerable("name")); //true
     
    Person.prototype.prop = "我是原型属性" //添加一个原型属性
    console.log(p.propertyIsEnumerable("prop")); //false prop是继承自原型上的属性,所以返回的是false
     
    for(var k in p){
      console.log(k+","+p[k]);//name,我是实例属性  age,19  prop,我是原型属性
    }

        从中也可以发现,如果是对象的原型链中的属性,不管是否枚举都会返回false。
        但是 for ...in 仍然可以读出原型链中的可枚举属性 

    二、枚举属性的作用

     枚举属性主要会影响几个方法

    ES5中:
        for...in                         //只遍历对象自身的和继承的可枚举的属性
        Object.keys()             //返回对象自身的所有可枚举的属性的键名
        JSON.stringify           //JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串。
     
    ES6中:
        Object.assign()          //会忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

        可以看出来这些都是可以遍历对象的方法,而这四个操作中只有for...in中会返回继承的属性

        先看一个例子,创建一个"xsy"对象:

    function Person(){
        this.name = "XSY"
    };
    Person.prototype = {
        constructor: Person,
        job:"student",
    };
     
    var xsy = new Person();
    Object.defineProperty(xsy, "sex",{
        value:"female",
        enumerable:false
    });

          这里用defineProperty方法定义了一个叫"sex"的不可枚举属性

    然后可以开始验证了:

    a.  for...in

    for(var pro in xsy){
        console.log("xsy." + pro+ " = " + xsy[pro]);
    }

         输出的结果如下,可以发现 对象中声明的属性,原型链上绑定的属性成功输出了,而不可枚举属性“sex”没有输出。

      b.  Object.keys()

    console.log(Object.keys(xsy));

     从输出结果可以发现,这里只输出了对象声明的可枚举属性,但是没有输出原型链中的可枚举属性

    c. JSON.stringify

    console.log(JSON.stringify(xsy));

    这里的输出也和上面一样,结果中只有对象中的可枚举属性没有原型链中的。

            从上面这些操作中大概可以明白了,可枚举性决定了这个属性能否被for…in查找遍历到。所以可枚举与否都是开发者自己定义的,
    可以通过Object.defineProperty()方法。

    三、设置可枚举属性

        其实在上面的例子中已经使用到了设置enumerable的方法:Object.defineProperty()

    var person = {
        name:'xiao',
        age: '18',
        sex: 'boy'
    }
     
    Object.defineProperty(person,'age',{
        enumerable:true,//可以被枚举
    });
    Object.defineProperty(person,'sex',{
        enumerable:false,//不可以被枚举
    })
     
    for(var k in person){
        console.log(person[k])//a,可以被枚举
    }
    //18
    //xiao

          从上面可以看出:
         1.Object.defineProperty(obj, prop, descriptor)方法有三那个参数
               第一个:目标对象
               第二个:目标属性,字符串
               第三个:对目标属性的行为,放在对象里
         2.enumerable为true时表示可枚举,enumerable为false表示不可枚举;
         3.开发者自己定义的对象person中的所有属性默认都是可枚举的;

    四、如何判断是否可枚举-- propertyIsEnumerable

           有时候不知道对象的可枚举性,该怎么判断呢。propertylsEnumerable()方法可以解决这个问题

    person.propertyIsEnumerable('sex');//false
    person.propertyIsEnumerable('age');//true

      propertyIsEnumerable() 语法:

    1. 语法:obj.propertyIsEnumerable(prop)
    2. 描述:每个对象都有一个propertyIsEnumerable方法。此方法可以确定对象中指定的属性是否可枚举,返回一个布尔值。但该方法对通过原型链继承的属性无效(原型链继承的属性是否可枚举不能用该方法来判断)
    3. 案例:
    4. 1)用户自定义对象和引擎内置对象的区别
    Math.propertyIsEnumerable('random');   // 返回 false
    Object.propertyIsEnumerable('constructor');    // 返回 false
    var num = new Number();
    for(var pro in num) {
        console.log("num." + pro + " = " + num[pro]);
    }//输出空
    1. 这说明了开发者自定义的属性在一般情况下时可以枚举的,但是内置的对象Math和基本包装类型里的属性是不可枚举的,如Object, Array, Number等;其实,propertyIsEnumerable方法只对对象自身的属性(对象自身添加的、构造函数实例化的)有效,对原型上的、继承来的属性都无效。

    五、总结

    1.  for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面的可枚举属性;
    2. 而Object.keys()只是遍历自身的可枚举属性,不可以遍历原型链上的可枚举属性. 这是for...in和Object.keys()的主要区别;
    3. Object.getOwnPropertyNames()则是遍历自身所有属性(不论是否是可枚举的),不包括原型链上面的。
  • 相关阅读:
    星战代码小电影
    CDlinux 安装
    网络正常使用,图标状态显示不正常
    查询正在执行的SQL语句DBCCINPUTBUFFER
    如何在MYSQL下所有指定数据库名下执行SQL
    GHOST完成后出现GRUB解决方法
    MySql Cast与Convert函数
    MYSQL查询数据库表索引的硬盘空间占用
    警惕企业中的五种虚假执行力
    开启笔记本win7的虚拟热点笔记本变成wifi
  • 原文地址:https://www.cnblogs.com/art-poet/p/13651968.html
Copyright © 2011-2022 走看看