一、介绍
1.历史
ECMAScript和JavaScript
- ECMAScrip是标准,JavaScript是实现
- 类似于HTML5是标准,IE10、Chrome、FF都是实现
- 换句话说,将来也能有其他XXXScript来实现ECMA
- ECMAScript简称ECMA或ES
- 目前版本
- 低级浏览器主要支持ES 3.1
- 高级浏览器正在从ES 5过渡到ES 6
- ECMAScrip是标准,JavaScript是实现
历史版本
时间 | ECMA | JS | 解释 |
---|---|---|---|
1996.11 | ES 1.0 | JS稳定 | Netscape将JS提交给ECMA组织,ES正式出现 |
1998.06 | ES 2.0 | ES2正式发布 | |
1999.12 | ES 3.0 | ES3被广泛支持 | |
2007.10 | ES 4.0 | ES4过于激进,被废了 | |
2008.07 | ES 3.1 | 4.0退化为严重缩水版的3.1 因为吵得太厉害,所以ES 3.1代号为Harmony(和谐) | |
2009.12 | ES 5.0 | ES 5.0正式发布 同时公布了JavaScript.next也就是后来的ES 6.0 | |
2011.06 | ES 5.1 | ES 5.1成为了ISO国际标准 | |
2013.03 | ES 6.0 | ES 6.0草案定稿 | |
2013.12 | ES 6.0 | ES 6.0草案发布 | |
2015.06 | ES 6.0 | ES 6.0预计发布正式版 JavaScript.next开始指向ES 7.0 |
2.兼容性
1.兼容性
- ES5浏览器兼容性一览表: ES5浏览器支持情况
- ES6浏览器情况。包括:IE10+、Chrome、Firefox、移动端、NodeJS,具体情况为: ES6浏览器支持情况
2.编译与转换,将ES6编译转换成低版本浏览器支持的JS代码
- 在线编译,使用语法解析转换工具将ES6语法解析转换为大部分浏览器识别的ES5语法,通用的转换方案有babel,traceur,jsx,typescript,es6-shim,其中,Bable是比较常用的,参见Bable,可以引入browser.js使浏览器支持Babel;
- 提前编译
2.ES6特性
1.变量
1.var的缺陷
- 可以重复声明,var a =5; var b = 7; var a = 12;
- 无法限制修改,对于某些常量,如PI等可以任意修改;
- 没有块级作用域,var作用于函数,而不是作用于块语句;
2.新的关键字
- let: 不能重复声明,变量可以修改,块级作用域
- const: 不能重复声明,变量不可以修改,块级作用域
var aBtn = document.getElementByTagName('button');
(function(i){
for(var i = 0; i < aBtn.length; i++){
aBtn.i.onclock = function(){
alert(i);
}
})(i)
}
用let不用闭包来解决以上问题:
var aBtn = document.getElementByTagName('button');
for(var let = 0; i < aBtn.length; i++){
aBtn.i.onclock = function(){
alert(i);
}
}
2.函数
1.箭头函数
省略条件
- 如果只有一个参数,()可以省略;
- 如果只有一个return语句,{}可以省略
let show = function(){
alert('13')
}
show();
let show = ()=>{
alert('13')
}
function add(a, b){
return a+b
}
add(5,12);
(a, b)=>a+b
2.函数参数
1.参数扩展/数组展开
- 参数扩展:…args,用来收集剩余参数,但必须是参数列的最后一个,例如:
function add(a, b, ...args){
return a+b;
};
add(1,2,3,4,4,6);//函数中的3,4,4,6会传给...args;
- 数组展开。
let arr = [1,2,3] ...arr//1,2,3
let arr1 = [2,3], arr2 = [e,3];
let arr3=[...arr1, ...arr2]; arr3//2, 3, e, 3
2.默认参数, 参数默认值 function(a, b=2){};
3.解构赋值,直接对多个变量同时赋值,解构赋值条件如下:
- 左右两边结构一样
- 右边必须符合语法
- 声明和赋值不能分开
使用场景
解构赋值在很多时候可以大大简化代码。例如,交换两个变量x和y的值,可以这么写,不再需要临时变量:
var x=1, y=2;
[x, y] = [y, x]
快速获取当前页面的域名和路径:
var {hostname:domain, pathname:path} = location;
如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个Date对象:
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
它的方便之处在于传入的对象只需要year、month和day这三个属性:
buildDate({ year: 2017, month: 1, day: 1 });
// Sun Jan 01 2017 00:00:00 GMT+0800 (CST)
也可以传入hour、minute和second属性:
buildDate({ year: 2017, month: 1, day: 1, hour: 20, minute: 15 });
// Sun Jan 01 2017 20:15:00 GMT+0800 (CST)
3.数组
新增加了四个函数,分别是:
- map 映射 返回长度和原数组相同的数组 arr.map(function(item, index, arr))
- reduce 汇总 arr.reduce(function(tmp, item, index)) tmp为计算得到的临时值
- filtr 过滤 arr.filter(function(item, index, arr))
- forEach 循环 arr.forEach(function(item, index){})
let arr1 = [12, 23, 15];
let result = arr1.map(item=>item);
alert(result);
let result2 = arr1.reduce((tmp, item, index) => {
if(index != arr1.length-1){
return tmp+item
} else {
return (tmp+item)/arr1.length
}
});
arr1.forEach((item, index) => {
console.log(index + ':' + item)
});
3.字符串
1.多了两个新方法,感觉像是根据正则表达式封装实现的
- startsWith(str) 判断字符是否以str开头;
- endsWith(str) 判断字符是否以str结尾;
2.字符串模板
- 字符串中可以识别变量 $(变量);
- 可以换行;
let firstname = 'bill';
let lastname = 'gates';
let name = `${firstname}, ${lastname}`;
4.面向对象
ES5中实现面向对象的继承需使用原型链,具体如下:
function Person(props){
this.name = props.name;
this.age = props.age;
}
Person.prototype.getName = function(){
return this.name;
}
function Student(props){
Person.call(this, props);
this.school = props.school;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
出现class, super, extends等面向对象关键字后,便可以使用类似JAVA的方式实现继承,但是实质上是对原型和原型继承的封装,class等关键字只是语法糖,还是要理解原型和原型链等。使用class等关键字如下:
class User{
constructor(name, pass){
this.name = name
this.pass = pass
}
showName(){
alert(this.name)
}
showPass(){
alert(this.pass)
}
}
class VipUser extends User{
constructor(name, pass, level){
super(name, pass)
this.level = level
}
showLevel(){
alert(this.level)
}
}
let vl = new VipUser('hotsuitor', '123456', 5)
v1.showName()
v1.showPass()
v1.showLevel()
4.JSON
JSON是JavaScript Object Notation的缩写,它是一种数据交换格式,由道格拉斯·克罗克福特(Douglas Crockford)设计,JSON实际上是JavaScript的一个子集。JSON还定死了字符集必须是UTF-8,表示多语言就没有问题了。为了统一解析,JSON的字符串规定必须用双引号”“,Object的键也必须用双引号”“。在JSON中,数据类型:
- number:和JavaScript的number完全一致;
- boolean:就是JavaScript的true或false;
- string:就是JavaScript的string;
- null:就是JavaScript的null;
- array:就是JavaScript的Array表示方式——[];
- object:就是JavaScript的{ … }表示方式。
1.JSON对象,两个方法:
- stringfiy() 序列化;
- parse() 反序列化;
var xm = {
name: '小明',
age: 14,
toJSON: function () {
return { // 只输出name和age,并且改变了key:
'Name': this.name,
'Age': this.age
};
}
};
JSON.stringify(xm);
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
2.JSON简写
- 名字和值一样
- 方法可以省略function关键字
let a=12,b=12;
let json={a,b,c:12} == {a:a,b:b,c:12}
let json = {
a:12,
show(){
alert(this.a);
}
}
5.Promise
1.什么是Promise
是JS异步编程的重要概念,异步抽象处理对象,是目前比较流行的JS异步编程解决方案之一
2.异步编程方案
异步编程方案有以下几种,具体后面会有文章来详细介绍:
- 回调函数
- 事件监听
- 发布/订阅模式
- Promise
- Generator
3.Promise
Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject。
promise相当于一个状态,有三种状态,并且promsie状态只能由 pending => fulfilled/rejected, 一旦修改就不能再变:
- pending promise对象的初始状态
- fulfilled 调用resolve(success) 会由pending => fulfilled
- rejected 调用resolve(error) 会由pending => rejected
4.Promise方法
- then方法注册 当resolve(成功)/reject(失败)的回调函数,异步执行;
- resolve(成功) onFulfilled会被调用;
- reject(失败) onRejected会被调用;
- Promise.resolve 返回一个fulfilled状态的promise对象;
- Promise.reject 返回一个rejected状态的promise对象;
- Promise.all 接收一个promise对象数组为参数,只有全部为resolve才会调用,通常会用来处理多个并行异步操作;
- Promise.race 接收一个promise对象数组为参数,Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
5.Promise原理
Promise像是一个状态机,分为初始状态、成功和失败状态。Promoise的构造函数接受一个函数fn作为参数,fn有两个参数函数:参数resolve和reject,因为Promise是一个状态机,需要声明一个属性记录其状态,同时,需要声明两个属性记录返回数据,then方法接受两个函数,分别用来处理返回的成功状态的promise对象和失败状态的对象,但then方法是异步执行的,因此,当运行到then方法时,可能fn还没有执行完毕,因此,需要在constructor中分别声明事件队列用来记录then方法中的两个函数,那么,相应的fn方法中resolve方法需要遍历执行成功事件队列,reject方法需要遍历执行失败事件队列。
class Promise2 {
constructor(fn) {
const _this = this;
_this.status = '';
_this._queue = [];
_this._succ_res = null;
_this._erro_res = null;
fn(function(...arg) {
_this._succ_res = arg;
_this.status = 'success';
_this._queue.forEach(function(json) {
json.fn1(...arg);
});
}, function(...arg) {
_this._erro_res = arg;
_this.status = 'error';
_this._queue.forEach(function(json) {
json.fn2(...arg);
});
});
}
then(fn1, fn2) {
if (this.status === 'success') {
fn1(this._succ_res);
} else if (this.status === 'error') {
fn2(this._erro_res);
} else {
this._queue.push({fn1, fn2});
}
}
}
Promise2.all = function(arr){
let res = [];
return new Promise2(function(resolve, reject){
let i = 0;
next();
function next() {
arr[i].then(function(result){
res.push(result);
i++;
if(i === arr.length){
resolve(res);
}else{
next();
}
},reject);
}
})
};
6.Promise应用
Promise适用于一次对很多数据情况。
let p1=new Promise(function (resolve, reject){
$.ajax({
url: 'data/arr.txt',
dataType: 'json',
success(arr){
resolve(arr);
},
error(err){
reject(err);
}
})
});
let p2=new Promise(function (resolve, reject){
$.ajax({
url: 'data/json.txt',
dataType: 'json',
success(arr){
resolve(arr);
},
error(err){
reject(err);
}
})
});
Promise.all([
p1, p2
]).then(function (arr){
let [res1, res2]=arr;
alert('全都成功了');
alert(res1);
alert(res2);
}, function (){
alert('至少有一个失败了');
});
6.Generator
1.基本概念
生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。普通函数是一路执行到底,Generator可以中间暂停。
语法如下:
function show(){
alert("a")
alert("b")
}
show(); //一次性执行完整个函数
function *show2(){
alert("a")
yield
alert("b")
}
let geneObj = show2();
show2().next() //alert a
show2().next() //alert b
可以理解为:Generator函数底层实现是把一个“大函数”生成多个yield分割的“小函数”。
2.yield
- 可以传参数
let geneObj = show2();
geneObj.next();//第一个参数无效,可以在show()函数中设置参数,show(12);
geneObj.next(12);
- 可以返回值
理解yield,可以通过下图来理解理解yield。
3.Generator使用
1.在NodeJS中:
npm install yield-runner-blue //安装blue封装的包
runner(function *(){
let data1 = $.ajax(url, dataType:'json')
let data2 = $.ajax(url, dataType:'json')
let data3 = $.ajax(url, dataType:'json')
console.log(data1, data2, data3)
})
2.异步操作
Generator generator 带逻辑的异步更方便,Promise适合一次读一堆,不适合带逻辑异步操作
- Promise
Promise.all([
$.ajax({url: xxx, dataType: 'json'})
$.ajax({url: xxx, dataType: 'json'})
$.ajax({url: xxx, dataType: 'json'})
]).then(result=>{
}, error=>{
})
- Generator
runner(function *(){
let data1 = yield $.ajax({url: xxx, dataType: 'json'})
let data2 = yield $.ajax({url: xxx, dataType: 'json'})
let data3 = yield $.ajax({url: xxx, dataType: 'json'})
});
//带逻辑的 generator
runner(function *(){
let userData = yield $.ajax(url: 'getUserType', dataType: 'json')
if (userData == 'VIP') {
let VipUser = yield $.ajax(url: 'getVipUsers', dataType: 'json')
} else {
let normalUser = yield $.ajax(url: 'getNormalUsers', dataType: 'json')
}
//其他逻辑
})