笔记
属性初始化器的速记法
局部变量为对象同名属性赋值1
2
3
4
5
6function createPerson(name, age) {
return {
name,
age
};
}
方法简写
省略冒号与 function 关键字1
2
3
4
5
6var person = {
name: "Nicholas",
sayName() {
console.log(this.name);
}
};
使用方法简写速记法创建的方法,其 name 属性就是括号之前的名称。
可计算属性名
方括号允许指定变量或字符串字面量为属性名1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 第一种用法
var person = {},
lastName = "last name";
person["first name"] = "Nicholas";
person[lastName] = "Zakas";
console.log(person["first name"]); // "Nicholas"
console.log(person[lastName]); // "Zakas"
// 第二种用法
var lastName = "last name";
var person = {
"first name": "Nicholas",
[lastName]: "Zakas"
};
// 第三种用法
var suffix = " name";
var person = {
["first" + suffix]: "Nicholas",
["last" + suffix]: "Zakas"
};
新的方法
Object.is() 方法
绝大多数情况下, Object.is() 的结果与 === 运算符是相同的
仅有的例外是:它会认为+0 与 -0 不相等,而且 NaN 等于 NaN
Object.assign() 方法
重复的对象字面量属性
1 | var person = { |
自有属性的枚举顺序
Object.getOwnPropertyNames()
- 所有的数字类型键,按升序排列。
- 所有的字符串类型键,按被添加到对象的顺序排列。
- 所有的符号类型( 详见第六章) 键,也按添加顺序排列。
1
2
3
4
5
6
7
8
9
10var obj = {
a: 1,
0: 1,
c: 1,
2: 1,
b: 1,
1: 1
};
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join("")); // "012acbd"
对于 for-in 循环,并非所有的 JS 引擎都采用相同的处理方式,其枚举顺序仍未被明确规定。而 Object.keys() 和 JSON.stringify() 也使用了与 for-in 一样的枚举顺
序。
更强大的原型
###修改对象的原型
对象原型的实际值被存储在一个内部属性 [[Prototype]] 上
- ES5 添加了 Object.getPrototypeOf() 方法来获取任意指定对象的原型
- Object.setPrototypeOf() 接受两个参数:需要被修改原型的对象,以及将会成为前者原型的对象
###使用 super 引用的简单原型访问- 简单来说, super 是指向当前对象的原型的一个指针
1
2
3
4
5
6
7let friend = {
getGreeting() {
// 这相当于上个例子中的:
// Object.getPrototypeOf(this).getGreeting.call(this)
return super.getGreeting() + ", hi!";
}
};
- 简单来说, super 是指向当前对象的原型的一个指针
- 试图在方法简写之外的情况使用 super 会导致语法错误
1
2
3
4
5
6let friend = {
getGreeting: function() {
// 语法错误
return super.getGreeting() + ", hi!";
}
};
正式的“方法”定义
- ES6 则正式将方法定义为:一个拥有 [[HomeObject]] 内部属性的函数,此内部属性指向该方法所属的对象。
1
2
3
4
5
6
7
8
9
10
11let person = {
// 方法
getGreeting() {
return "Hello";
}
};
// 并非方法
function shareGreeting() {
return "Hi!";
}
总结
第六章 符号与符号属性
创建符号值
使用全局 Symbol 函数来创建一个符号值
1
2
3
4let firstName = Symbol();
let person = {};
person[firstName] = "Nicholas";
console.log(person[firstName]); // "Nicholas"Symbol 函数还可以接受一个额外的参数用于描述符号值,该描述并不能用来访问对应属性,但它能用于调试,例如:
1
2
3
4
5
6let firstName = Symbol("first name");
let person = {};
person[firstName] = "Nicholas";
console.log("first name" in person); // false
console.log(person[firstName]); // "Nicholas"
console.log(firstName); // "Symbol(first name)"由于符号值是基本类型的值,因此调用 new Symbol() 将会抛出错误
- 可以使用 typeof 运算符来判断一个变量是否为符号
使用符号值
你可以在任意能使用“可计算属性名”的场合使用符号。共享符号值
符号值的转换
检索符号属性
使用知名符号暴露内部方法
Symbol.hasInstance 属性
Symbol.isConcatSpreadable
Symbol.match 、 Symbol.replace 、Symbol.search 与 Symbol.split
###Symbol.toPrimitiveSymbol.toStringTag
识别问题的变通解决方法
ES6 给出的答案
Symbol.unscopables
总结
第七章 Set与Map
第九章 JS的类
ES5 中的仿类结构
- 创建一个构造器,然后将方法指派到该构造器的原型上
1
2
3
4
5
6
7
8
9
10function PersonType(name) {
this.name = name;
}
PersonType.prototype.sayName = function() {
console.log(this.name);
};
let person = new PersonType("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonType); // true
console.log(person instanceof Object); // true
类的声明
基本的类声明
类声明以 class 关键字开始,其后是类的名称;剩余部分的语法看起来就像对象字面量中的方法简写,并且在方法之间不需要使用逗号:
1
2
3
4
5
6
7
8
9
10class PersonClass {
// 等价于 PersonType 构造器
constructor(name) {
this.name = name;
}
// 等价于 PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
}自有属性(Own properties ) :该属性出现在实例上而不是原型上,只能在类的构造器或方法内部进行创建。
为何要使用类的语法
尽管类与自定义类型之间有相似性,但仍然要记住一些重要的区别:
- 类声明不会被提升,这与函数定义不同。类声明的行为与 let 相似,因此在程序执行到声明处之前,类都会位于暂时性死区内。
- 类声明中的所有代码会自动运行并锁定在严格模式下
- 类的所有方法都是不可枚举的,这是对于自定义类型的显著变化,后者必须用 Object.defineProperty() 才能将方法改变为不可枚举。
- 类的所有方法内部都没有 [[Construct]] ,因此使用 new 来调用它们会抛出错误。
- 调用类构造器时不使用 new ,会抛出错误。
- 试图在类的方法内部重写类名,会抛出错误。
1
2
3
4
5
6
7class Foo {
constructor() {
Foo = "bar"; // 执行时抛出错误
}
}
// 但在类声明之后没问题
Foo = "baz";
类表达式
基本的类表达式
1 | let PersonClass = class { |
具名类表达式
1 | let PersonClass = class PersonClass2 { |