zoukankan      html  css  js  c++  java
  • ES6 对象的扩展

    一、 对象成员 的扩展

    1. 对象成员 的简洁写法

    • 属性
    const foo = 'bar';
    const result = {foo};
    
    // 上式 等同于:
    const foo = 'bar';
    const result = {foo: foo};
    
    • 方法
    const o = {
        method() {
            return "Hello!";
        }
    };
    
    // 上式 等同于
    
    const o = {
        method: function() {
            return "Hello!";
        }
    };
    

    2. 自定义创建对象时,属性名 可以是 动态表达式

    • 举例说明:
    // 如下:ES6支持;ES5不支持
    
    
    let lastWord = 'last word';
    
    const a = {
        'first word': 'hello',
        [lastWord]: 'world'
    };
    
    • 注意区分:
      • ES5、ES6 都支持给 已创建好的对象 添加属性时,属性名为动态表达式
      • ES5 不支持在 自定义创建对象时, 为对象添加 动态表达式的属性
      • ES6 支持在自 自定义创建对象时, 为对象动态添加属性
    // 如下:ES5 、ES6 都支持
    let obj = {};
    const aa = 'name';
    
    obj[aa] = 'zhang';
    
    • 约束: 属性名表达式与简洁表示法,不能同时使用,会报错
    // 报错
    const foo = 'bar';
    const bar = 'abc';
    const baz = { [foo] };
    
    // 正确
    const foo = 'bar';
    const baz = { [foo]: 'abc'};
    

    二、 对象的 扩展运算符

    1. 作用:取出对象中 自身 可枚举的、非继承 的属性

    let z = { a: 3, b: 4 };
    let result = { ...z };
    console.log(result);    // { a: 3, b: 4 }
    

    2. 扩展运算符 结合 解构赋值

    • 结构赋值时,尚未被读取的属性,都会被分配到指定的对象上面
    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    console.log(x);         // 1
    console.log(y);         // 2
    console.log(z);         // { a: 3, b: 4 }
    
    • 解构赋值不是最后一个参数,所以会报错
    let { ...x, y, z } = obj; // 句法错误
    let { x, ...y, ...z } = obj; // 句法错误
    
    • 解构赋值是 浅拷贝;不复制 原型上的属性
    let o2 = { b: 2 };
    o2.__proto__ = o1;
    let { ...o3 } = o2;
    o3 // { b: 2 }
    

    3. 等同于 Object.assign( ) :对象属性拷贝合并(浅拷贝)

    • 重名属性,后者覆盖前者
    let result = { ...a, ...b };
    
    // 等同于
    let result = Object.assign({}, a, b);
    
    • 不能用于对象的 深拷贝: 对象的属性如果是对象,则为属性对象的 浅拷贝:只是拷贝了 属性对象的指针
    const a = {
        name: 'zhang',
        info: {
            age: 18
        }
    };
    const aClone = {...a};
    
    a.name = 'xin';
    a.info.age = 20;
    console.log(aClone);    // aClone.name 值为 'zhang';aClone.info.age 值为20
    

    三、 对象的合并:Object.assign( )

    1. 语法 Object.assign(target, source1, source2)

    • 参数target 目标对象

    • 参数source1source2 源对象

    • 返回值: 合并了 源对象属性的 目标对象指针

    2. 作用:对象属性的合并

    • 将源对象 所有可枚举的、非继承的属性, 合并到 目标对象中

    • 如果 目标对象 与 源对象 有同名属性、源对象 与 源对象 有重名属性:后者覆盖前者

    3. 对象的属性如果是对象,则为属性对象的 浅拷贝:只是拷贝了 属性对象的指针

    • 如果 源对象 某个属性的值是对象,那么目标对象拷贝,得到的是这个对象的引用
    const a = {age: 20};
    const b = {
        info: {
            name: 'zhang',
            sex: 'man'
        }
    };
    
    const result = Object.assign(a, b);
    
    console.log(result.info === b.info);    // true
    
    • 注意: Object.assign( ) 不能用于对象的深拷贝,举例如下
    const a = {
        name: 'zhang',
        info: {
            age: 18
        }
    };
    const aClone = Object.assign({}, a);
    
    console.log(a === aClone);      // 输出false;但改变了 a.info 中的属性;aClone.info 中的属性也会变化
    

    4. 如果参数不是对象,会被默认转成对象(了解)

    • 如果参数不是对象,会默认将参数转为对象(但 null / undefined 不能转为对象)

    • 参数target:(目标对象)

      • 若 值为 null / undefined, 会直接报错
      • 若值为 string 类型:会将字符串转为包装对象(数组形式); 'ab' 变为 [0: 'a', 1: 'b']
      • 若值为 Number 类型:会将 数值 转为包装对象
      • 若值为 Boolean 类型:会将 布尔值 转为包装对象
    • 参数source1:(源对象)

      • 若 值为 null / undefined,会跳过,不报错
      • 若值为 string 类型:会将字符串转为包装对象(数组形式); 'ab' 变为 [0: 'a', 1: 'b']
      • 若值为 Number 类型:会被忽略
      • 若值为 Boolean 类型: 会被忽略

    四、对象的遍历:Object.keys( )、Object.values( )、Object.entries( )

    1. ES5 引入 Object.keys( )

    • 作用: 遍历 自身 可枚举的、非继承的属性键值

    • 语法:

      • Object.keys(obj)

      • 参数: 要遍历的对象

      • 返回值: 对象 键名 构成的 一维数组(键名)

    var obj = { foo: 'bar', baz: 42 };
    
    console.log(Object.keys(obj));      // ["foo", "baz"]
    

    2. ES6 补充 Object.values( )

    • 作用: 遍历 自身 可枚举的、非继承的属性键值

    • 语法:

      • Object.values(obj)

      • 参数: 要遍历的对象

      • 返回值: 对象 键值 构成的 一维数组(键值)

    var obj = { foo: 'bar', baz: 42 };
    
    console.log(Object.values(obj));      // ["bar", 42]
    

    3. ES6 补充 Object.entries( )

    • 语法:
      • Object.values(obj)

      • 参数: 要遍历的对象

      • 返回值: 对象 键值 构成的 二维数组(键名 、键值)

    const obj = { foo: 'bar', baz: 42 };
    
    console.log(Object.entries(obj));   // [ ["foo", "bar"], ["baz", 42] ]
    
    • 作用: 遍历 自身 可枚举的、非继承的属性键名、键值
      • 遍历对象

      • 将对象转为真正的Map结构

    const obj = { foo: 'bar', baz: 42 };
    const map = new Map(Object.entries(obj));
    map // Map { foo: "bar", baz: 42 }
    

    4. 遍历 对象属性 的方法汇总

    • (1)遍历对象属性 的几种方法:

      • for...in:遍历 对象属性 (含:可枚举的、继承的;不含:Symbol 类型的)

      • Object.keys(obj)Object.values(obj)Object.entries(obj):返回一个数组;(含:可枚举的;不含:继承的、Symbol类型的)

      • Object.getOwnPropertyNames(obj):返回一个键名数组;(含:可枚举的、不可枚举的;不含:继承的、Symbol类型的)

      • Object.getOwnPropertySymbols(obj):返回一个 Symbol 键值的数组;(只含:Symbol 类型的)

      • Reflect.ownKeys(obj):返回一个数组, (含:除继承外的 所有属性,无论 是否可比遍历、无论Symbol类型;不含:继承的)

    • (2)遍历对象属性的顺序: 以上五种方法都遵循,如下

      • 首先遍历所有数值键,按照数值升序排列
      • 其次遍历所有字符串键,按照加入时间升序排列
      • 最后遍历所有 Symbol 键,按照加入时间升序排列

    五、对象属性的 底层描述

    1. 回顾:获取对象属性 的描述对象 Object.getOwnPropertyDescriptor(obj, property)

    • 对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为

    • Object.getOwnPropertyDescriptor(obj, property) 方法来 获取对象属性 的描述对象

    const obj = { foo: 123 };
    const result = Object.getOwnPropertyDescriptor(obj, 'foo');
    
    console.log(result);
    //  {
    //    value: 123,           // 属性值
    //    writable: true,       // 可写性:是否可修改
    //    enumerable: true,     // 可枚举性:是否可枚举
    //    configurable: true    // 可配置性:是否可以用 delete删除
    //  }
    

    2. 回顾:给对象添加属性 和 属性的描述信息 Object.defineProperty(obj, property, descriptor)

    • 语法:
      • 参数1:要添加属性的对象

      • 参数2:要添加属性的键值

      • 参数3:要添加属性的描述信息

    var obj = {};
    
    Object.defineProperty(obj, "a", {
        value : 1,
        writable : true,
        configurable : true,
        enumerable : true
    });
    
    // 如上代码,等同于:
    var o = {};
    o.a = 1;
    

    3. 回顾:判断对象的属性 是否是继承的 / 自身提供的 myObject.hasOwnProperty(property)

    • 语法:
      • 参数:要判断的属性

      • 返回值:布尔值(true:对象自身属性;false:对象继承属性)

    4. 回顾:对象属性的 可枚举性 Object.getOwnPropertyDescriptor(obj, property).enumerable

    • 查看对象的属性是否 可枚举
    console.log(Object.getOwnPropertyDescriptor([], 'length').enumerable);
    
    // false
    
    • 4个操作:会忽略 enumerablefalse 的属性
      • for...in遍历 对象自身、可枚举、继承 的属性(含继承、不含 Symbol 属性)

      • 扩展运算符 ...遍历 对象自身、可枚举属性(不含继承)

      • Object.keys()遍历 对象自身、可枚举属性(不含继承、 不含 Symbol 属性)

      • JSON.stringify()只串行化 对象自身、可枚举的属性(不含继承)

      • Object.assign()拷贝 对象自身、可枚举属性(不含继承)

    5. 回顾:判断属性是否是 对象自身的 并且 可枚举 maObject.propertyIsEnumerable(property)

    • 返回值: 只有属性 既是自身属性,又可枚举, 才返回 true

    6. ES6:获取对象所有自身(不含继承)属性 的描述对象 Object.getOwnPropertyDescriptors

    const obj = {
      foo: 123,
      get bar() { return 'abc' }
    };
    
    const result = Object.getOwnPropertyDescriptors(obj)
    
    console.log(result);
    // { foo:
    //    { value: 123,
    //      writable: true,
    //      enumerable: true,
    //      configurable: true },
    //   bar:
    //    { get: [Function: get bar],
    //      set: undefined,
    //      enumerable: true,
    //      configurable: true } }
    

    六、对象原型 操作方法

    1. __proto__ 获取对象的原型对象:只有浏览器广泛支持(不推荐使用)

    • 声明: 该属性没有写入 ES6 的正文,标准明确规定,只有浏览器必须部署这个属性,其他运行环境不一定需要部署;所以在实际开发中不要使用该属性

    • 语法: obj.__proto__ 可以获取 obj 对象的原型对象

    2. ES6 设置 原型对象 Object.setPrototypeOf(object, prototype)

    • 语法:
      • 参数1:被操作对象

      • 参数2:原型对象

      • 返回值:被操作对象本身

    let proto = {};
    let obj = { x: 10 };
    Object.setPrototypeOf(obj, proto);
    
    proto.y = 20;
    proto.z = 40;
    
    obj.x // 10
    obj.y // 20
    obj.z // 40
    
    • 规定:
      • 如果第一个参数不是对象,会自动转为对象;由于返回的还是第一个参数,所以这个操作不会产生任何效果
      • 若第一个参数是 undefinednull(无法转成对象),会报错
    Object.setPrototypeOf(1, {}) === 1              // true
    Object.setPrototypeOf('foo', {}) === 'foo'      // true
    Object.setPrototypeOf(true, {}) === true        // true
    
    Object.setPrototypeOf(undefined, {});   // 报错
    Object.setPrototypeOf(null, {});        // 报错
    

    3. ES6 获取 原型对象 Object.getPrototypeOf(object)

    • 语法:
      • 参数:操作对象

      • 返回值:操作对象 的 原型对象

    七、关键字 super --- 指向 当前对象的原型对象(2个使用约束条件)

    • 关键字 super:指向当前对象的原型对象

    • 约束:

      • 只能用在 对象的 简写 方法 之中, 目前 super 在其他地方都会报错
    // 正确用法
    const obj = {
        find() {
            return super.foo;
        }
    };
    
    
    // 以下三种情况,都不允许,会报错
    const obj = {
        foo: super.foo              // 报错:super 用在了对象的属性中
    }
    
    
    const obj = {
        foo: () => super.foo        // 报错:super 用在了函数中,又将这个函数定义成对象的方法
    }
    
    
    const obj = {
        foo: function () {
            return super.foo        // 报错:super 用在了函数中,又将这个函数定义成对象的方法   
        }
    }
    

    八、 比较 任意数据类型的值 是否相等:Object.is( )

    • ES6提出: "Same-value equality" 的原则,对比较两个值是否相等,做了更严格的规范

    • 语法:

      • 参数1,参数2: 要比较是否相等的两个值 Object.is(a, b)

      • 返回值: 布尔值

    • 对比:

      • ES6中的比较方法 Object.is( ) :NaN 等于 NaN;-0 不等于 +0

      • ES5中的比较方法 == === :NaN 不等于 NaN;-0 等于 +0;== 会发生隐式转换

  • 相关阅读:
    构造函数作为友元函数的参数
    引用调用
    分块查找
    折半查找
    c++中map按key和value排序
    STL之map学习实例
    STL之stack
    STL之map
    STL之string
    STL之template类模板
  • 原文地址:https://www.cnblogs.com/zxvictory/p/8458109.html
Copyright © 2011-2022 走看看