ES6

ES6深入浅出之新版对象

Posted by weite122 on 2019-01-01

对象初始化

  • 新建一个空对象。可以通过new Object()Object.create()方法,或者使用字面量标记(初始化标记)初始化对象。 一个对象初始化器,由花括号/大括号 ({}) 包含的一个由零个或多个对象属性名和其关联值组成的一个逗号分隔的列表构成。

    1
    2
    3
    4
    var a = new Object()//有__proto__
    var b = Object.create(null)//无__proto__
    var c = Object.create(Object.prototype)//有__proto__
    var d = {}

属性访问

  • 创建对象后,可以读取或者修改它。对象属性可以用下标小圆点标记或者方括号标记访问。

    1
    2
    3
    4
    var name = "a"
    var object = {}
    object[name] =1
    // 可以缩写成object = { [name]: 1 }

重复属性名

  • 属性使用了同样的名称时,后面的属性会覆盖前面的属性。

    1
    2
    var a = {x: 1, x: 2};
    console.log(a); // { x: 2}

方法定义

  • 对象属性也可以是一个函数gettersetter方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var o = {
property: function ([parameters]) {},
get property() {},
set property(value) {},
};

var x = {
_age: 18,
get age(){
return x._age
},
set age(value){
if(value <100){
x._age = value
}else{
x._age = 100
}
}
}
  • 一道算法题 a === 1 && a===2 && a ===3
1
2
3
4
5
6
7
var i = 0
Object.defineProperty(window, 'a', {
get(){
i+=1
return i
}
})

计算属性名

  • 允许在[]中放入表达式,计算结果可以当做属性名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var i = 0;
    var a = {
    ["foo" + ++i]: i,
    ["foo" + ++i]: i,
    ["foo" + ++i]: i
    };

    console.log(a.foo1); // 1
    console.log(a.foo2); // 2
    console.log(a.foo3); // 3

扩展属性

  • 使用比Object.assign()更短的语法,可以轻松克隆(不包括原型)或合并对象。

    1
    2
    3
    4
    5
    6
    7
    8
    var obj1 = { foo: 'bar', x: 42 };
    var obj2 = { foo: 'baz', y: 13 };

    var clonedObj = { ...obj1 };
    // Object { foo: "bar", x: 42 }

    var mergedObj = { ...obj1, ...obj2 };
    // Object { foo: "baz", x: 42, y: 13 }
  • 请注意,Object.assign()会触发setter,而展开操作符则不会。

对象字面量表示法与JSON

  • JSON 只允许"property": value syntax形式的属性定义。属性名必须用双引号括起来。且属性定义不允许使用简便写法。
  • JSON中,属性的值仅允许字符串,数字,数组,truefalsenull或其他(JSON)对象。
  • JSON中,不允许将值设置为函数。
  • Date 等对象,经JSON.parse()处理后,会变成字符串。
  • JSON.parse() 不会处理计算的属性名,会当做错误抛出。

Object.defineProperty()

  • Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

  • 语法

    1
    Object.defineProperty(obj, prop, descriptor)

属性描述符

  • 对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。

  • 数据描述符和存取描述符均具有以下可选键值:

    • configurable
      • 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      var o = {name: "weite122"}
      Object.defineProperty(o, 'name', {writable:false})
      //{name: "weite122"}
      o.name = "xxx"// "xxx"
      o.name// "weite122"
      Object.defineProperty(o, 'name', {writable:true})//{name: "weite122"}
      o.name = "yyy"//"yyy"
      o.name//"yyy"
      Object.defineProperty(o, 'name', {writable:false,configurable:false})//强制不可读
      Object.defineProperty(o, 'name', {writable:true})//直接报错
    • enumerable
      • 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中,即可以遍历。默认为 false。
        1
        2
        3
        4
        5
        6
        7
        8
        var array = [1,2,3]
        for(let key in array){console.log(key)}// 0 1 2
        array['不想遍历的属性'] = '不想遍历的属性'
        for(let key in array){console.log(key)}// 0 1 2 不想遍历的属性
        Object.getOwnPropertyDescriptor(array, "不想遍历的属性")
        //{value: "不想遍历的属性", writable: true, enumerable: true, configurable: true}
        Object.defineProperty(array, "不想遍历的属性", {writable:false,enumerable:false,configurable:false})
        for(let key in array){console.log(key)}// 0 1 2
  • 数据描述符同时具有以下可选键值:

    • value

      • 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
    • writable

      • 当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false。
      1
      2
      3
      4
      5
      var o = {
      get name(){return 'weite122'}
      }
      Object.defineProperty(o, 'name2', {value:'weite122',writable:false})
      //name 和 name2 都是可读的变量,但name是通过set定义,name2是通过writable设置他可读性
  • 存取描述符同时具有以下可选键值:

    • get
      • 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。
      • 默认为 undefined。
    • set
      • 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。
      • 默认为 undefined。

Object.prototype.__proto__

  • 通过现代浏览器的操作属性的便利性,可以改变一个对象的 [[Prototype]] 属性, 这种行为在每一个JavaScript引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在 obj.proto = … 语句上, 它还会影响到所有继承来自该 [[Prototype]] 的对象,如果你关心性能,你就不应该在一个对象中修改它的 [[Prototype]].。相反, 创建一个新的且可以继承 [[Prototype]] 的对象,推荐使用 Object.create()。
  • 当Object.prototype.proto 已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在ECMAScript 2015规范中被标准化为传统功能,以确保Web浏览器的兼容性。为了更好的支持,建议只使用 Object.getPrototypeOf()。