扩展对象的功能性
属性名称简写
let name = 'ligang'
let person = {
name,
sayName() {
console.log(name)
}
}
javascript引擎会在访问作用域中查找其同名变量;如果找到,则变量的值被赋给对象字面量的同名属性。
Object.is()
Object.is()
方法是为了弥补全等运算符’===’的准确性,其接受两个参数,如果两个参数类型相同且具有相同的值,则返回true。
console.log(+0 === =0) // true
console.log(Object.is(+0, -0)) // false
console.log(NaN === NaN) // false
console.log(Object.is(NaN, NaN)) // true
console.log(isNaN(NaN)) // true
注意:map.get()
底层使用的就是Object.is()
进行判断获取
let myMap = new Map().set('0', 'xxx')
myMap.get(0) // undefined
myMap.get('0') // xxx
Object.assign()
对象组合,浅拷贝
自有属性枚举顺序
ESMAScript6严格定义了对象的自有属性被枚举时的返回顺序,这会影响到Object.getOwnPropertyNames()
方法及Reflect.ownKeys
返回属性的方式,Object.assign()
方法处理属性的顺序也将随之改变。
- 所有数字键按照升序排序;
- 所有字符串按照它们被加入对象的顺序排序;
- 所有symbol键按照它们被加入对象的顺序排序。
let obj = {
a: 1,
0: 1,
c: 1,
2: 1,
b: 1,
1: 1
}
Object.getOwnPropertyNames(obj) // ["0", "1", "2", "a", "c", "b"]
注意,for-in
并非所有厂商都遵循相同的实现方式;Object.keys()
和JSON.stringify()
与for-in
相同,所以目前也不明确!
原型访问super
let person = {
sayHi() {
return 'hi'
}
}
let friend = {
sayHi() {
// 获取其原型方法
return Object.getPrototypeOf(this).sayHi.call(this) + ' friend'
}
}
let friend2 = {
sayHi() {
return super.sayHi() + ' friend2'
}
}
Object.setPrototypeOf(friend, person);
friend.sayHi() // "hi friend"
Object.setPrototypeOf(friend2, person);
friend2.sayHi() // "hi friend2"
函数
函数形参的默认值
ES5方式
function test(name) {
name = (typeof name !== 'undefined') ? name : 'ligang'
// name = name || 'ligang' // 当name为假值时会出现问题!!如,test(0)
return name
}
ES6:注意,对于默认参数值,null是一个合法值
function test(name = 'ligang') {
return name
}
test(undefined) // ligang
test(null) // null
默认参数表达式
function getvalue(n) {
return n
}
function add(first, second = getvalue(first)) {
return first + second
}
add(100) // 200
注意:
-
getvalue()
方法只有当调用add()
函数且不传入第二个参数时才会调用;
- 引用参数默认值时,只允许引用前面参数的值,即先定义的参数不能访问后面定义的参数。
展开运算符
数组
let ary = [1, 2, 3]
let max = Math.max(...ary, 5)
console.log(max) // 5
对象
let obj = {a: 1, b: {c: 2}}
let obj2 = {...obj}
obj.b.c = 3
console.log(obj2) // {a: 1, b: {c: 3}} 浅拷贝
特别说明:
ES6中展开运算符只针对iterable才起作用,默认有数组、set、map和字符串。并不包含对象!ES6规范中也并未将展开运算符支持对象,但是目前的主流浏览器Chrome和firefox均已实现该特性。这意味着如果想在低版本浏览器中使用需要特别的Babel插件进行转换!object-rest-spread

明确函数的多重用途
JavaScript函数有两个不同的内部方法:[[Call]]和[[Construct]](构造函数)。通过new关键字调用函数时,执行的是[[Construct]]函数,将this绑定到实例上;如果不通过new调用,则执行[[Call]]函数。
function Person(name) {
if (this instanceof Person) {
this.name = name
} else {
throw new Error('必须通过new关键词创建')
}
}
let p = new Person('ligang')
Person.call(p, 'lee') // 不会报错
所以,我们无法区分通过Person.call()
(或Person.apply()
)调用还是new关键字创建!
元属性new.target可以解决,调用[[call]]方法,new.target的值为undefined。
function Person(name) {
if (typeof new.target !== 'undefined') {
this.name = name
} else {
throw new Error('必须通过new关键词创建')
}
}
let p = new Person('ligang')
Person.call(p, 'lee') // 必须通过new关键词创建
箭头函数
- 没有this、super、arguments河new.target绑定;
- 不能通过new关键字调用;
- 没有原型;
- 不可以改变this的绑定;
如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this;否则,this的值会被设置为undefined。
let person = {
name: 'ligang',
sayName() {
return (() => this.name)()
}
}
尾调用优化
ES6对尾调用(函数作为另一个函数的最后一条语句被调用)进行了优化。ES5中,尾调用实现为“创建一个新的栈,将其推入调用栈来表示函数调用,即未用完的栈都在内存中,当调用栈变大会造成程序内存溢出”。ES6中不在创建新栈,会清除并重新利用当前栈。
- 尾调用不访问当前栈的变量(即不是一个闭包);
- 在函数内部,尾调用是最后一条语句;
- 尾调用的结果作为函数值返回。
function factorial(n) {
if (n <= 1) {
return 1
}
return n * factorial(n - 1)
}
优化后
function factorial(n, p = 1) {
if (n <= 1) {
return 1 * p
}
let result = n * p
return factorial(n - 1, result)
}