ECMAScript 学习小结
ECMAScript和JavaScript的关系是什么?
前者是后者的规格,后者是前者的一种实现。日常场合,两者是可以互换不做分别的。
ECMAScript 6 即是ECMAScript的第 6 个版本。
let和const命令
let和const命令:
let用来声明变量,用法类似于var,但是也有很大的差别。
const用来声明常量,常量是必须声明后立即赋值的,不可以后续赋值也不可以后续更改值,
否则会报错。const的其他特点和let基本一致。
let的变量声明和赋值是同步进行,是不会提前声明的,不挂载到window上的,
在let声明执行之前也是不可以对let声明的变量进行任何操作的。
console.log(b); //2 console.log(a); //报错,提示a不存在 let a = 1; var b = 2;
let、const声明的变量名不可以重复声明。
let a = 1; var a = 2; //直接报错 let a = 1; function a(){ var a = 2; } //直接报错
let、const声明只在let命令所在的代码块内有效。
{ let a = 10; var b = 1; } console.log(b); //1 console.log(a); //报错
for循环中循环表达式很适合用let命令。也进一步证明let命令只在代码块中有效。
for(var i=0;i<10;i++){} console.log(i) //10 for(let j=0;j<10;j++){} console.log(j) //报错
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); //10
以上代码因为var为全局变量赋值,在全局范围内有效且只有一个i,每一次循环i的值都会发生改变,最终累加到10停止循环。
而for循环内部的console.log( i ),这里的i值在函数内找不到就只能去父级寻找,最终找到已经累加到10的i,进行输出,所以输出为10。
那么怎样才能使其输出对应下标里的i值呢?
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); //6
以上代码使用了let来声明变量i,所以i只在块级作用域内有效,而且是本轮循环内有效,所以每次循环的i值都为在一个块级作用域内一个独立的变量。
而每次循环i能记住上一个i的值,是因为JavaScript内部进行的操作,引擎内部会记住上一轮循环的值,在上一轮循环的基础上进行计算。
除了上一种方法,还有一种采用闭包的方法。
var arr = []; for (var i = 0; i < 10; i++) { (function(i){ arr[i] = function(){ console.log(i) } }(i)) } arr[8](); //8
let和const的临时死区
只要块级作用域内存在let和const命令,它所声明的变量就绑定这个区域,不再受外部的影响。
ES7中的...运算符
多用于调用函数和对象:
function abc(a,b,c){
console.log(a+b+c);
}
var arr = [3,4,5];
abc(...arr)
该运算符将一个数组变为参数序列。运算符也可以和正常的函数参数结合使用。
function abc(a,b,c,d){ console.log(a+b+c+d); } var arr = [3,4,5]; abc(2,...arr);
可以通过该运算符来达到克隆的效果。
浅克隆:
let a = { num : 1 } let b = { num : 2 } let c = { ...a, ...b }
深克隆
let a = { num : 1 } let b = { num : 2 } let c = { num : { ...a, ...b } }
解构赋值
解构一个数组
let arr = [1,2,3]; let x,y,z; [x,y,z] = arr; //x = 1;y = 2;z = 3;
解构一个对象
let obj = { name : "Tom", age : 18, sex : "0" } let name,age,sex; ({name,age,sex} = obj ) //name = "Tom";age = 18;sex = "0";
箭头函数
ES6 允许使用“箭头”(`=>`)定义函数。可以非常简洁的写函数。
var sum = function(a,b){ return a+b; } //等同于 let sum = (a,b) =>{ return a+b; }
var fun = function(a,b){ return { a:a,b:b } } //等同于 let fun = (a,b) => { return { a : a, b : b } }
function fun(x){ return function(y){ return function(z){ return x+y+z; } } } //等同于 let fun = x => y => z => x+y+z;
Map 结构
Map数据结构类似于对象,就是用来存储内容的。
首先来用Map方法来创建一个集合。
var map = new Map(); map.a = 1; map.b = 2; map.c = 3; map.set("0","html"); map.set("1","css"); map.set("2","JavaScript");
map.get("0");//"html"
map.get("0");//true
这个map数据集合可以使用set方法为其中添加一个键值,也可以用get方法获取到这个值。也可以使用delete方法来删除选择的键值。
作为构造函数,Map也可以接受一个数组作为参数。
var map = new Map([['name','张三'],['age','20']]); //等同于set('name','张三');
实例的属性和操作方法
size属性
size属性返回Map结构的成员总数
let map = new Map(); map.set("name","Tom"); map.set("age","20"); map.size //2
Map.set(key,value)
set方法设置属性名key对应的属性值为value,然后返回整个Map结构。如果key已经有值,则属性值会被更新,否则就新生成该属性。
let map = new Map(); map.set("key",10); //属性名是字符串,值为数字 map.set(110,"120"); //属性名是数字,值为字符串 map.set(undefined,"haha") //属性名为undefined,值为字符串
//可以使用链式写法
map.set(1,"a")
.set(2,"b")
.set(3,"c");
Map.get(key)
get方法读取key对应的属性值,如果找不到key,则返回undefined
function fun(){console.log("Hello world!!!");} let map = new Map() .set(fun,"Hello"); map.get(fun); //会调用到该函数,输出"Hello world !!!"
map.get(haha); //undefined
Map.delete(key)
delete方法删除某个属性,返回true。如果删除失败,则返回false
function fun(){console.log("Hello world !!!");} let map = new Map().set(fun,"Hello world") map.delete(fun); //true map.delete(fun); //false
Map.clear()
clear方法清除所有成员,没有返回值。
let map = new Map(); map.set(1,1); map.set(2,2); map.clear();
Map的循环遍历
for of
var map = new Map([['name','张三'],['age','20']]); //等同于set('name','张三'); for(var i in map){ console.log(i) } //输出map对象下标名 for(var index of map){ console.log(index); } //输出添加进去的键值对的数组 for(var name of map.entries()){ console.log(name) } //输出对应的键值对 for (var [key,value] of map.entries()){ console.log(key,value) } //输出对应键值对 for (var val of map.values()){ console.log(val) } //输出键值对的值
class
ES 6 的类完全可以看做构造函数的另一种写法。其数据类型就是函数。
class Hyh{} typeof Hyh; //"function"
使用的时候也是直接对lei使用new命令,和构造函数的用法完全一致。
class ID{ constructor(name,age){ this.name = name; this.age = age; } logFun(){ console.log("name:"+this.name+"\n"+"age:"+this.age); } } var Tom = new ID("Tom",21); Tom.name //"Tom" Tom.age //21 Tom.logFun(); //name:Tom //age:21
Tom是ID的实例,Tom的constructor方法就是ID类原型的constructor方法,可以在类的prototype上添加类的新方法。可以通过Object.assign方法一次向类添加多个方法。
Object.assign(ID.prototype,{
toName(){},
toAge(){}
})
class的继承
class可以通过extends关键字实现继承
class Code extends ID{}
继承后可以调用继承来的方法和属性
var Jack = new Code("Jack","20"); Jack.name; //"Jack" Jack.logFun(); //name:Jack //age:20
也可以继承父类函数后再在自身添加新的属性和参数,通过super方法接收父类构造的参数信息
class ID{ constructor(name,age){ this.name = name; this.age = age; } logFun(){ console.log("name:"+this.name+"\n"+"age:"+this.age); } } class Code extends ID{ constructor(name,age,color){ super(name,age); //用来继承父类参数接收 this.color=color } } var color = new Code("Jack","20","black")
Promise对象 承诺
它是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。主要用来做异步的消息处理的。
它就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
Promise对象的两个特点:
1、对象的状态不受外界的影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、funlfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为funlfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就成为resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果,这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
基本用法
Promise对象是一个构造函数,用来生成Promise实例。
let promise = new Promise(function(resolve,reiect){ if("如果异步操作成功"){ resolve(value); //执行resolve成功函数 }else{ reject(error); //执行reject失败函数 } })
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve失败函数和reject成功函数。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从pending变为resolved),再异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从pending变为rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
then()方法
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的毁掉函数。
promise.then(function(value){ console.log("成功了!"+value); },function(error){ console.log("失败了!"+error); })
then调用以后又返回一个Promise对象。这时可以链式写法在新的Promise上写then方法,这个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。
promise.then(function(data){ return data + 10; },function(){ }).then(function(data){ console.log(data); },function(err){ console.log(err); })
利用Promise写一个ajax
var btn = document.getElementById("btn"); var box = document.getElementById("box"); btn.onclick = function(){ var promise = new Promise(function(resolve,reject){ ajax('./16.txt',function(data){ resolve(data) },function(err){ reject(err) }) }) promise.then(function(data){ box.innerHTML = data; },function(err){ box.innerHTML = err; }) } function ajax(url,fnSucc,fnErr){ var xhr = new XMLHttpRequest(); xhr.open('GET',url,true); xhr.send(); xhr.onload = function(){ if(xhr.readyState == 4 && xhr.status == 200){ fnSucc(xhr.responseText); }else{ fnErr(xhr.status); } } }