对象的扩展

简洁的属性表达

  1. ES6 允许直接写入变量和函数,作为对象的属性和方法;

  2. 属性值、方法简写

    JavaScript
    JavaScript
    // ES5
    function getObj(x, y) {
      return {x: x, y: y};
    }
    
    // 等同于 ES6
    function getObj(x, y) {
      return {x, y};
    }
    
    getObj(1, 2) // {x: 1, y: 2}
    
    var person = {};
    
    function getName () {
      return person.name
    }
    function setName () {
      person.name = '李四'
    }
    function clear () {
      person = {};
    }
    
    // ES5 写法
    module.exports = {
      getName: getName
      setName: setName,
      clear: clear
    };
    
    // ES6写法
    module.exports = { getName, setName, clear };
    

属性名表达式

  1. ES5 定义字面量对象;

    var obj = {
      name: 'ricepudding',
      age: 7
    }
    
  2. ES6 对对象的属性进行了扩展,可以覆盖更多的场景,属性可以使用变量的形式来定义;

    JavaScript
    JavaScript
    JavaScript
    // 字面量对象中的属性是可以放在中括号中,中括号中的可以是变量,也可以是表达式
    var key = 'name';
    var obj = {
      [key]: 'ricepudding',
      ['a' + 'ge']: 7
    }
    
    // 属性也可以是一个带空格的字符串,在取值时在中括号中可以直接使用字符串,也可以使用变量
    var str = 'first name';
    var obj = {
      ['I love ricepudding']: 'ES6 Wiki',
      [str]: 'Jack'
    }
    console.log(obj['I love ricepudding'])	// ES6 Wiki
    console.log(obj[str])	// Jack
    console.log(obj['first name'])	// Jack
    
    // 表达式还可以用于定义对象上的方法名
    var person = {
      name: 'Jack',
      ['get' + 'Name']() {
        console.log(this.name)
      }
    };
    console.log(person.getName())	// Jack
    
  3. 注意:

    JavaScript
    JavaScript
    JavaScript
    // 属性名表达式与属性简洁表示,不能同时使用,会报错
    // 报错
    var name = 'Jack';
    var age = 18;
    var person = { [name] }; // Uncaught SyntaxError: Unexpected token '}'
    
    var name = 'Jack';
    var person = { [name]: 18 };	// {Jack: 18}
    
    // 属性名必须是字符串类型的,如果属性表达式是一个对象,则会先调 toString() 先将对象转为字符串,然后才进行使用
    var key1 = {name: 'ricepudding'};
    var key2 = {age: 7};
    var obj = {
      [key1]: 'value content 1',
      [key2]: 'value content 2',
    }
    console.log(obj);	// {[object Object]: "value content 2"}
    
    // 如果属性的表达式是数组时,则和对象不一样。数组在 toString() 后会变成一个字符串,所以对象属性的表达式就是一个字符串
    var keys = ['ricepudding', '7'];
    var obj = {
      [keys]: 'value content',
    };
    console.log(key.toString());	// "ricepudding,7"
    console.log(obj);		// {ricepudding,7: "value content"}
    console.log(obj[keys]);	// "value content"
    

方法的 name 属性

  1. ES6 增加了函数的 name 属性,函数直接调用 name 会返回函数名,字面量对象上的方法也是函数,因此也有 name 属性;

    var person = {
      name: "Jack",
      getName() {
        console.log(this.name);
      },
    };
    
    person.getName.name // "getName"
    
  2. 有两种特殊情况:

    • Function 构造函数创造的函数,name 属性返回 “anonymous”
    • bind 方法创造的函数,name 属性返回 “bound” 加上原函数的名字;
    (new Function()).name // "anonymous"
    
    var doSomething = function() { };
    doSomething.bind().name // "bound doSomething"
    
  3. 如果对象的方法是一个 Symbol 值,那么 name 属性返回的是带中括号的 Symbol 的描述内容;

    const key1 = Symbol('description content');
    const key2 = Symbol();
    let obj = {
      [key1]() {},
      [key2]() {},
    };
    obj[key1].name // "[description content]"
    obj[key2].name // ""
    

