2017.11.12
数值的扩展
二进制和八进制表示法,分别使用0b和0o表示
Number.isFinite()和Number.isNaN()
与传统的isFinite和isNaN方法的区别在于,传统方法先调用Number()将非数值的值转换为数值,再进行判断,而这个新的方法只对数值有效,非数值一律返回false
Number,isInteger()
用来判断一个值是否为整数。但是需要注意的是,在JavaScript中,整数和浮点数都同样是同样的存储方法,所以3和3.0都被视为同一个值
数组的扩展
Array.from()
用于将两类对象转换为真正的数组
一类是类数组对象(array-like-object)和可遍历的(iterable)的对象,其中包括ES6新增的Set和Map结构。
Array.from的一个应用是将字符串转换为数组,然后返回字符串的长度
Array.of()方法
将用于一组值,转换为数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3).length // 1
这样做的目的在于弥补构造函数Array()的不足。因为参数的个数的不同,会导致Array行为差异
Array() // []
Array(3) // [undefined, undefined, undefined]
Array(3,11,8) // [3, 11, 8]
数组实例的find()方法
用于找出第一个符合条件的数组元素,它的参数是一个回调函数,回调函数的参数——当前值,当前位置和原数组
findIndex()和find方法类似
fill()
使用给定值,填充一个数组
还可以接受第二个和第三个参数
用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
数组实例的entries(),keys(),values()
它们都返回一个遍历器,可以使用for ... of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
数组推导
数组推导可以代替map方法和filter方法
需要注意的是数组推导的方括号构成了一个单独的作用域,在这个方括号中声明的变量类似于let语句声明的变量
还有一个注意点就是,新数组会立即在内存中生效,这时。如果原数组是一个很大的数组的话,将会非常的耗费内存
Array.observe()和Array.unobserve()
这两个方法用于监听(取消监听)数组的变化,指定回调函数
属于ES7中的内容
对象的扩展
ES6中允许字面量定义对象时候,用表达式作为对象的属性名,即把表达式放到方括号内
Object.is()
用来判断两个值是否严格相等。它与严格相等符(===)的行为基本一致,不同之处在于:-0不等于+0,NaN等于自身
Object.assign()
用来将源对象(Sourse)的所有可枚举属性,复制到目标对象。它至少需要两个对象作为参数,第一个是目标对象,后面都是源对象
assign()用法很多
为对象添加属性
为对象添加方法
克隆对象
为属性指定默认值
proto属性
用来读取或设置当前对象的prototype对象
Object.setPrototypeOf()
用来设置一个对象的prototype对象
Object.getPrototypeOf()
用于读取一个对象的prototype对象
函数的扩展
ES6允许为函数设置默认值,即直接写在参数定义的后面
需要注意的一点是,参数默认值所处的作用域是函数作用域,而不是全局作用域
reset参数(...变量名)
用来获取函数的多余参数,这样就不用使用arguments对象了。reset参数搭配的变量是一个数组,该变量将多余的参数放进一个数组中
扩展运算符(spread)
是三个点(...),它好比reset参数的逆运算,将一个数组用逗号分隔的参数序列。该运算符主要用于函数调用
扩展运算符内部调用的是数据结构的iterator接口,因此只要具有iterator接口的对象,都可以使用扩展运算符,比如map结构
箭头函数
如果箭头函数中不需要参数或者需要多个参数,就使用一个圆括号代表参数部分
如果代码部分多于一条代码,就要使用大括号将它们括起来,并且使用return语句返回
另外由于大括号被解析成代码块,所以如果箭头函数返回一个对象的话,必须在对象外面加上括号
var getTempItem = id => ({ id: id, name: "Temp" });
箭头函数的作用
简化回调函数
需要注意点
1.函数体内的this对象,绑定的是定义时候的所在的对象,而不是使用时候所在的对象
2.不可以当做构造函数
3.不可以使用arguments对象,该对象在函数体内不存在
this的指向是可变的,但在箭头函数中,它是固定的。
set和map数据结构
Set
set方法提供了一种数组去重的方式
function dedupe(array){
return Array.from(new Set(array));
}
类似于数组,但是成员是唯一的,没有重复的值
遍历操作
set结构有一个values方法,返回一个遍历器
set结构的默认遍历器就是它的values方法,也就是说,可以忽略values方法,直接使用for ... of循环遍历set
set结构的forEach方法
也有keys和entries方法,这个时候每个值的键名就是键值
由于扩展运算符(...)内部使用for...of循环,所以也可以用于set结构
let set = new Set(['red', 'green', 'blue']);
let arr = [...set];
// ['red', 'green', 'blue']
提供了一种便捷的数组去重的方式
let arr = [3, 5, 2, 2, 5, 5];
let unique = [...new Set(arr)];
// [3, 5, 2]
map
基本用法
提出原因:因为JavaScript对象,本质上是键值对的集合,但是只能用字符串当做键。(这里所受的限制就很大了)
作为构造函数
Map可以接受一个数组作为参数,该数组的成员是一个表示键值对的数组
map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
map结构转化为数组结构,比较快速的方法是使用扩展运算符(...)
map还有一个forEach方法,与数组的forEach方法类似,也可以实现遍历
还可以接受第二个参数,用来绑定this
WeakMap只接受对象作为键名(null除外),不接受原始数据的值作为键名,而且键名所指向的对象,不计入垃圾回收机制
iterator
遍历器是一种接口规格,任何对象只要部署这个接口,就可以完成遍历操作
作用:
1.为各种数据结构,提供一个统一的、 简便的接口
2、使得对象中的各个属性能够按着某种次序排列
遍历器提供了一个指针,指向当前对象的某个属性,使用next方法,就可以将指针移动到下一个属性。next方法返回一个包含value和done两个属性的对象。其中value属性是当前遍历位置的值,done属性是一个布尔值,表示遍历是否结束
在Es6中,有三类数据结构原生具备Iterator接口:数组、类数组对象、Set和map结构
ES6中,一个对象只要部署了@@iterator方法,就被视为具有iterator接口,就可以使用for...of循环遍历它的值。也就是说,for....of循环内部调用是原对象的symbol.iterator方法
JavaScript原有的for...in循环,只能获取对象的键名,不能直接获取键值。ES6提供的for...of循环,允许遍历获取键值
var arr = ["a", "b", "c", "d"];
for (a in arr) {
console.log(a); // 0 1 2 3
}
for (a of arr) {
console.log(a); // a b c d
}
总结一下,for...of循环可以使用的范围包括数组、类似数组的对象(比如arguments对象、DOM NodeList对象)、Set和Map结构、后文的Generator对象,以及字符串。
Generator
可以把它理解成一个函数内部状态的遍历器,每调用一次,函数内部的状态发生一次改变(可以理解成发生某些事件)。为了可以完全控制函数内部的状态的改变,依次遍历这些状态
两个特征
1、function命令和函数名之前有一个*号
2、函数内部使用yield语句
当调用Generator函数的时候,该函数并不执行,而是返回一个遍历器(可以理解为暂停执行)
使用next方法遍历yield语句定义的内部状态
总结一下,Generator函数使用iterator接口,每次调用next方法的返回值,就是一个标准的iterator返回值:有着value和done两个属性的对象。其中,value是yield语句后面那个表达式的值,done是一个布尔值,表示是否遍历结束。
return和yield语句的区别
区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能
Generator函数可以不用yield语句,这时候就变成了一个单纯的暂缓执行函数
next()方法的参数
next方法可以带一个参数,该参数就会被当做上一个yield语句的返回值
for....of循环可以遍历Generator函数,而且此时不再需要调用next方法
yield*语句
如果yield命令后面跟的是一个遍历器,需要在yield命令后面加上星号,表明它返回的是一个遍历器
yield*命令可以很方便地取出嵌套数组中所有的成员
作为对象属性的Generator函数
let obj = {
\* myGeneratorMethod() {
···
}
};
还可以写成:
let obj = {
myGeneratorMethod: function* () {
···
}
};
这两者是等价的
应用:
Generator可以暂停函数的执行,返回任意表达式的值
1、异步操作的同步化表达
2、控制流管理
注意,yield语句是同步运行,而不是异步运行
3、部署iterator接口
4、作为数据结构
Class和Module
Class
ES5通过构造函数,定义并生成新的对象。
function Point(x,y){
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '('+this.x+', '+this.y+')';
}
ES6引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '('+this.x+', '+this.y+')';
}
}
var point = new Point(2,3);
point.toString() // (2, 3)
注意:里面有一个constructor函数,这就是构造函数,而this关键字则代表实例对象。定义方法的时候,不需要加上function这个保留字,直接把函数定义放进去就可以了
Class之间可以通过extends关键字实现继承
class ColorPoint extends Point {}
super关键字,它指向父类的同名方法。
注意:类和模块的内部,默认就是严格模式,所以不需要使用use strict指定的运行模式
Module的基本模块
ES6模块的设计思想,是尽量的静态化,使得编译时候就能够确定模块的依赖关系,以及输入和输出的变量
模块功能主要由两个命令构成:export和import
export命令用于用户自定义的模块,规定对外接口;import命令用于输入其他模块提供的功能,同时创建命名空间(namescape),防止函数名冲突
ES6允许将独立的JS文件作为模块,也就是说,允许一个JavaScript脚本文件调用另一个脚本文件
如果想为输入的变量重新取一个名字,import语句中使用as关键字,将输入的的变量重命名
module命令可以取代import语句,达到整体输入模块的作用
module circle from 'circle'
export default
如果需要输出匿名函数,可以使用export default命令
import进来的时候,可以为该匿名函数指定任意名称
模块的继承
promise对象
所谓的promise对象,就是代表了未来某个将要发生的事件(通常是一个异步操作)。
用处:有了promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
ES6中的promise对象是一个构造函数,用来生成Promise实例,下面是promise对象的基本用法
var promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value) {
// success
}, function(value) {
// failure
});
promise实例生成后,可以使用then方法分别指定resolve方法和reject方法的回调函数
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
timeout(100).then(() => {
console.log('done');
});
上面代码的timeout方法返回一个Promise实例对象,表示一段时间以后改变自身状态,从而触发then方法绑定的回调函数。
resolve和reject方法调用的时候,都有参数。它们的参数会被传递给回调函数。reject方法的参数通常是Error对象的实例,而resolve方法的参数除了正常的值以外,还可能是另一个Promise实例
Promise.prototype.then:链式操作
Promise.prototype.then
返回的是一个新的promise对象
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// proceed
});
第一个回调函数完成之后,会将返回结果作为参数,传入第二个回调函数
如果前一个回调函数返回的是promise对象,这时后一个回调函数就会等待该promise对象有了运算结果,才进行下一步的调用
这种设计使得嵌套的异步操作,可以被很容易的改写,从回调函数的“横向发展”变成“向下发展”
promise.prototype.catch
方法:捕捉错误
该方法是Promise.prototype.then(null,rejection)
的别名,用于指定发生错误时候的回调函数
Promise.all方法 Promise.race方法
这两个方法用于将多个promise实例,包装成一个新的Promise实例
Promise.resolve方法 Promise.reject方法
有时候需要将现有的对象转化为Promise对象
如果Promise.resolve方法的参数,不是具有then方法的对象(又称thenable对象),则返回一个新的promise对象,而且它的状态为fullfilled
var p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
Promise.resolve方法的参数就是回调函数的参数
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
var p = Promise.reject('出错了');
p.then(null, function (s){
console.log(s)
});
// 出错了
async函数
async函数是用来取代回调函数的另一种方法
只要函数名前面加上async关键字,就表明该函数内部有异步操作。该异步操作应该返回一个Promise对象,前面用await关键字注明。当函数执行的时候,遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句
async function getStockPrice(symbol, currency) {
let price = await getStockPrice(symbol);
return convert(price, currency);
}
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncValue(value) {
await timeout(50);
return value;
}