主要知识点有对象类别、属性速记法、方法简写、需计算属性名、Object.is()方法、Object.assign()方法、可允许重复的属性、自有属性的枚举顺序、Object.setPrototypeOf()方法、super引用、方法定义
对象类别
- 普通对象:拥有 JS 对象所有默认的内部行为。
- 奇异对象:其内部行为在某些方面有别于默认行为。
- 标准对象:在 ES6 中被定义的对象,例如 Array 、 Date ,等等。标准对象可以是普通的,也可以是奇异的。
- 内置对象:在脚本开始运行时由 JS 运行环境提供的对象。所有的标准对象都是内置对象。
对象字面量语法的扩展
属性初始化器的速记法
属性初始化器的速记法可以用来消除属性名和本地变量的重复情况,可以使用作用域内的变量值赋值给同名属性:
ES5 及更早版本中:
function createPerson(name, age) {
return {
name: name,
age: age
};
}
ES6简写:
function createPerson(name, age) {
return {
name,
age
};
}
方法简写
在对象字面量的写法中,为一个对象添加一个方法,需要指定对象的属性以及具体的函数声明。ES6提供了一种方法简写语法,通过省略function关键字,能够让为对象添加方法的语法更加简洁。
ES5中的写法:
var person = {
name: "Nicholas",
sayName: function() {
console.log(this.name);
}
};
ES6简写语法:
var person = {
name: "Nicholas",
sayName() {
console.log(this.name);
}
};
需计算属性名
需计算属性名规则允许对象字面量中属性名是变量、字符串字面量或者由变量计算而得的,具体写法是通过方括号[]包含属性名。
var lastName = "last name";
var person = {
"first name": "Nicholas",
[lastName]: "Zakas"
};
console.log(person["first name"]); // "Nicholas"
console.log(person[lastName]); // "Zakas"
var suffix = " name";
var person = {
["first" + suffix]: "Nicholas",
["last" + suffix]: "Zakas"
};
console.log(person["first name"]); // "Nicholas"
console.log(person["last name"]); // "Zakas"
const id = 5
const obj = {
[`my-${id}`]: id
}
console.log(obj['my-5']) // 5
新的方法:Object.is()和Object.assign()
Object.is() 方法
JS中比较两个值是否相同的时候会使用严格等于运算符===,但是,使用严格运算符式,+0和-0会认为这两者是相等的,而NaN===NaN是不相等的,使用Object.is()方法来判断这两者情况与使用严格相等符会有所不同,其他情况和使用严格相等运算符基本一致;
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(5 == 5); // true
console.log(5 == "5"); // true
console.log(5 === 5); // true
console.log(5 === "5"); // false
console.log(Object.is(5, 5)); // true
console.log(Object.is(5, "5")); // false
Object.assign() 方法
混入( Mixin )是在 JS 中组合对象时最流行的模式。在一次混入中,一个对象会从另一个对象中接收属性与方法。
下面是一个mixin方法的实现,这个方法实现的是浅拷贝。将b对象的属性拷贝到了a对象,合并成一个新的对象。
//mixin不只有这一种实现方法。
function mixin(receiver, supplier) {
Object.keys(supplier).forEach((key) => {
receiver[key] = supplier[key]
})
return receiver
}
let a = {name: 'sb'};
let b = {
c: {
d: 5
}
}
console.log(mixin(a, b)) // {"name":"sb","c":{"d":5}}
写这样一个mixin方法是不是很烦,而且每个项目都得引入这个方法,现在,ES6给我们提供了一个现成的方法Object.assign()来做mixin的事情。
假设要实现上面的mixin方法,你只需要给Object.assign()传入参数即可。
console.log(Object.assign(a, b))// {"name":"sb","c":{"d":5}}
重复的对象字面量属性
ES5 严格模式为重复的对象字面量属性引入了一个检查,若找到重复的属性名,就会抛出错误。
"use strict";
var person = {
name: "Nicholas",
name: "Greg" // 在 ES5 严格模式中是语法错误
};
ES6 移除了重复属性的检查,严格模式与非严格模式都不再检查重复的属性。当存在重复属性时,排在后面的属性的值会成为该属性的实际值:
"use strict";
var person = {
name: "Nicholas",
name: "Greg" // 在 ES6 严格模式中不会出错
};
console.log(person.name); // "Greg"
自有属性的枚举顺序
ES5 并没有定义对象属性的枚举顺序,而是把该问题留给了 JS 引擎厂商。而 ES6 则严格定义了对象自有属性在被枚举时返回的顺序。这对 Object.getOwnPropertyNames() 与Reflect.ownKeys)如何返回属性造成了影响,还同样影响了Object.assign() 处理属性的顺序。
自有属性枚举时基本顺序如下:
- 所有的数字类型键,按升序排列。
- 所有的字符串类型键,按被添加到对象的顺序排列。
- 所有的符号类型(详见第六章)键,也按添加顺序排列。
const state = {
id: 1,
5: 5,
name: "eryue",
3: 3
}
Object.getOwnPropertyNames(state)
//["3","5","id","name"] 枚举key
Object.assign(state, null)
//{"3":3,"5":5,"id":1,"name":"eryue"}
for-in 循环的枚举顺序仍未被明确规定,因为并非所有的 JS 引擎都采用相同的方式。而 Object.keys() 和 JSON.stringify() 也使用了与 for-in 一样的枚举顺序。
更强大的原型
一般来说,对象的原型会在通过构造器或 Object.create() 方法创建该对象时被指定。
ES5 添加了 Object.getPrototypeOf() 方法来从任意指定对象中获取其原型;
缺少在初始化之后更改对象原型的标准方法。
修改对象的原型
ES6 通过添加 Object.setPrototypeOf() 方法而改变了这种假定,此方法允许你修改任意指定对象的原型。它接受两个参数:需要被修改原型的对象,以及将会成为前者原型的对象。
let person = {
getGreeting() {
return "Hello";
}
};
let dog = {
getGreeting() {
return "Woof";
}
};
// 原型为 person
let friend = Object.create(person);
console.log(friend.getGreeting()); // "Hello"
console.log(Object.getPrototypeOf(friend) === person); // true
// 将原型设置为 dog
Object.setPrototypeOf(friend, dog);
console.log(friend.getGreeting()); // "Woof"
console.log(Object.getPrototypeOf(friend) === dog); // true
使用 super 引用的简单原型访问
能够使用super引用,来访问原型中的方法:
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
注意,super关键字表示原型对象时,只能用在对象的简写方法之中,用在其他地方都会报错。
// 报错
const obj = {
foo: super.foo
}
// 报错
const obj = {
foo: () => super.foo
}
// 报错
const obj = {
foo: function () {
return super.foo
}
}
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"
上面代码中,super.foo指向原型对象proto的foo方法,但是绑定的this却还是当前对象obj,因此输出的就是world。
正式的“方法”定义
ES6 则正式做出了定义:方法是一个拥有 [[HomeObject]] 内部属性的函数,此内部属性指向该方法所属的对象。
let person = {
// 方法
getGreeting() {
return "Hello";
}
};
// 并非方法
function shareGreeting() {
return "Hi!";
}
大多数情况下,这种差异并不重要,然而使用 super 引用时就完全不同了。
let person = {
getGreeting() {
return "Hello";
}
};
// 原型为 person
let friend = {
getGreeting() {
return super.getGreeting() + ", hi!";
}
};
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting()); // "Hello, hi!"
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。