在没风的地方找太阳  在你冷的地方做暖阳 人事纷纷  你总太天真  往后的余生  我只要你 往后余生  风雪是你  平淡是你  清贫也是你 荣华是你  心底温柔是你  目光所致  也是你 想带你去看晴空万里  想大声告诉你我为你着迷 往事匆匆  你总会被感动  往后的余生  我只要你 往后余生  冬雪是你  春花是你  夏雨也是你 秋黄是你  四季冷暖是你  目光所致  也是你 往后余生  风雪是你  平淡是你  清贫也是你 荣华是你  心底温柔是你  目光所致  也是你
jQuery火箭图标返回顶部代码 - 站长素材

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()则是遍历自身所有属性(不论是否是可枚举的),不包括原型链上面的。

 

posted @ 2020-09-11 15:28  艺术诗人  阅读(1600)  评论(0编辑  收藏  举报