可选链操作符(?.)

  1. 可选链操作符使用 ?. 来表示,可以判断操作符之前属性是否有效,从而链式读取对象的属性或返回 undefined

    obj?.prop     // 对象上的属性
    obj?.[expr]   // 对象上的属性可以是一个表达式
    arr?.[index]  // 对数组使用时,可以接数组的位置
    func?.(args)  // 对函数使用时,可以接收传入的参数
    
  2. 使用场景

    JavaScript
    JavaScript
    JavaScript
    JavaScript
    // 可选链和表达式
    let firstName = obj?.['first' + 'Name'];
    
    // 可选链与函数调用
    var person = {};
    var name = person.getName?.();
    
    // 可选链不能用于赋值
    let obj = {};
    obj?.name = 'ricepudding';	// Uncaught SyntaxError: Invalid left-hand side in assignment
    
    // 可选链访问数组元素
    var arr = [];
    let item = arr?.[5];
    

空值合并运算符(??)

  1. ?? 运算符称为 空值合并运算符,用来判断一个值是否为 nullundefined,与 短路或 || 的使用方式一样;

  2. 使用场景

    const result1 = 0 ?? 10;
    const result2 = null ?? 10;
    
    console.log(result1); // 输出 0
    console.log(result2); // 输出 10
    

空赋值运算符(??=)

  1. ??= 也被称为空赋值运算符,仅当值为 nullundefined 时,此赋值运算符才会赋值;

  2. 使用场景

    var x = null;
    var y = 5;
    
    console.log(x ??= y); // => 5
    console.log(x = (x ?? y)); // => 5
    

对象方法的扩展

Object.is()

  1. Object.is() 会接收两个需要判断的参数,最后返回一个布尔值,如果相同则返回 true 否则返回 false

  2. 基本使用

    Object.is('ricepudding', 'ricepudding');  // true
    Object.is('ricepudding', 'rice');   // false
    
    Object.is(window, window);    // true
    Object.is([], []);           // false
    
    var foo = { a: 1 };
    var bar = { a: 1 };
    var obj = foo;
    Object.is(foo, foo);         // true
    Object.is(foo, bar);         // false
    Object.is(foo, obj);         // true
    
    Object.is(null, null);       // true
    
    // 特例
    Object.is(0, -0);            // false
    Object.is(0, +0);            // true
    Object.is(-0, -0);           // true
    Object.is(NaN, 0/0);         // true
    
  3. 对比等号 (=)

    JavaScript
    JavaScript
    JavaScript
    // == 是一个非严格相等的对比运算符,它只会对比两边的操作数是否相等,相等则会返回 true。如果对比的操作数类型不同,则会自动将值进行隐式转换为一种常见的类型
    
    0 == -0 			// true
    0 == '0' 			// true
    0 == false          // true
    0 == ''        		// true
    "" == false         // true
    null == undefined   // true
    1 == '1'  		    // true
    true == 'true' 		// false
    NaN == 'NaN' 		// false
    NaN == NaN 			// false
    
    {"name": "ricepudding"} == {"name": "ricepudding"} // false
    
    let a = {"name": "ricepudding"}
    let b = a
    console.log(a == b) // true
    
    // === 运算符:=== 是严格相等的,被称作全等操作符,和 == 很相似,区别在于 === 不执行隐式类型转换。只有当两个操作值的值与类型都相等的前提下,才会返回 true
    
    +0 === -0             // true
    true === true 				// true
    null === null 				// true
    NaN === NaN 					// false, NaN永远不等于NaN
    
    1 === '1' 						// false, 值类型不同:数值和字符串
    true === 'true' 			// false
    null === undefined 		// false
    
    'hello' === 'Hello' 	// false, 严格区分大小写
    
    // Object.is()
    
    // 1. 当操作值都没有被定义时,这时它们的值是 undefined
    let a
    let b
    Object.is(a,b) // true
    
    // 2. Object.is() 也是严格区分大小写的
    Object.is('Ricepudding', 'Ricepudding') // true
    Object.is('Ricepudding', 'ricepudding') // false
    
    // 3. 操作值的类型必须相同,无论是什么值,只要类型不一样就会返回 false
    Object.is(null, 'null') // false
    Object.is(undefined, 'undefined') // false
    
    // 4. 判断引用类型的值时,引用类型的地址相同时,则相等,与 == 和 === 判断的结果是一样的
    let a = {"name": "ricepudding"}
    let b = a
    Object.is(a, b) // true
    Object.is({"name": "ricepudding"}, {"name": "ricepudding"}) // false
    Object.is(window, window) 		// true, 只有一个window全局变量
    
    // 5. 操作数是 0、+0、-0 的比较,0 和 +0 是相等的,因为正号可以省略,但是 0 和 -0 是不相等的,这样就和 === 判断的结果不一样了
    Object.is(0, +0) 	// true
    Object.is(0, -0) 	// false
    
    // 6. 当两个操作值是 NaN 时,使用 Object.is() 返回的结果是 true 这个和 === 返回的结果不一样,如果计算的结果是 NaN 的话,返回的结果也是 true
    Object.is(NaN, NaN) 	// true
    Object.is(NaN, 0/0) 	// true
    

