1.变量声明
1.let命令在块级作用域里面起作用,没有变量提升
2.const命令声明常量,不能改变
2.字符串扩展
1.模板字符串
2.字符串查找
includes():返回布尔值,表示是否找到了参数字符串。支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';
s.includes('Hello', 6) // false复制代码
3.数值扩展
1.Number.isFinite()
用来检查一个数值是否为有限的(finite),即不是Infinity
2.
Number.isNaN()
用来检查一个值是否为NaN;
3.
Number.isInteger()
用来判断一个数值是否为整数;
4.
Math.sign
方法用来判断一个数到底是正数、负数、还是零;
4.函数扩展
1.箭头函数
(1)函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new
命令,否则会抛出一个错误。
(3)不可以使用arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代 替。
(4)不可以使用yield
命令,因此箭头函数不能用作 Generator 函数。
( 5 ) 尾调用(Tail Call)是函数式编程的一个重要概念,是指某个函数的最后一步是调用另一个函数,释放外层函数的调用栈,内存和变量,避免闭包的缺点,重点返回的函数不能使用外层函数的变量,必须只返回函数
function f(x){
return g(x);
}
// 情况一
function f(x){
let y = g(x);
return y;
}
// 情况二
function f(x){
return g(x) + 1;
}
// 情况三
function f(x){
g(x);
}
//情况1,2,3都不属于尾调用
复制代码
( 6 ) 尾调用和递归,以及函数默认值的应用实例
function factorial(n, total = 1) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5) // 120复制代码
5.数组扩展
(1)复制数组
前言: 数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。
ES5 复制数组方法(深拷贝)。
const a1 = [1, 2];
const a2 = a1.concat();
a2[0] = 2;
a1 // [1, 2]复制代码
ES6 扩展运算符复制数组的方法
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;复制代码
ES6 扩展运算符合并数组的方法
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
//********不过,这两种方法都是浅拷贝,使用的时候需要注意。
复制代码
( 2 ) 数组查找
数组实例的find
方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true
的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined
。
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10复制代码
数组实例的findIndex
方法的用法与find
方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2复制代码
*******另外,这两个方法都可以发现NaN
,弥补了数组的indexOf
方法的不足。
[NaN].indexOf(NaN)
// -1
[NaN].findIndex(y => Object.is(NaN, y))
// 0复制代码
Array.prototype.includes
方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes
方法类似。ES2016 引入了该方法。
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) //复制代码
6.对象的扩展
1.属性的简便表示方法
( 1 )属性值得简写
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};复制代码
( 2 )函数方法的简写
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};复制代码
2.对象属性合并
Object.assign
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}复制代码
Object.assign
拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false
)。
Object.assign
方法实行的是浅拷贝,而不是深拷贝
7.Symbol新增的数据类型
特点
独一无二的,可以保证不会与其他属性名产生冲突,是一种类似于字符串的数据类型.
Symbol
函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
let s = Symbol();
typeof s
// "symbol"
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
复制代码
8.新的数据结构Set和Map
1.Set
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成 Set 数据结构。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
//通过add方法添加不重复的元素复制代码
利用Set数组去重
// 去除数组的重复成员
[...new Set(array)]复制代码
Set实例的方法
add(value)
:添加某个值,返回 Set 结构本身。delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。has(value)
:返回一个布尔值,表示该值是否为Set
的成员。clear()
:清除所有成员,没有返回值。
Array.from
方法可以将 Set 结构转为数组。所以另一种数组去重的方法
function dedupe(array) {
return Array.from(new Set(array));
}
dedupe([1, 1, 2, 3]) // [1, 2, 3]复制代码
Set实例遍历的方法
keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每个成员
2.Map
Map数据结构类似于Javascript的对象,但是传统对象只能拿字符串做为对象的键,所以有很大的局限性,Map很好的解决了这个问题,它的键可以是任何值
const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false复制代码
作为构造函数,Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组,
下面代码在新建 Map 实例时,就指定了两个键name
和title
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"复制代码
需要注意的是,只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。
const map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined复制代码
上面代码的set
和get
方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此get
方法无法读取该键,返回undefined
。
由上可知,Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
实例的属性和操作方法
size
属性返回 Map 结构的成员总数。set
方法设置键名key
对应的键值为value
,然后返回整个 Map 结构。如果key
已经有值,则键值会被更新,否则就新生成该键。get
方法读取key
对应的键值,如果找不到key
,返回undefined
。has
方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。delete
方法删除某个键,返回true
。如果删除失败,返回false
。clear
方法清除所有成员,没有返回值
实例的遍历方法
keys()
:返回键名的遍历器。values()
:返回键值的遍历器。entries()
:返回所有成员的遍历器。forEach()
:遍历 Map 的所有成员。