(一)正则的扩展
1、添加了 u 修饰符,含义为“Unicode 模式”,用来正确处理大于 \uFFFF 的 Unicode 字符。也就是说,会正确处理四个字节的 UTF-16 编码。
2、新增 unicode 属性,表示是否设置了 u 修饰符。
3、加了 y 修饰符,叫做“粘连”(sticky)修饰符
4、与 y 修饰符相匹配,ES6 的正则实例对象多了 sticky 属性,表示是否设置了 y 修饰符
5、新增了 flags 属性,会返回正则表达式的修饰符。
四个字符属于“行终止符”。
U+000A 换行符( \ |
( 二 )数值的扩展
1、二进制和八进制数值的新的写法,分别用前缀 0b (或 0B )和 0o (或 0O )表示。
2、新提供了 Number.isFinite() 和 Number.isNaN() 两个方法
注传统方法先调用 Number() 将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效, Number.isFinite() 对于非数值一律返回 false , Number.isNaN() 只有对于 NaN 才返回 true ,非 NaN 一律返回 false 。3、将全局方法 parseInt() 和 parseFloat() ,移植到 Number 对象上面,行为完全保持不变。
4、 Number.isInteger() 用来判断一个数值是否为整数。
5、新增一个极小的常量 Number.EPSILON 。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。
6、JavaScript 能够准确表示的整数范围在 -2^53 到 2^53 之间(不含两个端点) Number.isSafeInteger() 则是用来判断一个整数是否落在这个范围之内
7、 Math.trunc 方法用于去除一个数的小数部分,返回整数部分
8、 Math.sign 方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。 它会返回五种值。
- 参数为正数,返回 +1 ;
- 参数为负数,返回 -1 ;
- 参数为 0,返回 0 ;
- 参数为-0,返回 -0 ;
- 其他值,返回 NaN
9、 Math.cbrt 方法用于计算一个数的立方根。
10、 新增了一个指数运算符( ** )
2 ** 3
// 8(三)函数的扩展
1、参数默认值可以与解构赋值的默认值,结合起来使用。
指定了默认值以后,函数的 length 属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后, length 属性将失真。function fetch(url, { body = '', method = 'GET', headers = {} }) {
console.log(method);
}2、引入 rest 参数(形式为 …变量名 ),用于获取函数的多余参数,这样就不需要使用 arguments 对象了
3、ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
4、ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的 name 属性,会返回空字符串,而 ES6 的 name 属性会返回实际的函数名。
Function 构造函数返回的函数实例, name 属性的值为 anonymous 。(new Function).name
// "anonymous"bind 返回的函数, name 属性值会加上 bound 前缀。
function foo() {};
foo.bind({}).name
// "bound foo"
(function(){}).bind({}).name
// "bound "5、允许使用“箭头”( => )定义函数。
箭头函数有几个使用注意点。
(1)函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
(3)不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。6、尾调用优化
ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
上面代码中,如果函数 g 不是尾调用,函数 f 就需要保存内部变量 m 和 n 的值、 g 的调用位置等信息。但由于调用 g 之后,函数 f 就结束了,所以执行到最后一步,完全可以删除 f(x) 的调用帧,只保留 g(3) 的调用帧。
7、尾递归优化
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5)
// 120
// 上面代码是一个阶乘函数,计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n) 。
// 如果改写成尾递归,只保留一个调用记录,复杂度 O(1) 。
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1)
// 120
(四)数组的扩展
1、扩展运算符(spread)是三个点( … )。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
任何定义了遍历器(Iterator)接口的对象(参阅 Iterator 一章),都可以用扩展运算符转为真正的数组。2、 Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
3、 Array.of 方法用于将一组值,转换为数组。
4、数组实例的 copyWithin 方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
Array.prototype.copyWithin(target, start = 0, end = this.length)
// target(必需):从该位置开始替换数据。如果为负值,表示倒数。
// start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
// end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
// 这三个参数都应该是数值,如果不是,会自动转为数值。5、数组实例的 find、 findIndex方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为 true 的成员,然后返回该成员。如果没有符合条件的成员,则返回 undefined 。
[1, 4, -5, 10].find((n) => n < 0)
// -56、 fill 方法使用给定值,填充一个数组。
7、ES6 提供三个新的方法—— entries() , keys() 和 values() ——用于遍历数组。
8、 Array.prototype.includes 方法返回一个布尔值,表示某个数组是否包含给定的值,与 字符串的 includes 方法类似。
9、数组的成员有时还是数组, Array.prototype.flat(number) 用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。number: 表示要“拉平”number层的嵌套数组
flatMap() 方法对原数组的每个成员执行一个函数(相当于执行 Array.prototype.map() ),然后对返回值组成的数组执行 flat() 方法。该方法返回一个新数组,不改变原数组。// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
// 注意
// 将数组的空位,转为 undefined
Array.from(['a',,'b'])
// [ "a", undefined, "b" ]
[...['a',,'b']]
// [ "a", undefined, "b" ]
[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
new Array(3).fill('a') // ["a","a","a"]
let arr = [, ,];
for (let i of arr) {
console.log(1);
}
// 1
// 1(五)对象的扩展
1、ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
const baz = {
foo,
method() {
return "Hello!";
}
};
baz // {foo: "bar",method:function method(){...}}2、可枚举性与遍历:
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。es5的方法: Object.getOwnPropertyDescriptor 方法可以获取该属性的描述对象。let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }描述对象的 enumerable 属性,称为“可枚举性”,如果该属性为 false ,就表示某些操作会忽略当前属性。
目前,有四个操作会忽略 enumerable 为 false 的属性(不遍历)。for…in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
Object.keys(obj)
Object.keys 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames 返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols 返回一个数组,包含对象自身的所有 Symbol 属性的键名。
Reflect.ownKeys(obj)
Reflect.ownKeys 返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2', '10', 'b', 'a', Symbol()]3、 this 关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字 super ,指向当前对象的原型对象。
5、函数的 name 属性,返回函数名。对象方法也是函数,因此也有 name 属性。
如果对象的方法使用了取值函数( getter )和存值函数( setter ),则 name 属性不是在该方法上面,而是该方法的属性的描述对象的 get 和 set 属性上面,返回值是方法名前加上 get 和 set 。const person = {
get foo() {},
set foo(x) {},
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
obj.foo.name
// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
// 有两种特殊情况:
// bind方法创造的函数,name属性返回bound加上原函数的名字;
// Function构造函数创造的函数,name属性返回anonymous
(new Function()).name // "anonymous"
var doSomething = function() {
// ...
};
doSomething.bind().name // "bound doSomething"
// 如果对象的方法是一个 Symbol 值,那么name属性返回的是这个 Symbol 值的描述。
const key1 = Symbol('description');
const key2 = Symbol();
let obj = {
[key1]() {},
[key2]() {},
};
obj[key1].name // "[description]"
obj[key2].name // ""对象的新增方法
1、 Object.is 。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
不同之处只有两个:一是 +0 不等于 -0 ,二是 NaN 等于自身。+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true2、 Object.assign 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
3、ES5 的 Object.getOwnPropertyDescriptor() 方法会返回某个对象属性的描述对象(descriptor)。ES2017 引入了 Object.getOwnPropertyDescriptors() 方法,返回指定对象所有自身属性(非继承属性)的描述对象。
4、 Object.setPrototypeOf 方法的作用与 proto 相同,用来设置一个对象的 prototype 对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法(接收两个参数)
如果第一个参数不是对象,会自动转为对象( undefined 和 null 无法转为对象会报错)。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。Object.setPrototypeOf(1, {}) === 1 // true
Object.setPrototypeOf('foo', {}) === 'foo' // true
Object.setPrototypeOf(true, {}) === true // trueObject.getPrototypeOf(obj);与 Object.setPrototypeOf 方法配套,用于读取一个对象的原型对象。如果参数不是对象,会被自动转为对象。如果参数是 undefined 或 null ,它们无法转为对象,所以会报错。
5、ES5 引入了 Object.keys 方法,返回一个数组、ES2017 引入了跟 Object.keys 配套的 Object.values 和 Object.entries ,作为遍历一个对象的补充手段,供 for…of 循环使用。
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"] 属性名为数值的属性(同上文属性的遍历规则),是按照数值大小,从小到大遍历的,因此返回的顺序是 b、c、aObject.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)
所有可遍历(enumerable)属性的键值对数组。如果原对象的属性名是一个 Symbol 值,该属性会被忽略。const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]6、 Object.fromEntries() 方法是 Object.entries() 的逆操作,用于将一个键值对数组转为对象。
拓展:
ES5 中 Object.create
Object.create() 方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
语法:
Object.create(proto, [propertiesObject])
proto
新创建对象的原型对象。propertiesObject
可选。如果没有指定为 undefined ,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应[Object.defineProperties()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties的第二个参数。
ES5 中 Object.defineProperties()
语法:
Object.defineProperties(obj, props)
- obj
- 在其上定义或修改属性的对象。
- props
- 要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符和访问器描述符(更多详情,请参阅Object.defineProperty())。描述符具有以下键:
- configurable
- 对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。
默认为 false - enumerable
- true 当且仅当在枚举相应对象上的属性时该属性显现。
默认为 false
- value
- 与属性关联的值。可以是任何有效的JavaScript值(数字,对象,函数等)。
默认为 undefined . - writable
- true 当且仅当与该属性相关联的值可以用assignment operator改变时。
默认为 false
var obj = {}; |