Object.assign()

  1. Object.assign() 把一个对象复制到另一个对象,在 ES5 中需要循环对象进行拷贝;

  2. 使用示例

    JavaScript
    JavaScript
    JavaScript
    JavaScript
    JavaScript
    JavaScript
    // 拷贝对象
    let target = {};
    let source = { a: 1, b: 2, c: 3 };
    Object.assign(target, source);
    target.d = 4;
    console.log(target)   // {a: 1, b: 2, c: 3, d: 4}
    console.log(source)   // {a: 1, b: 2, c: 3}
    
    // 合并对象
    let target = { a: 1 };
    let source1 = { b: 2 };
    let source2 = { c: 3 };
    Object.assign(target, source1, source2);
    console.log(target);  // {a: 1, b: 2, c: 3}
    
    // 覆盖前面的值
    let target = { a: 1, b: 1 };
    let source1 = { b: 2, c: 2 };
    let source2 = { c: 3 };
    Object.assign(target, source1, source2);
    console.log(target);  // {a: 1, b: 2, c: 3}
    
    // 浅拷贝(需要深拷贝则需要,需要递归地使用去 Object.assign() 来拷贝对象)
    var target = {};
    var source = { a: 1, b: { c: 2, d: 3 } };
    Object.assign(target, source);
    
    target.a = 5;
    target.b.c = 9;
    console.log(target)   // {a: 5, b: {c: 9, d: 3}}
    console.log(source)   // {a: 1, b: {c: 9, d: 3}}
    
    // 基本类型的合并
    console.log(Object.assign({}, "abc")); // { '0': 'a', '1': 'b', '2': 'c' }
    console.log(Object.assign({}, null)); // {}
    console.log(Object.assign({}, undefined)); // {}
    console.log(Object.assign({}, true)); // {}
    console.log(Object.assign({}, 10)); // {}
    console.log(Object.assign({}, Symbol("foo"))); // {}
    console.log(Object.assign({}, "abc", null, true, undefined, 10, Symbol("foo"))); // { '0': 'a', '1': 'b', '2': 'c' }
    
    // 拷贝异常时会被打断:在拷贝时如果发生异常,则拷贝会被终止,并报错,前面已经被拷贝的不会被影响可以继续使用,但后面没有被拷贝的则不能被使用
    var target = Object.defineProperty({}, "a", {
      value: 1,
      writable: false
    });
    Object.assign(target, { b: 2 }, { a: 3 }, { c: 4 });
    // Uncaught TypeError: Cannot assign to read only property 'a' of object '
    console.log(target);  // {b: 2, a: 1}
    

