一、簡介
ES6 -> ECMA 標準,又叫 ES2015。ES6 -> 2015年6月 ES6.0;
每年6月份,發布一個版本
發布時間 | 版本 | 別名 |
---|---|---|
2016年6月 | ES6.1 | ES7、ES2016 |
2017年6月 | ES6.2(async await) | ES8、ES2017 |
- babel-loader 解析 ES6。
- 所有 ES6 內容見:官方資料
- chrome, 對新的語法支持,速度挺猛,一般在新語法發布的下一個版本中就會支持。
- ES6環境:
- webpack3.x --> babel-loader;
- Traceur。
二、 let 和 const
-
關于定義(聲明)變量:
- 之前:var a=12;
- 現在:let a=12。
-
之前作用域:
- 全局;
- 函數作用域。
-
現在作用域:
- 塊級作用域。
-
塊級作用域:
- ES5只有全局作用域和函數作用域,沒有塊級作用域。
- 問題一:內層變量可能會覆蓋外層變量;
- 問題二:用來計數的循環變量泄露為全局變量。
- ES5只有全局作用域和函數作用域,沒有塊級作用域。
1.let
- let:用來
聲明變量
。它的用法類似于var,但是所聲明的變量,只在let命令所在的代碼塊內有效; -
不存在變量提升
,所以變量一定要先聲明后使用; -
暫時性死區
(TDZ,temporal dead zone):ES6明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉的作用域,凡是在聲明之前就使用這些變量,就會報錯,并且不受外部的影響(即和外部有同樣變量名的變量沒有關系);- typeof不再安全,如果在聲明之前調用typeof,會報錯referenceError;而如果一個變量根本沒有被聲明,使用typeof反而不會報錯。
- 不允許重復聲明:在同一作用域內,不允許重復聲明同一個變量,即使使用var聲明也不可以;for循環中,for 判斷條件中的是父級作用域,循環體里面的是子作用域。
function func(arg){
let arg; //報錯
}
function func2(arg){
{
let arg: //不報錯
}
}
var arr = [];
for (var i=0;i<3;i++){
var fun = function () {
console.log(i);
};
arr.push(fun);
}
arr[1](); //3
var arr = [];
for (let i=0;i<3;i++){
var fun = function () {
console.log(i);
};
arr.push(fun);
}
arr[1](); //1
2.const
- 聲明一個只讀的常量,一旦聲明,常量的值就不可以更改;
- 所以在聲明變量的時候,就必須立即初始化,不得留著以后賦值;
- const作用域和let一樣,只在聲明所在的塊級作用域內有效;
- 存在暫時性死區,只能在聲明的位置后面使用;
- 不可重復聲明;
- 對于復合類型的變量,變量名不指向數據,而是指向數據所在的地址。const命令只是保證變量名指向的地址不變,并不保證該地址的數據不變,所有將一個對象聲明為常量時必須非常小心。如果想讓一個對象凍結,可以使用Object.freeze()方法:
Object.freeze(對象)
- 立即執行函數: IIFE
(function(){
//TODO
})()
- 建議:
- 以后 就用 let 不要在使用var
- 不讓后期修改的變量使用 const,如:
const http = require('http');
三、解構賦值:
- 非常有用,特別在做數據交互 ajax;
-
let [a,b,c] =[12,5,6];
; - 注意: 左右兩邊,結構格式要保持一致。
- 數組的解構賦值和位置有關;而對象的解構賦值和位置沒有關系,而是取決于它的變量名和屬性名對應關系。
//解構json:
let json = {
name:'YJW',
age:18,
job:'coding'
};
let {name,age,job} = json; //其中 {} 中的名字要和 JSON 中的 key 必須對應,否則會找不到,結果為 undefined
console.log (name,age,job); //YJW 18 coding
let {name:n,age:g, job:a} = json;
let json = {
name:'YJW',
age:18,
job:'coding'
};
let {name:n,age:a, job:j} = json; //給變量起別名,此時只能用別名,不能再使用 name、age、job,只能用別名
console.log (n,a,j); //YJW 18 coding
- 解構時候可以給默認值:
let [e,f,g] = [12,23];
console.log(e,f,g); //12 23 undefined
let [e,f,g=34] = [12,23];
console.log(e,f,g); //12 23 34
null 和 undefined 的區別:
let [e,f,g=34] = [12,23,undefined];
console.log(e,f,g); //12 23 34
let [e,f,g=34] = [12,23,null];
console.log(e,f,g); //12 23 null
//說明如果值為 null 時,默認值不能生效
交換兩個數的位置:
let h = 12;
let i = 5;
[h,i] = [i,h];
console.log(h,i); //5 12
- 用小括號
()
的情況:
let j;
({j} = {j:111}); //此處的 {j} 限定了作用域,如果不加小括號會報錯
console.log(j);
四、字符串模板:
- 字符串模板語法:兩個反單引號
``
- 優點: 可以隨意換行
- 使用變量:
${變量名字}
let name ='Strive';
let age = 18;
let str = `這個人叫${name}, 年齡是 ${age}歲`;
- 練習:新聞列表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>string</title>
</head>
<body>
<ul id="news"></ul>
<script>
let newsArr = [
{title:"2018博鰲亞洲論壇年會",read:12},
{title:"中朝啟動志愿軍烈士陵園修繕工程 ",read:33},
{title:"捍衛國家利益,我們有底氣!",read:44},
{title:"中國是亞洲經濟增長的重要后盾",read:55},
{title:"美國的任性行為破壞國際貿易秩序 損人不利己",read:66}
];
window.onload = function () {
//var newUl = document.getElementById("news");
var newUl = document.querySelector("#news");
for(var i=0; i<newsArr.length; i++){
var li = document.createElement("li");
li.innerHTML = `新聞標題:${newsArr[i].title},
閱讀人數:${newsArr[i].read}`;
newUl.appendChild(li);
}
};
</script>
</body>
</html>
ES2016 新增的內容
- 字符串查找:
- str.indexOf(要找的東西):返回索引(位置) ,沒找到返回-1。
- str.includes(要找的東西):返回值 true/false。
- 判斷瀏覽器的包含信息:includes
navigator.userAgent.includes("Chrome");
- 字符串是否以誰開頭:
-
str.startsWith(檢測東西);
;
-
- 字符串是否以誰結尾:
-
str.endsWith(檢測東西);
;例如檢測文件后綴名.png
等。
-
- 重復字符串:
-
str.repeat(次數);
;
-
"yjw".repeat(3); //yjwyjwyjw
- 字符串填充:
- str.padStart(整個字符串長度, 填充東西):往前填充;
- str.padEnd(整個字符串長度, 填充東西):往后填充;
- 如果設定的
整個字符串長度
小于原來字符串長度,則不進行填充,得到的還是原字符串。
let str = "aaa";
let padStr = "bbb";
console.log(str.padStart(str.length+padStr.length,padStr)); //bbbaaa
console.log("321".padStart(6,'a')); //"aaa321"
console.log('321'.padStart(6,"abcdefg")); //"abc321"
console.log("321".padStart(2,"aaaaaaa")); //"321"
五、函數變化:
1. 函數默認參數
- 之前:
function show(a,b) {
a = a || "Wel ";
console.log(a + b);
}
show("Welcome ","YJW"); //Welcome YJW
show("Welcome ",""); //Welcome
show("","YJW"); //Wel YJW
- 現在:
function show({x=0,y=0}={}){
console.log(x,y);
}
show();
函數參數默認已經定義了,函數的參數作用范圍在函數體內,不能再使用let,const聲明
function show(a=18){
let a = 101; //錯誤
console.log(a);
}
show()
2. rest運算符(擴展運算符):...
- 展開數組:
var arr = [1,2,3,4,5];
console.log(...arr); //1 2 3 4 5
- 合并為一個數組:
...
function arrSort(...a) {
console.log(a.sort()); //[1, 2, 3, 8, 9]
}
arrSort(2,1,3,9,8);
- 剩余參數:作為參數必須放到最后,如
show(a,b,...c);
。
3. 箭頭函數:=>
- 箭頭函數之前:
function show1() {
return 1;
}
console.log(show1()); //1
- 箭頭函數
let show2 = ()=>1;
console.log(show2()); //1
- 格式:
(參數) => return東西
(參數) =>{
語句
return
}
- 注意:
- this 問題:this 指定義函數所在的對象,不在是運行時所在的對象;
- 箭頭函數里面沒有arguments,用 ‘...arg’
- 箭頭函數不能當構造函數。
function Person() {
this.name = "yjw";
}
let pers = new Person();
console.log(pers.name);
let Person2 = ()=>{
this.name = "yjw";
};
let person = new Person2();
console.log(person.name); //報錯 Person2 is not a constructor
六、數組
1. ES5里面新增一些東西
循環:
-
之前:
- for:
for(let i=0; i<arr.length; i++){}
- while
- for:
arr.forEach(回調函數):// 代替普通for
var arr = ["apple","banana","pear"];
arr.forEach(function (value,index) {
console.log(value,index);
});
結果:
apple 0
banana 1
pear 2
其實它可以接受兩個參數,
arr.forEach/map/...(callback,this指向的值);
。
- arr.map():// 非常有用,做數據交互 "映射"
- 正常情況下,需要配合 return,返回是一個新的數組;
- 若是沒有 return,相當于 forEach
- 注意:平時只要用map,一定是要有return
- 練習:重新整理數據結構:
[{title:'aaa'}] -> [{t:'aaaa'}]
let newsArr = [
{title:"2018博鰲亞洲論壇年會",read:12},
{title:"中朝啟動志愿軍烈士陵園修繕工程 ",read:33},
{title:"捍衛國家利益,我們有底氣!",read:44},
{title:"中國是亞洲經濟增長的重要后盾",read:55},
{title:"美國的任性行為破壞國際貿易秩序 損人不利己",read:66}
];
let newArr = newsArr.map(function (value,index) {
let json = {};
json.t = `hei${value.title}`;
json.r = value.read+100;
return json;
});
console.log(newArr);
結果:
[{t: "hei2018博鰲亞洲論壇年會", r: 112},
{t: "hei中朝啟動志愿軍烈士陵園修繕工程 ", r: 133},
{t: "hei捍衛國家利益,我們有底氣!", r: 144},
{t: "hei中國是亞洲經濟增長的重要后盾", r: 155},
{t: "hei美國的任性行為破壞國際貿易秩序 損人不利己", r: 166}]
- arr.filter():過濾,過濾一些不合格“元素”,如果回調函數返回 true,數組中的這條數據就會留下來。
let newsArr = [
{title:"2018博鰲亞洲論壇年會",read:12,top:true},
{title:"中朝啟動志愿軍烈士陵園修繕工程 ",read:33,top:true},
{title:"捍衛國家利益,我們有底氣!",read:44,top:false},
{title:"中國是亞洲經濟增長的重要后盾",read:55,top:true},
{title:"美國的任性行為破壞國際貿易秩序 損人不利己",read:66,top:false}
];
let newArr = newsArr.filter(function (value,index) {
return value.top;
});
console.log(newArr);
結果:
[{title: "2018博鰲亞洲論壇年會", read: 12, top: true},
{title: "中朝啟動志愿軍烈士陵園修繕工程 ", read: 33, top: true},
{title: "中國是亞洲經濟增長的重要后盾", read: 55, top: true}]
- arr.some():類似查找, 查找數組里面某一個元素是否符合條件,如果符合就返回true。
let newsArr = [
{title:"2018博鰲亞洲論壇年會",read:12,top:true},
{title:"中朝啟動志愿軍烈士陵園修繕工程 ",read:33,top:true},
{title:"捍衛國家利益,我們有底氣!",read:44,top:false},
{title:"中國是亞洲經濟增長的重要后盾",read:55,top:true},
{title:"美國的任性行為破壞國際貿易秩序 損人不利己",read:66,top:false}
];
let newArr = newsArr.some(function (value,index) {
return value.top;
});
console.log(newArr);
結果:true。
- arr.every():數組里面所有的元素都符合條件,才返回 true,否則返回 false。
let newsArr = [
{title:"2018博鰲亞洲論壇年會",read:12,top:true},
{title:"中朝啟動志愿軍烈士陵園修繕工程 ",read:33,top:true},
{title:"捍衛國家利益,我們有底氣!",read:44,top:false},
{title:"中國是亞洲經濟增長的重要后盾",read:55,top:true},
{title:"美國的任性行為破壞國際貿易秩序 損人不利己",read:66,top:false}
];
let newArr = newsArr.every(function (value,index) {
return value.top;
});
console.log(newArr);
結果:false。
- 以上所有函數都可以接收兩個參數:
arr.forEach/map...(循環回調函數, this指向誰);
。
- arr.reduce()://從左往右
- 使用:求數組的和、階乘、乘方等
let arrNum = [2,3,4,5];
let result = arrNum.reduce(function (accumulator, cur, curIndex, arr) {
//accumulator 為上一次 return 的值,第一次循環時返回的為數值中第一個值
//cur 為當前數組的值
//curIndex 為當前的索引
//arr 為調用這個方法的數組
console.log("pre: "+accumulator);
console.log("cur: "+cur);
console.log("val: "+curIndex);
console.log("index:"+arr);
return (accumulator+cur)
});
console.log(result);
pre: 2
cur: 3
val: 1
index:2,3,4,5
pre: 5
cur: 4
val: 2
index:2,3,4,5
pre: 9
cur: 5
val: 3
index:2,3,4,5
14
- arr.reduceRight(): //從右往左
let arrNum = [1,3,5,7];
let result = arrNum.reduceRight(function (accumulator, cur, curIndex, arr) {
//accumulator 為上一次 return 的值,第一次循環時返回的為數值中最后一個值
//cur 為當前數組的值
//curIndex 為當前的索引
//arr 為調用這個方法的數組
console.log("pre: "+accumulator);
console.log("cur: "+cur);
console.log("val: "+curIndex);
console.log("arr: "+arr);
return (accumulator+cur)
});
console.log(result);
pre: 7
cur: 5
val: 2
arr: 1,3,5,7
pre: 12
cur: 3
val: 1
arr: 1,3,5,7
pre: 15
cur: 1
val: 0
arr: 1,3,5,7
16
- ES2017新增一個運算符:冪(**)
- Math.pow(2,3) = 2 ** 3
2. ES6:
-
for....of....
:- arr.keys():數組下標;
- arr.entries():數組中的每一項(包含下標和值);
let arrNum = ["apple","banana","pear"];
for (let value of arrNum){
console.log(value);
}
//apple
//banana
//pear
let arrNum = ["apple","banana","pear"];
for (let key of arrNum.keys()){
console.log(key);
}
//0
//1
//2
let arrNum = ["apple","banana","pear"];
for (let entry of arrNum.entries()){
console.log(entry);
}
//[0, "apple"]
//[1, "banana"]
//[2, "pear"]
let arrNum = ["apple","banana","pear"];
for (let [key,val] of arrNum.entries()){
console.log(key,val);
}
//0 "apple"
//1 "banana"
//2 "pear"
- 擴展運算符:
...
let arr =[1,2,3];
let arr2 = [...arr];
let arr3 = Array.from(arr);
//arr2 和 arr3 結果一樣。
Array.from:
作用: 把類數組(一組元素、arguments...) 對象`轉成數組`
暫時發現:具備 length這個東西,就靠譜。比如 JSON 沒有 length,但是在 JSON 中添加 `length:2` 就可以解決問題。
- Array.of():把一組值,轉成數組
let arr = Array.of("aaa","bbb","ccc");
console.log(arr); //["aaa", "bbb", "ccc"]
- arr.find(): 查找,找出第一個符合條件的數組成員,如果沒有找到,返回undefined
let arr = [12,120,13,101];
let num = arr.find(function (val,index) {
return val>100;
});
console.log(num); //120
- arr.findIndex():找的是位置, 沒找到返回-1
let arr = [12,120,13,101];
let num = arr.findIndex(function (val,index) {
return val>100;
});
console.log(num); //1
- arr.fill():填充
- 用法:
arr.fill(填充的東西, 開始位置, 結束位置);
。
- 用法:
let arr = new Array(5);
arr.fill("aa",1,3);
console.log(arr); //[empty × 1, "aa", "aa", empty × 2]
- 在ES2016里面新增:
- arr.indexOf();
- arr.includes();
- str.includes();
let str = "abcdefg";
console.log(str.includes("cd")); //true
let arr = ["a","b","c","d"];
console.log(arr.indexOf("c")); //2
console.log(arr.includes("c")); //true
七、對象:
- 對象簡潔語法(相當有用):
//之前用法
let a = 1;
let b = 2;
let json ={
a:a,
b:b,
showA:function(){
return this.a;
}
showB:function(){
return this.b;
}
}
//現在用法
let json ={
a,
b,
showA(){ //個人建議: 一定注意,不要用箭頭函數
},
showB(){
}
}
new Vuex.Store({
state,
mutation,
types,
actions
});
new Vue({
router,
App,
vuex
});
- Object.is():用來比較兩個值是否相等
- 語法:
Object.is('a','a');
- 語法:
console.log(NaN == NaN); //false
console.log(Number.isNaN(NaN)); //true
console.log(Object.is(NaN,NaN)); //true
console.log(+0 == -0); //true
console.log(Object.is(+0,-0)); //false
console.log(Object.is("aaa","aaa")); //true
- Object.assign():用來合并對象、復制對象
- 語法:
let 新的對象 = Object.assign(目標對象, source1, srouce2....);
- 語法:
let a = {a:1};
let b = {b:2,a:2}; // 有重復變量時,后面的會覆蓋前面的
let c = {c:3};
let json = Object.assign({},a,b,c);
console.log(json); // {a: 2, b: 2, c: 3}
- 使用:
function ajax(options){ // options 為用戶傳的參數
let defaults={
type:'get',
header:
data:{}
....
};
let json = Object.assign({}, defaults, options);
.....
}
let arr = ["a","b","c"];
let newArr = Object.assign([],arr);
newArr.push("dd");
console.log(arr); //["a", "b", "c"]
console.log(newArr); //["a", "b", "c", "dd"]
- 用途:
- 復制一個對象;
- 合并參數。
ES2017引入:
- Object.keys(obj);
- Object.entries(obj);
- Object.values(obj);
let json = {
a:111,
b:222,
c:333
};
console.log(Object.keys(json)); // ["a", "b", "c"]
console.log(Object.values(json)); // [111, 222, 333]
console.log(Object.entries(json)); // [["a", 111],["b", 222],["c", 333]]
let {keys, values, entries} = Object;
for (let key of keys(obj){
....
}
- 擴展運算符:
...
,計劃在ES2018引入
let json = {
a:111,
b:222,
c:333,
d:444
};
let {a,b,...c} = json;
console.log(a,b,c); //111 222 {c: 333, d: 444}
let json = {
a:111,
b:222,
c:333,
d:444
};
let newJson = {...json};
delete newJson.a;
console.log(newJson); //{b: 222, c: 333, d: 444}
console.log(json); //{a: 111, b: 222, c: 333, d: 444}
八、Promise
- 作用: 解決異步回調問題
- 傳統方式,大部分用回調函數,事件:
ajax(url,{ //獲取token
ajax(url,()=>{ //獲取用戶信息
ajax(url, ()=>{
//獲取用戶相關新聞
})
})
})
- Promise 基本語法:
let promise = new Promise(function(resolve, reject){
//resolve, 成功調用
//reject 失敗調用
});
promise.then(res=>{
//成功時候執行這里
....
}, err=>{
//失敗時候執行這里
....
});
promise.catch(err=>{
//失敗時候會執行這里
....
})
let a = 1;
let promise = new Promise(function (resolve, reject) {
if (a == 10){
resolve("成功啦。。。");
}else {
reject("失敗了。。。");
}
});
promise.then(res=>{
console.log(res);
},err=>{
console.log(err);
});
promise.catch(err=>{
console.log(err);
});
// 失敗了。。。
// 失敗了。。。
// 如果 let = 10;會打印 “成功啦。。。”
- 因為
promise.then
中失敗的回調方法和promise.catch
中失敗的回調方法一樣,此處只需調用一個即可:
new Promise().then(res=>{
....
}).catch(err=>{
....
})
let a = 10;
let promise = new Promise(function (resolve, reject) {
if (a == 10){
resolve("成功啦。。。");
}else {
reject("失敗了。。。");
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
});
// 成功啦。。。
- Promise.resolve('aa'):將現有的東西,轉成一個promise對象, resolve 狀態,成功狀態。等價于:
new Promise(resolve =>{
resolve('aaa')
});
- Promise.reject('aaa'):將現有的東西,轉成一個promise 對象,reject 狀態,失敗狀態。等價于:
new Promise((resolve, reject) =>{
reject('aaa')
});
let p1 = Promise.resolve("succ--哈哈哈");
let p2 = Promise.reject("fail--嘿嘿嘿");
p1.then(res=>{
console.log(res); // succ--哈哈哈
});
p2.then(res=>{
console.log(res);
},err=>{
console.log(err); // fail--嘿嘿嘿
});
- 批量處理函數:Promise.all([p1, p2, p3]):把 promise 打包,扔到一個數組里面,打包完還是一個promise對象。
let p1 = Promise.resolve("aaa");
let p2 = Promise.resolve("bbb");
let p3 = Promise.resolve("ccc");
Promise.all([p1,p2,p3]).then(res=>{
console.log(res);
}).catch(err => {
console.log(err);
})
// ["aaa", "bbb", "ccc"]
必須確保,所有的promise對象,都是resolve狀態,都是成功狀態,否則只會返回失敗的那個信息
let p1 = Promise.resolve("aaa");
let p2 = Promise.resolve("bbb");
let p3 = Promise.reject("ccc");
Promise.all([p1,p2,p3]).then(res=>{
console.log(res);
}).catch(err => {
console.log(err);
});
// ccc
- Promise.race([p1, p2, p3]):只會返回第一個
let p1 = Promise.reject("aaa");
let p2 = Promise.resolve("bbb");
let p3 = Promise.resolve("ccc");
Promise.race([p1,p2,p3]).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
});
//aaa
- 執行順序比較:
new Promise(function (resolve, reject) {
console.log("1111");
resolve("22222");
new Promise(function (resolve, reject) {
resolve("333333")
}).then(function (res) {
console.log(res);
});
setTimeout(function () {
console.log("44444");
},0);
console.log("66666");
}).then(res => {
console.log(res)
});
console.log("55555");
結果:
1111
66666
55555
333333
22222
44444
// 發現定時器是最后執行的
- 使用實例:用戶登錄 -> 用戶信息。
九、模塊化
- js 不支持模塊化;
- 其它語言中:
- ruby --> require
- python --> import
- 在ES6之前,社區制定一套模塊規范:
- Commonjs:主要服務端 nodeJs,如:require('http');
- AMD:requireJs, curlJs
- CMD:seaJs
- ES6出來,統一服務端和客戶端模塊規范:
import {xx} ddd
模塊化:
- 注意: 需要放到服務器環境
- 如何定義模塊?
① export 東西
② export const a =12;
③ export{
a as aaa, // 以后導入的時候只能導入 aaa :import {aaa} from "./a.js";
b as banana // 以后導入的時候只能導入 banana
}
④ export default aaa; // 導入的方式不需要 {}:import aaa from "./a.js";
- 如何使用?
<script type="module">
① import
② import './modules/1.js';
③ import {aaa as a, banana as b, cup as c} from './modules/2.js'; // 使用時候只能用 a、b、c
④ import * as modTwo from './modules/2.js';
</script>
import:特點
a. import 可以是相對路徑,也可以是絕對路徑:import “https://code.jquery.com/jquery-3.3.1.js”;
;
b. import 模塊實際上只會導入一次,無論你引入多少次;
c. import './modules/1.js'; 如果這么用,相當于引入文件,要的不是這個效果,而是:import {a} form './modules/1.js';
;
d. 有提升效果,import 會自動提升到頂部,首先執行;
e. 導出去模塊內容,如果里面有定時器更改,外面也會改動,不像 Common 規范緩存。默認 import 語法不能寫到 if 之類里面,即不能根據條件去有選擇性的導入某個文件。
-
import()
:類似 node 里面 require, 可以動態引入,返回值,是個 promise 對象,可以采用 promise 規范://這樣就可以根據條件加載了 function result(a){ switch(a){ case 1: return "./1.js"; break; case ... } } import(result(1)).then(res=>{ console.log(res.a+res.b); }); 優點: 1. 按需加載 2. 可以寫if中 3. 路徑也可以動態
Promise.all([import("./1.js"),import("./2.js")]).then(([mod1,mod2]) => {
console.log(mod1);
console.log(mod2);
});
- ES2017 加 async await,import 可以配合這兩個使用。
-
use strict
:以后默認就是嚴格模式。
十、類和繼承
- ES6 之前:函數模擬。
人: Person
屬性: name
展示名字: showName
Person.prototype.showName
function Person(name,age){
this.name='aaa';
this.age = age;
}
Person.prototype.showName=function(){
return `名字是:${this.name}`;
}
let p1 = new Person("yjw",18);
程序中類
- ES6
面向對象 ,類
屬性
方法
ES6中變形:
class Person{
constructor(name,age){ //構造方法(函數),調用 new 時,自動執行
this.name = name;
this.age = age
}
showName(){
return `名字是:${this.name}`;
}
}
let p = new Person("yjw",18);
- 其它定義格式:
const Person = class{}
。
let name = "yjw";
class Person{
[name](){
console.log("haha "+name);
}
}
let p = new Person();
p[name](); //haha yjw
// [] 中放變量名,這樣通過 [] 就可以變成一個屬性,屬性名可以是表達式
- 注意:
- ES6 里面 class 沒有提升功能,在 ES5,用函數模擬可以,默認函數提升;
- ES6 里面 this 比之前輕松多了。
-
矯正this:
- fn.call(this指向誰, args1, args2....) // 函數執行時才會綁定;
- fn.apply(this指向誰, [args1, args2....]) // 函數執行時才會綁定;
- fn.bind()。
class里面取值函數(getter), 存值函數(setter)
class Person{
set name(val){
console.log(`設置了 name 的值,值為:${val}`);
}
get name(){
return `獲得了 name 屬性的值`;
}
}
let p = new Person();
p.name = "yjw"; //設置了 name 的值,值為:yjw
console.log(p.name); //獲得了 name 屬性的值
- 靜態方法:就是類身上方法,在方法名前加 static 即可:
class Person{
showName(){
return "展示 name";
}
static showLog(){
return "展示 靜態方法";
}
}
let p = new Person();
console.log(p.showName()); //展示 name
console.log(Person.showLog()); //展示 靜態方法
繼承:
// 之前:
function Person(name) {
this.name = name;
}
Person.prototype.showName = function () {
return `名字是:${this.name}`;
};
function Student(name, skill) {
Person.call(this,name); // 繼承 name 屬性
this.skill = skill;
}
Student.prototype = new Person(); // 繼承方法
let p = new Person("yjw");
console.log(p.showName()); //名字是:yjw
let s = new Student("wang");
console.log(s.name); //wang
console.log(s.showName()); //名字是:wang
//現在: extends
class Person{
constructor(name){
this.name = name;
}
showName(){
return `名字是:${this.name}`;
}
}
class Student extends Person{
constructor(name,skill){
super(name);
this.skill = skill;
}
}
let s = new Student("yjw","study");
console.log(s.name); //yjw
console.log(s.showName()); //名字是:yjw
console.log(s.skill); //study
- 拖拽
十一、Symbol
- ES6 多一個數據類型 Symbol(首字母一定要大寫);
- 使用頻率不高,node 底層可能會用到;
- 定義:
let sym = Symbol("aaa");
console.log(sym); //Symbol(aaa)
console.log(typeof sym); //symbol,用 typeof 檢測出來數據類型:symbol
- 注意:
Symbol 不能 new;
Symbol() 返回一個唯一值:做一個 key,定義一些唯一或者私有一些東西;
symbol 是一個單獨數據類型,就叫 symbol,是一個基本類型。所有數據類型:number、string、boolean、symbol、undefined、Object、function。
如果 symbol 作為 key ,用 for in 循環,會出不來。
let sym = Symbol("aaa");
let json = {
a:"aaa",
b:"bbb",
[sym]:"symbol"
};
for (let key in json){
console.log(key);
}
//結果
a
b
十二、generator 函數
生成器;
解決異步深度嵌套的問題,但是現在多用 async 解決異步問題(后面會講);
語法:
// 方法一:
function * show(){
yield
}
//方法二
function* show(){
yield
}
//方法三
function *show(){
yield
}
//使用
function * gen() {
yield 111111;
yield (function () {return 2222;})();
return 33333;
}
let g = gen();
console.log(g.next()); //{value: 111111, done: false}
console.log(g.next()); //{value: 2222, done: false}
console.log(g.next()); //{value: 33333, done: true}
console.log(g.next()); //{value: undefined, done: true}
console.log(gen().next()); //{value: 111111, done: false}
console.log(gen().next()); //{value: 111111, done: false}
- 上述調用,手動調用,麻煩:可以配合
for .. of
自動遍歷generator
:
function * gen() {
yield 111111;
yield (function () {return 2222;})();
yield 333333;
return 444444;
yield 555555;
}
for (let val of gen()){
console.log(val);
}
111111
2222
333333
// return 的東西,不會被遍歷
//并且 return 后面的數據也不會被遍歷,yield 中的 return 不會被影響
- generator 不僅可以配合
for ... of ...
,還可以與其它配合使用。 - 解構賦值:
function * gen() {
yield 111111;
yield (function () {return 2222;})();
yield 333333;
return 444444;
yield 555555;
}
let [a,b,c,d] = gen();
console.log(a, b, c, d); //111111 2222 333333 undefined
- 擴展運算符:
...
function * gen() {
yield 111111;
yield (function () {return 2222;})();
yield 333333;
return 444444;
yield 555555;
}
let [a,...b] = gen();
console.log(a, b);
// 111111 [2222, 333333]
- Array.from():
function * gen() {
yield 111111;
yield (function () {return 2222;})();
yield 333333;
return 444444;
yield 555555;
}
let arr =Array.from(gen());
console.log(arr); //[111111, 2222, 333333]
- generator結合 axios數據請求:
十三、async
異步:不連續,上一個操作沒有執行完,下一個操作照樣開始;
同步:連續執行,上一個操作沒有執行完,下一個沒法開始。
關于異步,解決方案:
a). 回調函數
b). 事件監聽
c). 發布/訂閱 (emit/on)
d). Promise對象
自動執行的庫:co....等等ES2017,規定 async。在函數名前面加 async,在函數里面配合 await 使用,意在說明 await 后面的操作是耗時的,不能立刻返回結果。
async function fn(){ //表示異步,這個函數里面有異步任務
let result = await xxx //表示后面結果需要等待
}
nodeJs 中讀取文件 fs.readFile。
- 首先創建三個文件:aaa.txt(里面存有aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)、bbb.txt(里面存有bbbbbbbbbbbbb)、ccc.txt(里面存有cccccccccccc)
//1. promise
let fs = require("fs");
let read = function (fileName) {
return new Promise((resolve,reject) => {
fs.readFile(fileName,function (err,res) {
if (err) reject(err);
resolve(res)
});
});
};
read("./aaa.txt").then(res=>{
console.log(res.toString());
return read("./bbb.txt");
}).then(res=>{
console.log(res.toString());
return read("./ccc.txt");
}).then(res=>{
console.log(res.toString());
});
//aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
//bbbbbbbbbbbbb
//cccccccccccc
//2. genrator
let fs = require("fs");
let read = function (fileName) {
return new Promise((resolve,reject) => {
fs.readFile(fileName,function (err,res) {
if (err) reject(err);
resolve(res)
});
});
};
function * gen(){
yield read("./aaa.txt");
yield read("./bbb.txt");
yield read("./ccc.txt");
}
let g = gen();
g.next().value.then(res => {
console.log(res.toString());
return g.next().value;
}).then(res => {
console.log(res.toString());
return g.next().value;
}).then(res => {
console.log(res.toString());
});
//aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
//bbbbbbbbbbbbb
//cccccccccccc
//3. async
let fs = require("fs");
let read = function (fileName) {
return new Promise((resolve,reject) => {
fs.readFile(fileName,function (err,res) {
if (err) reject(err);
resolve(res)
});
});
};
async function fn() {
let f1 = await read("./aaa.txt");
console.log(f1.toString());
let f2 = await read("./bbb.txt");
console.log(f2.toString());
let f3 = await read("./ccc.txt");
console.log(f3.toString());
}
fn();
//aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
//bbbbbbbbbbbbb
//cccccccccccc
- async 特點:
- await 只能放到 async 函數中;
- 相比 genrator 語義化更強;
- await 后面可以是 promise 對象,也可以數字、字符串、布爾;
- async 函數返回是一個 promise 對象;
- 只要 await 語句后面 Promise 狀態變成 reject,那么整個 async 函數會中斷執行。
如何解決async函數中拋出錯誤,影響后續代碼:
a).
try{
}catch(e){
}
b). promise本身catch
個人建議大家:
try{
let f1 = await readFile('data/a.txt');
let f3 = await readFile('data/c.txt');
let f2 = await readFile('data/b.txt');
}catch(e){}
async await
數據結構
數組
json, 二叉樹....
set數據結構:
類似數組,但是里面不能有重復值
let arr = ['a','b','a'];
let arr = new Array();
set用法:
let setArr = new Set(['a','b']);
setArr.add('a'); 往setArr里面添加一項
setArr.delete('b'); 刪除一項
setArr.has('a') 判斷setArr里面有沒有此值
setArr.size 個數
setArr.clear(); 清空
for...of...
循環:
a). for(let item of setArr){ //默認是values()
console.log(item);
}
b). for(let item of setArr.keys()){console.log(item);}
c). for(let item of setArr.values()){}
d). for(let [k,v] of setArr.entries()){}
e). setArr.forEach((value,index) =>{
console.log(value, index);
});
let setArr = new Set().add('a').add('b').add('c');
數組去重:
let arr = [1,2,3,4,5,6,7,6,5,4,3,2,1,2,3,4,4];
let newArr = [...new Set(arr)];
console.log(newArr);
set數據結構變成數組:
[...set]
想讓set使用數組的,map循環和filter:
let arr = [{},{}];
new Set([]); 存儲數組, 這種寫法對
new WeakSet({}) 存儲json,這種寫法不靠譜
WeakSet沒有size,也沒有clear()
有, add(), has(), delete()
確認,初始往里面添加東西,是不行的。最好用add添加
總結: new Set()
let json ={
p1:1,
b:2
};
map:
類似 json, 但是json的鍵(key)只能是字符串
map的key可以是任意類型
使用:
let map = new Map();
map.set(key,value); 設置一個值
map.get(key) 獲取一個值
map.delete(key) 刪除一項
map.has(key) 判斷有沒有
map.clear() 清空
循環:
for(let [key,value] of map){}
for(let key of map.keys()){}
for(let value of map.values()){}
for(let [k,v] of map.entries()){}
map.forEach((value, key) =>{
console.log(value, key);
})
WeakMap(): key只能是對象
總結:
Set 里面是數組,不重復,沒有key,沒有get方法
Map 對json功能增強,key可以是任意類型值
十四、數字(數值)變化:
二進制和八進制表示法:
- 二進制: (Binary),使用 0b 或 0B 表示,0b010101;
- 八進制: (Octal),使用 0o 或 0O 表示,0o666;
- 將二進制或者八進制的數轉化為十進制的數:Nunber(0o777);
Number.isNaN(NaN) -> true
Number.isFinite(a) 判斷是不是數字 √
Number.isInteger(a) 判斷數字是不是整數 √
-------------------------------------------
Number.parseInt();
Number.parseFloat();
安全整數:
2**3
安全整數: -(2^53-1) 到 (2^53-1), 包含-(2^53-1) 和(2^53-1)
Number.isSafeInteger(a);
Number.MAX_SAFE_INTEGER 最大安全整數
Number.MIN_SAFE_INTEGER 最小安全整數
Math:
Math.abs()
Math.sqrt()
Math.sin()
Math.trunc() 截取,只保留整數部分
Math.trunc(4.5) -> 4
Math.trunc(4.9) -> 4
Math.sign(-5) 判斷一個數到底是正數、負數、0
Math.sign(-5) -> -1
Math.sign(5) -> 1
Math.sign(0) -> 0
Math.sign(-0) -> -0
其他值,返回 NaN
Math.cbrt() 計算一個數立方根
Math.cbrt(27) -> 3
.......
ES2018(ES9):
1. 命名捕獲
語法: (?<名字>)
let str = '2018-03-20';
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let {year, month ,day} = str.match(reg).groups;
console.log(year, month, day);
反向引用:
\1 \2 $1 $2
反向引用命名捕獲:
語法: \k<名字>
let reg = /^(?<Strive>welcome)-\k<Strive>$/;
匹配: ‘welcome-welcome’
-------------------------------------------------
let reg = /^(?<Strive>welcome)-\k<Strive>-\1$/;
匹配: 'welcome-welcome-welcome'
替換:
$<名字>
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
str = str.replace(reg,'$<day>/$<month>/$<year>');
console.log(str);
----------------------------------------
str = str.replace(reg, (...args)=>{
//console.log(args)
let {year, month, day} = args[args.length-1];
return `${day}/${month}/${year}`;
});
console.log(str);
2. dotAll 模式 s
之前 '.' 在正則里表示匹配任意東西, 但是不包括 \n
let reg = /\w+/gims;
3. 標簽函數
function fn(){
}
fn() //這樣調用就是普通函數
fn`aaa` //標簽函數使用
-----------------------------------
function fn(args){
return args[0].toUpperCase();
}
console.log(fn`welcome`);
ES2018(ES9)
proxy: 代理
擴展(增強)對象、方法(函數)一些功能
比如:
Vue
Vue.config.keyCodes.enter=65
Proxy作用: 比如vue中攔截
預警、上報、擴展功能、統計、增強對象等等
proxy是設計模式一種, 代理模式
let obj ={
name:'Strive'
};
//您訪問了name
obj.name // Strive
語法:
new Proxy(target, handler);
let obj = new Proxy(被代理的對象,對代理的對象做什么操作)
handler:
{
set(){}, //設置的時候干的事情
get(){}, //獲取干的事情
deleteProperty(){}, //刪除
has(){} //問你有沒有這個東西 ‘xxx’ in obj
apply() //調用函數處理
.....
}
實現一個,訪問一個對象身上屬性,默認不存在的時候給了undefined,希望如果不存在錯誤(警告)信息:
DOM.div()
DOM.a();
DOM.ul()
set(), 設置,攔截:
設置一個年齡,保證是整數,且范圍不能超過200
deleteProperty(): 刪除,攔截:
has(): 檢測有沒有
apply() :攔截方法
Reflect.apply(調用的函數,this指向,參數數組);
fn.call()
fn.apply() 類似
Reflect: 反射
Object.xxx 語言內部方法
Object.defineProperty
放到Reflect對象身上
通過Reflect對象身上直接拿到語言內部東西
'assign' in Object -> Reflect.has(Object, 'assign')
delete json.a -> Reflect.deleteProperty(json, 'a');