• ES6 入门教程 10 对象的扩展 10.4 属性的可枚举性和遍历 & 10.5 super 关键字


    ES6 入门教程

    ECMAScript 6 入门

    作者:阮一峰

    本文仅用于学习记录,不存在任何商业用途,如侵删

    10 对象的扩展

    10.4 属性的可枚举性和遍历
    10.4.1 可枚举性

    对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。

    let obj = { foo: 123 };
    Object.getOwnPropertyDescriptor(obj, 'foo')
    //  {
    //    value: 123,
    //    writable: true,
    //    enumerable: true,
    //    configurable: true
    //  }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性。

    目前,有四个操作会忽略enumerablefalse的属性。

    • for...in循环:只遍历对象自身的和继承的可枚举的属性。
    • Object.keys():返回对象自身的所有可枚举的属性的键名。
    • JSON.stringify():只串行化对象自身的可枚举的属性。
    • Object.assign(): 忽略enumerablefalse的属性,只拷贝对象自身的可枚举的属性。

    这四个操作之中,前三个是 ES5 就有的,最后一个Object.assign()是 ES6 新增的。

    其中,只有for...in会返回继承的属性,其他三个方法都会忽略继承的属性,只处理对象自身的属性。实际上,引入“可枚举”(enumerable)这个概念的最初目的,就是让某些属性可以规避掉for...in操作,不然所有内部属性和方法都会被遍历到。

    比如,对象原型的toString方法,以及数组的length属性,就通过“可枚举性”,从而避免被for...in遍历到。

    Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
    // false
    
    Object.getOwnPropertyDescriptor([], 'length').enumerable
    // false
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    上面代码中,toStringlength属性的enumerable都是false,因此for...in不会遍历到这两个继承自原型的属性。

    另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。

    Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
    // false
    
    • 1
    • 2

    在这里插入图片描述

    总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。

    所以,尽量不要用for...in循环,而用Object.keys()代替。

    10.4.2 属性的遍历

    ES6 一共有 5 种方法可以遍历对象的属性。

    (1)for…in

    for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

    (2)Object.keys(obj)

    Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

    (3)Object.getOwnPropertyNames(obj)

    Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

    (4)Object.getOwnPropertySymbols(obj)

    Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

    (5)Reflect.ownKeys(obj)

    Reflect.ownKeys返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

    以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。

    • 首先遍历所有数值键,按照数值升序排列。
    • 其次遍历所有字符串键,按照加入时间升序排列。
    • 最后遍历所有 Symbol 键,按照加入时间升序排列。
    Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
    // ['2', '10', 'b', 'a', Symbol()]
    
    • 1
    • 2

    在这里插入图片描述

    上面代码中,Reflect.ownKeys方法返回一个数组,包含了参数对象的所有属性。这个数组的属性次序是这样的,首先是数值属性210,其次是字符串属性ba,最后是 Symbol 属性。

    10.5 super 关键字

    this关键字总是指向函数所在的当前对象,

    ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象。

    const proto = {
      foo: 'hello'
    };
    
    const obj = {
      foo: 'world',
      find() {
        return super.foo;
      }
    };
    
    Object.setPrototypeOf(obj, proto);
    obj.find() // "hello"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    上面代码中,对象obj.find()方法之中,通过super.foo引用了原型对象protofoo属性。

    注意,super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。

    // 报错
    const obj = {
      foo: super.foo
    }
    
    // 报错
    const obj = {
      foo: () => super.foo
    }
    
    // 报错
    const obj = {
      foo: function () {
        return super.foo
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    上面三种super的用法都会报错,因为对于 JavaScript 引擎来说,这里的super都没有用在对象的方法之中。第一种写法是super用在属性里面,第二种和第三种写法是super用在一个函数里面,然后赋值给foo属性。

    目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。

    JavaScript 引擎内部,super.foo等同于Object.getPrototypeOf(this).foo(属性)或Object.getPrototypeOf(this).foo.call(this)(方法)。

    const proto = {
      x: 'hello',
      foo() {
        console.log(this.x);
      },
    };
    
    const obj = {
      x: 'world',
      foo() {
        super.foo();
      }
    }
    
    Object.setPrototypeOf(obj, proto);
    
    obj.foo() // "world"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    上面代码中,super.foo指向原型对象protofoo方法,但是绑定的this却还是当前对象obj,因此输出的就是world

  • 相关阅读:
    Progresql数据库安装--安装
    可行性研究报告模板
    2311C++抽象工厂
    Linux命令全解
    轧钢切头飞剪机设计及有限元分析
    CSDN更换背景 调整博客风格与代码块样式方法
    小程序在线客服完整实现
    vue3后台管理框架之API接口统一管理
    【已解决】org.springframework.boot:type=Admin,name=SpringApplication异常
    kcp简析
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/127896871