Object.keys()

  1. 基本实例

    var obj =  {
      name:  'hello',
      type:  'ES6 Wiki'
    }
    console.log(Object.keys(obj)); // ["name", "type"]
    
    var arr = ['a',  'b',  'c'];
    console.log(Object.keys(arr)); // console: ['0', '1', '2']
    
    var obj =  {  0:  'a',  1:  'b',  2:  'c'  };
    console.log(Object.keys(obj));  // ['0', '1', '2']
    
    var obj =  {  name:  'hello',  10:  'a',  3:  'b',  age:  7  };
    console.log(Object.keys(obj)); // ["3", "10", "name", "age"]
    
  2. 自动排序问题

    1. 如果属性名的类型是 Number,那么 Object.keys 返回值是按照 key 从小到大排序;
    2. 如果属性名的类型是 String,那么 Object.keys 返回值是按照属性被创建的时间升序排序;
    3. 如果属性名的类型是 Symbol,那么逻辑同 String 相同;

Object.values()

  1. Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for…in 循环的顺序相同 (区别在于 for-in 循环枚举原型链中的属性)

  2. Object.keys() 相反一个是获取 key,一个是获取 value,其他的使用特性基本相同;

    1. 参数是数值或布尔值:Object.values()Object.keys() 一样都会进行类型转换,所以传入的是数字或布尔值时,则返回一个空数组;
    2. 键排序问题:Object.values() 返回的数组是按 Object.keys() 顺序后的结果展示的,所以得到的值要和排序后的属性一一对应;
    3. 参数为字符串:传入的对象如果是一个字符串时,则会把字符拆成数组中的单个项;

Object.entries()

  1. Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组;

  2. 示例

    var obj = {a: 1, b: 2, c: 3};
    console.log(Object.entries(obj)); // [['a', 1], ['b', 3], ['c', 3]]
    
    Object.entries(50);       // []
    Object.entries(false);    // []
    
    var obj = {10: 'a', 1: 'b', 7: 'c'};
    console.log(Object.entries(obj)); // [["1", "b"], ["7", "c"], ["10", "a"]]
    
    console.log(Object.entries('abc')); // [["0", "a"], ["1", "b"], ["2", "c"]]
    

Object.fromEntries()

  1. Object.fromEntries()Object.entries() 的反转函数,这样理解起来就比较轻松,它接收的是一个可迭代的对象,类似 Array、Map 或者其它实现了可迭代协议的对象,结果返回一个新的对象;

  2. 示例:

    JavaScript
    JavaScript
    // 数组转化为对象
    var arr = [ ['a', '0'], ['b', '1'], ['c', '2'] ];
    var obj = Object.fromEntries(arr);
    console.log(obj); // {a: "0", b: "1", c: "2"}
    
    // Map 转化为对象
    var map = new Map();
    map.set('name', 'hello');
    map.set('age', 7);
    console.log(map);     // Map(2) {"name" => "hello", "age" => 7}
    
    var obj = Object.fromEntries(map);
    console.log(obj);     // {name: "hello", age: 7}
    
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 对象的扩展
    1. 1.1. 简洁的属性表达
    2. 1.2. 属性名表达式
    3. 1.3. 方法的 name 属性
    4. 1.4. 可选链操作符(?.)
    5. 1.5. 空值合并运算符(??)
    6. 1.6. 空赋值运算符(??=)
  2. 2. 对象方法的扩展
    1. 2.1. Object.is()
    2. 2.2. Object.assign()
    3. 2.3. Object.keys()
    4. 2.4. Object.values()
    5. 2.5. Object.entries()
    6. 2.6. Object.fromEntries()