美文网首页我爱编程
JS - 面向对象 - 属性遍历

JS - 面向对象 - 属性遍历

作者: Iceesong | 来源:发表于2018-08-04 20:54 被阅读32次

    对象属性分类

    对于属性遍历而言,可以将对象属性分为是否可枚举、是否为继承 两种

    let ary = ['a', 'b', 'c']
    

    ary 数组中,可枚举属性是对应的索引 0, 1, 2 ,不可枚举的是 length

    对象属性配置

    对象中,属性是否可枚举可以通过 Object.defineProperty 设定

    class Car {                                          // 创建类
      constructor(brand, model, color) {                
        this.brand = brand
        this.model = model
        this.color = color
      }
    }
    
    let mycar = new  Car('Tesla', 'model 3', 'red')     // 没有的话 new 一个就好啦
    
    Object.defineProperty(mycar ,"color",{
            value: "red",
            enumerable: false,       //是否可枚举, 默认值 false
            configurable: false,    //是否可配置,默认值 false
            writable: false,        //没有 writable 使用默认值 false
      });
    

    对象创建完成,在控制台内通过颜色可以判断不可枚举属性,但作为一个严谨的程序员,当然需要更科学的办法啦

    可枚举属性

    Object.keys(o)

    按顺序遍历返回一个数组,其包含对象 o 自身(不包括原型)的所有可枚举属性的名称

    Object.keys(mycar)          
    // ["brand", "model"] 
    
    for...in循环

    该方法会依次访问一个对象及其原型链中所有可枚举的属性,就当前对象而言,效果较Object.keys(o) 相同

    for (let i in my car) {
      console.log(i)
    }
    // brand
    // model
    

    但如果继承的原型链上已有可枚举属性,原型上的 'foo' 也被遍历进来了

    mycar.__proto__.foo = 'foo'
    
    for (let i in mycar) {
      console.log(i)
    }
    // brand
    // model
    // foo
    
    Object.keys(mycar)          
    // ["brand", "model"] 
    

    所以得再过滤下,使用 hasOwnProperty 过滤继承属性,返回布尔值

    for(let i in mycar){
      // 此处可以使用 mycar.hasOwnProperty(i),
      // 以安全的角度看用 Object.prototype.hasOwnProperty.call(mycar,i) 
      if(Object.prototype.hasOwnProperty.call(mycar,i)){
        console.log(i)
      }
    }
    // brand
    // model
    
    

    所有属性

    Object.getOwnPropertyNames(o)

    该方法返回一个数组,其包含对象 o 所有自有的属性(无论是否可枚举)的名称

    mycar.__proto__.foo = 'foo'
    
    Object.getOwnPropertyNames( mycar )
    // ["brand", "model", "color"]
    

    不可枚举属性

    那既然可枚举和全部自有属性都有办法获取,要获取不可枚举属性就简单了

    mycar.__proto__.foo = 'foo'
    
    Object.getOwnPropertyNames(mycar).filter(val =>
      !Object.keys(mycar).includes(val)
    )
    // ["color"]
    

    遍历顺序

    值得注意的是,Object.keys() 遍历顺序对不同属性类型时,先后顺序不同

    let a = {'zz': 3, 3: 99, 1: 100, 'bb': 0}        
    //["1", "3", "zz", "bb"]
    

    引用 MDN 中说明:

    一个对象的属性名可以是任何有效的 JavaScript 字符串,或者可以被转换为字符串的任何类型,包括空字符串

    也就是说,对象的所有属性都会通过转换变化为字符串,而由数字转过来字符串排序优先(此处略有疑问)而 for...in循环 遍历顺序与 Object.keys() 一致

    // 同时创建多个变量
    let myObj = new Object(),
    str = "myString",
    rand = Math.random(),
    obj = new Object(),
    num1 = 23,
    num2 = 99,
    ary = [1,2];
    
    myObj.type              = "Dot syntax";
    myObj["date created"]   = "String with space";
    myObj[str]              = "String value";
    myObj[rand]             = "Random Number";
    myObj[obj]              = "Object";
    myObj[ary]              = 'here is a ary'
    myObj[num2]             = 'here is a number_2'
    myObj[""]               = "Even an empty string";
    myObj[num1]             = 'here is a number_1'
    
    for(let i in myObj){console.log(typeof i,' --- ', i, ' --- ',myObj[i])}
    // 去下图...
    

    小结

    • 遍历自有属性:

      • 可枚举:
        1. Object.keys(o) 遍历 对象 o 上的所有可枚举自有属性
        2. for...in 遍历对象 o 上所有自有属性(包括继承属性)
      • 可枚举 + 不可枚举:
        1. Object.getOwnPropertyNames(o) 遍历对象 o 上所有自有属性(无论是否可枚举)
      • 不可枚举:
        1. 通过 Object.getOwnPropertyNames(o) 获取所有自有属性,在通过 Object.keys(mycar) 获取 自有可枚举属性,在使用 filter 过滤
    • 遍历顺序:以属性设定时顺序为准,数字例外优先排序(仅参考)

    • 判断是否属于自有属性(返回布尔值):
      1. 普通做法 mycar.hasOwnProperty(i)
      2. 更安全的做法 Object.prototype.hasOwnProperty.call(mycar,i)

    统计表

    源自 MDN ,关于属性的 枚举,继承 统计表

    相关文章

      网友评论

        本文标题:JS - 面向对象 - 属性遍历

        本文链接:https://www.haomeiwen.com/subject/uwvmvftx.html