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

    属性的简介表示法

    允许直接写入变量和函数作为对象的属性和方法,这样的书写更简洁。

    function f( x, y ) {
      return { x, y };
    }
    
    // 等同于
    
    function f( x, y ) {
      return { x: x, y: y };
    }
    
    var o = {
      method() {
        return "Hello!";
      }
    };
    // 等同于
    
    var o = {
      method: function() {
        return "Hello!";
      }
    };
    install
    var Person = {
    
      name: '张三',
    
      //等同于birth: birth
      birth,
    
      // 等同于hello: function ()...
      hello() { console.log('我的名字是', this.name); }
    
    };
    

    这种写法用于函数的返回值会非常方便

    //ES5
    function a(){
        var data = {};
        data.x =1;
        data.y = 10;
        data.z = 100;
        return data;
    }
    a(); //{x:1,y:10,z:100}
    //ES6
    function a() {
      var x = 1,y = 10,z = 100;
      return {x, y, z};
    }
    a(); //{x:1,y:10,z:100}
    

    CommonJS模块输出变量就非常适合这个简洁写法

    var ms = {};
    
    function getItem (key) {
      return key in ms ? ms[key] : null;
    }
    
    function setItem (key, value) {
      ms[key] = value;
    }
    
    function clear () {
      ms = {};
    }
    
    module.exports = { getItem, setItem, clear };
    //等同于
    module.exports = {
      getItem: getItem,
      setItem: setItem,
      clear: clear
    };
    

    属性的赋值器(setter)和取值器(getter)其实也用了这种写法.

    注意简洁写法中的属性名总是字符串,这会导致一些看上去奇怪的结果。

    var obj = {
        class(){};
    }
    //等同于
    var obj = {
        'class':function(){};
    }
    

    上面的代码中,class是字符串,所以不会因为它属于关键字而导致语法错误。

    如果某个方法的值是一个Generator函数,则其前面需要加上*。

    var obj = {
        *m(){
            yield 'hello world';
        }
    }
    

    属性名表达式

    ES6允许用表达式作为属性名,表达式要放在[ ]方括号内使用,而ES5只支持直接用标识符作为属性名

    //标识符
    var o = {
        obj : 1,
        obj2: 'test'
    }
    //表达式
    var obj = 'how are you';
    var o = {
      [obj]: 1,
      ['hello world']: 'test'
    };
    o[obj]; // 1
    o['hello world']; //test
    

    还可以用表达式定义方法名:

    var a = 'ello';
    var obj = {
      ['h'+ a]() {
        return 'hi Jack';
      }
    };
    
    obj.hello() // hi Jack
    

    注:属性名表达式与简洁表示法,不能同时使用

    // 错误写法
    var foo = 'bar';
    var bar = 'abc';
    var baz = { [foo] };
    
    // 正确写法
    var foo = 'bar';
    var baz = { [foo]: 'abc'};
    

    方法的name属性

    函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。

    var person = {
      sayName: function() {
        console.log(this.name);
      },
      get firstName() {
        return "Nicholas"
      }
    }
    

    有两种特殊情况:

    1. bind方法创建的函数,name属性返回“bound”加上原有函数名
    2. Function构造函数创造的函数,name属性返回“anonymous”
    var doSomething = function() {
      return;
    };
    (new Function()).name // "anonymous"              
    doSomething.bind().name // "bound doSomething"  
    person.sayName.name   // "sayName"                 
    person.firstName.name // "get firstName"  
    
    

    如果对象的方法是一个Sysbol值,那么name属性返回的是这个Sysbol值的描述。

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

    Object.is()

    Object.is用来比较两个值是否严格相等。它与严格比较运算符(===)的行为基本一致。

    不过它的不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

    +0 === -0 //true
    Object.is(+0, -0) // false
    
    NaN === NaN // false
    Object.is(NaN, NaN) // true
    

    ES5可以通过下面的代码,部署Object.is:

    Object.defineProperty(Object, 'is', {
      value: function(x, y) {
        if (x === y) {
          // 针对+0 不等于 -0的情况
          return x !== 0 || 1 / x === 1 / y;
        }
        // 针对NaN的情况
        return x !== x && y !== y;
      },
      configurable: true,
      enumerable: false,
      writable: true
    });
    

    Object.assign()

    Object.assign方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。

    var target  =  { a: 1 };
    var source1 = { b: 2 };
    var source2 = { c: 3 };
    
    Object.assign(target, source1, source2);
    target // {a:1, b:2, c:3}
    

    注:如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

    var target = { a: 1, b: 1 };
    var source1 = { b: 2, c: 2 };
    var source2 = { c: 3 };
    
    Object.assign(target, source1, source2);
    target // {a:1, b:2, c:3}
    

    Object.assign只拷贝自身属性,不可枚举的属性(enumerable为false)和继承的属性不会被拷贝。

    Object.assign({b: 'c'},
      Object.defineProperty({}, 'invisible', {
        enumerable: false,
        value: 'hello'
      })
    )
    // { b: 'c' }
    
    
    Object.assign({b: 'c'},
      Object.defineProperty({}, 'invisible', {
        enumerable: true,
        value: 'hello'
      })
    )
    // {b: "c", invisible: "hello"}
    

    属性名为Symbol值的属性,也会被Object.assign拷贝。

    Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' })
    // { a: 'b', Symbol(c): 'd' }
    

    对于嵌套的对象,Object.assign的处理方法是替换,而不是添加。

    var target = { a: { b: 'c', d: 'e' } }
    var source = { a: { b: 'hello' } }
    Object.assign(target, source)
    // { a: { b: 'hello' } }
    

    上面代码中,target对象的a属性被source对象的a属性整个替换掉了,而不会得到{ a: { b: 'hello', d: 'e' } }的结果。这通常不是开发者想要的,需要特别小心。有一些函数库提供Object.assign的定制版本(比如Lodash的_.defaultsDeep方法),可以解决深拷贝的问题。

    注意,Object.assign可以用来处理数组,但是会把数组视为对象。

    Object.assign([1, 2, 3], [4, 5])
    // [4, 5, 3]
    

    Object.assgin方法有很多处

    为对象添加属性
    class Point {
      constructor(x, y) {
        Object.assign(this, {x, y});
      }
    }
    

    这样就给Point类的对象实例添加了x、y属性。

    为对象添加方法
    Object.assign(SomeClass.prototype, {
      someMethod(arg1, arg2) {
        ···
      },
      anotherMethod() {
        ···
      }
    });
    
    // 等同于下面的写法
    SomeClass.prototype.someMethod = function (arg1, arg2) {
      ···
    };
    SomeClass.prototype.anotherMethod = function () {
      ···
    };
    

    上面代码使用了对象属性的简洁表示法,直接将两个函数放在大括号中,再使用assign方法添加到SomeClass.prototype之中。

    克隆对象
    function clone(origin) {
      return Object.assign({}, origin);
    }
    

    上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。

    不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。

    function clone(origin) {
      let originProto = Object.getPrototypeOf(origin);
      return Object.assign(Object.create(originProto), origin);
    }
    

    在JS里子类利用Object.getPrototypeOf去调用父类方法,用来获取对象的原型。用它可以模仿Java的super。

    将多个对象合并成一个对象

    多个对象合并到某个对象

    const merge =(target, ...sources) => Object.assign(target, ...sources);
    

    多个对象合并到一个新对象

    const merge = (...sources) => Object.assign({}, ...sources);
    
    为属性指定默认值
    const DEFAULTS = {
      logLevel: 0,
      outputFormat: 'html'
    };
    
    function processContent(options) {
      let options = Object.assign({}, DEFAULTS, options);
    }
    

    上面代码中,DEFAULTS对象是默认值,options对象是用户提供的参数。Object.assign方法将DEFAULTS和options合并成一个新对象,如果两者有同名属性,则option的属性值会覆盖DEFAULTS的属性值。

    注: 由于存在深拷贝的问题,DEFAULTS对象和options对象的所有属性的值,都只能是简单类型,而不能指向另一个对象。否则,将导致DEFAULTS对象的该属性不起作用。

  • 相关阅读:
    codeforces C. Fixing Typos 解题报告
    codeforces B. The Fibonacci Segment 解题报告
    codeforces B. Color the Fence 解题报告
    codeforces B. Petya and Staircases 解题报告
    codeforces A. Sereja and Bottles 解题报告
    codeforces B. Levko and Permutation 解题报告
    codeforces B.Fence 解题报告
    tmp
    API 设计 POSIX File API
    分布式跟踪的一个流行标准是OpenTracing API,该标准的一个流行实现是Jaeger项目。
  • 原文地址:https://www.cnblogs.com/huyuzhu/p/6523493.html
Copyright © 2011-2022 走看看