day12-ES6新增語(yǔ)法
- ECMAScript6在保證向下兼容的前提下诬滩,提供大量新特性 ,大多數(shù)只允許在嚴(yán)格模式下使用霹粥。
- ES6 版本的開(kāi)發(fā)版 => babel => ES5 的發(fā)布版;
1. 嚴(yán)格模式
- 嚴(yán)格模式通過(guò)拋出錯(cuò)誤來(lái)消除了一些原有靜默錯(cuò)誤。
- 嚴(yán)格模式修復(fù)了一些導(dǎo)致 JavaScript引擎難以執(zhí)行優(yōu)化的缺陷:有時(shí)候疼鸟,相同的代碼后控,嚴(yán)格模式可以比非嚴(yán)格模式下運(yùn)行得更快。
- 嚴(yán)格模式禁用了在ECMAScript的未來(lái)版本中可能會(huì)定義的一些語(yǔ)法空镜。
范圍:用字符串“use strict”聲明的script標(biāo)簽或函數(shù)內(nèi)浩淘;
注意:從use strict聲明以下才有效,上面的不會(huì)起作用吴攒。
-
變量的嚴(yán)格
在嚴(yán)格模式之中,變量未經(jīng)聲明不可以賦值;
a = 20; //在嚴(yán)格模式下张抄,報(bào)錯(cuò)
var a = 010; //所有的瀏覽器都支持這種以零(0)開(kāi)頭的八進(jìn)制語(yǔ)法 console.log(a) //輸出8 var a = 0o10; // ES6中只能以0o開(kāi)頭來(lái)表示八進(jìn)制 console.log(a);
"use strict"; var x; delete x; // !!! 語(yǔ)法錯(cuò)誤 eval("var y; delete y;"); // !!! 語(yǔ)法錯(cuò)誤
-
只讀屬性不能修改
"use strict"; var str = "abcde"; str.length = 10; //報(bào)錯(cuò) var obj = {}; Object.defineProperty(obj,"a",{ writable:false; value:10 }); obj.a = 20; //報(bào)錯(cuò)
-
參數(shù)的嚴(yán)格
1.不允許同名參數(shù)存在;
2.arguments 和形參彼此分離并不會(huì)互相影響;
(function(){ })() //匿名函數(shù)后面沒(méi)有加“;”洼怔,在嚴(yán)格模式下會(huì)報(bào)錯(cuò)署惯,多行連讀 (function(){ })()
(function(){ function foo(a,a,b){ console.log(a,b); } foo(1 , 2 , 3); //結(jié)果是:2 3 })() (function(){ "use strict" function foo(a,a,b){ console.log(a,b); } foo(1 , 2 , 3); //調(diào)用結(jié)果會(huì)報(bào)錯(cuò) })()
(function() { function foo(a, b) { a = 20; b = 30; console.log(a, b, "arguments", arguments[0], arguments[1]); } foo(1, 2) })(); (function() { "use strict" function foo(a, b) { a = 20; b = 30; console.log(a, b, "arguments", arguments[0], arguments[1]); } foo(1, 2) })() //變量和偽數(shù)組沖突 Uncaught TypeError: "use strict" is not a function
function fn(a,b,...arg){ console.log(a,b,arg); } fn(3,5,7,8,9,10); //3 5 (4) [7, 8, 9, 10]
-
指針的嚴(yán)格
如果你指向了window, 那么就把指針指向拋空;
"use strict"; var obj1 = {}; Object.defineProperty(obj1, "x", { value: 42, writable: false }); obj1.x = 9; //給不可寫屬性賦值, 拋出TypeError錯(cuò)誤 var obj2 = { get x() { return 17; } }; obj2.x = 5; // 給只讀屬性賦值, 拋出TypeError錯(cuò)誤 var fixed = {}; Object.preventExtensions(fixed); fixed.newProp = "ohai"; // 給不可擴(kuò)展對(duì)象的新屬性賦值, 拋出TypeError錯(cuò)誤 delete Object.prototype; // 拋出TypeError錯(cuò)誤
-
反射 字符串反射對(duì)象
反射機(jī)制指的是程序在運(yùn)行時(shí)能夠獲取自身的信息。例如一個(gè)對(duì)象能夠在運(yùn)行時(shí)知道自己有哪些方法和屬性镣隶。
var obj0 = {}; var obj1 = {}; var obj2 = {}; var obj3 = {}; for (var i = 0; i < 4; i++) { eval("obj" + i).a = i; }
-
JSON
JSON 規(guī)則 key值必須用雙引號(hào) !
" : 轉(zhuǎn)義字符
var json = '{"a" : "10"}' console.log(JSON.parse(json)); //{a: "10"} var obj = { a : 10} console.log(JSON.stringify(obj)) //{"a":10}
2.ES6新增屬性
-
let關(guān)鍵字
- let 語(yǔ)句聲明一個(gè)塊級(jí)作用域的本地變量 极谊。
- let命令不存在變量提升,所以在聲明前調(diào)用變量安岂,都會(huì)報(bào)錯(cuò)轻猖,這在語(yǔ)法上,稱為“暫時(shí)性死區(qū)”(temporal dead zone域那,簡(jiǎn)稱TDZ)咙边。
- 比較var: var 定義的變量是
window
的屬性,而let a不是window
的屬性琉雳,無(wú)法通過(guò)this.a
調(diào)用样眠。
for(var i = 0; i < 5; i ++){ setTimeout(function(){ alert(i); },1000); } //輸出5 5 5 5 5 for(let i = 0; i < 5; i ++){ setTimeout(function(){ alert(i); },1000); } //輸出0 1 2 3 4 //var i = 0,定義的不是局部變量翠肘,而是全局變量檐束,這里不會(huì)形成閉包。
- 使用未聲明的變量
var varTest; let letTest; console.log(varTest); //輸出undefined(注意要注釋掉下面一行才能運(yùn)行) console.log(letTest); //直接報(bào)錯(cuò):ReferenceError: letTest is not defined
- 重復(fù)聲明同一個(gè)變量
var varTest = 'test var OK.'; let letTest = 'test let OK.'; var varTest = 'varTest changed.'; let letTest = 'letTest changed.'; //直接報(bào)錯(cuò):SyntaxError: Identifier 'letTest' has already been declared console.log(varTest); //輸出varTest changed.(注意要注釋掉上面letTest變量的重復(fù)聲明才能運(yùn)行) console.log(letTest);
- 變量作用域
var varTest = 'test var OK.'; let letTest = 'test let OK.'; { var varTest = 'varTest changed.'; let letTest = 'letTest changed.'; } console.log(varTest); // 輸出"varTest changed." // 內(nèi)部"{}"中聲明的varTest變量覆蓋外部的letTest聲明 console.log(letTest); // 輸出"test let OK." // 內(nèi)部"{}"中聲明的letTest和外部的letTest不是同一個(gè)變量
- 塊級(jí)作用域
// eg : function m(){ console.log("111111111") } if( flag > 5) { function m(){ console.log("2222222222") } } m(); //在ES5中束倍,函數(shù)m會(huì)在第二次定義時(shí)被覆蓋被丧。 結(jié)果: 222222222222 //在ES6中,則會(huì)出現(xiàn) 111111111111的結(jié)果
-
const常量
常量創(chuàng)建的是一個(gè)只讀的引用绪妹,它的值不能通過(guò)重新賦值來(lái)改變甥桂,并且不能重新聲明。
const obj = {}; obj.a =10; //報(bào)錯(cuò) obj = {}; //一些既定的邮旷,不需要改變的數(shù)據(jù)都可以放在常量中
-
箭頭函數(shù)
這個(gè)我個(gè)人不推薦使用黄选,待會(huì)再說(shuō)原因,先講優(yōu)點(diǎn)!
- 先看區(qū)別吧办陷,原來(lái)的寫法
var test = function(x){ return x+2; }
- 使用箭頭函數(shù)
var test = x=>x+2; //看起很簡(jiǎn)單吧貌夕? 省略了function、return關(guān)鍵字和大括號(hào)民镜。 //使用方法跟以前一樣沒(méi)區(qū)別test(5); 結(jié)果: 7
- 還有好處就是啡专,自動(dòng)綁定this,或者說(shuō)this指向不發(fā)生改變
var obj = { left : 200, move : function(){ setTimeout(function(){ //this.left = 100; //以前這里不能寫this },1000); } }
- 使用了箭頭函數(shù)
var obj = { left : 200, move : function(){ setTimeout( ()=>{ this.left = 100; },1000); } }
- 當(dāng)然也有一些缺陷
箭頭函數(shù)是不能new的制圈,它的設(shè)計(jì)初衷就跟構(gòu)造函數(shù)不太一樣
-
箭頭函數(shù)如果要返回一個(gè)JSON對(duì)象们童,必須用小括號(hào)包起來(lái)
var test = ()=>({id:3, val=20})
箭頭函數(shù)現(xiàn)在非常流行,但我個(gè)人并不覺(jué)得它有那么美好鲸鹦。
主要是因?yàn)榛劭猓@樣的設(shè)計(jì)對(duì)代碼的可讀性傷害太大了
引用國(guó)際著名OO專家、敏捷開(kāi)發(fā)創(chuàng)始人 馬丁.福勒的一句名言:任何一個(gè)傻瓜都能寫出計(jì)算器可以理解的代碼亥鬓。惟有寫出人類容易理解的代碼完沪,才是優(yōu)秀的程序員。
我們讀代碼的時(shí)間和寫代碼的時(shí)間比率是10:1嵌戈。這意味著我們大部分時(shí)間都在閱讀老代碼覆积,以便于之后新代碼的編寫。因?yàn)樽x代碼占得比重太大了熟呛,因此我們希望在閱讀代碼的時(shí)候能夠更加輕松宽档,即便在編寫代碼的時(shí)候需要費(fèi)點(diǎn)勁。這一段好像也是他老人家說(shuō)的庵朝,我覺(jué)得很有道理吗冤。
省略掉一個(gè)function單詞,并不能給開(kāi)發(fā)效率提高多少九府,但犧牲的卻是最基本的代碼可讀性除了數(shù)學(xué)運(yùn)算椎瘟,我們幾乎從來(lái)不用符號(hào)表示一些復(fù)雜的含義。
甚至以前有人質(zhì)疑過(guò)JQ關(guān)于each方法的設(shè)計(jì)思想侄旬,認(rèn)為它屏蔽了程序最基本的邏輯肺蔚,那就是循環(huán)代碼的可讀性收到了嚴(yán)重傷害。不過(guò)我們仔細(xì)看看forEach儡羔、map宣羊、filter這些函數(shù),盡管它們屏蔽了for循環(huán)汰蜘,但分析這些單詞的含義:each 每個(gè)map 映射(一一對(duì)應(yīng))filter 過(guò)濾它們其實(shí)全部都隱含的表達(dá)了遍歷的意思仇冯。
回過(guò)頭來(lái)我們?cè)倏矗瑥膄unction到 =>族操,這東西連個(gè)象形符號(hào)都算不上這就是為什么數(shù)學(xué)有那么多的符號(hào)可以用來(lái)交流苛坚,但我們卻從不把它稱為語(yǔ)言。
- 吐槽歸吐槽,還是要學(xué)的
-
(參數(shù)1, 參數(shù)2, …, 參數(shù)N) => { 函數(shù)聲明 }
相當(dāng)于:(參數(shù)1, 參數(shù)2, …, 參數(shù)N) =>{ return 表達(dá)式; }
-
(參數(shù)1, 參數(shù)2, …, 參數(shù)N) => 表達(dá)式(單一)
當(dāng)只有一個(gè)參數(shù)時(shí)泼舱,圓括號(hào)是可選的:
(單一參數(shù)) => {函數(shù)聲明}
單一參數(shù) => {函數(shù)聲明} -
沒(méi)有參數(shù)的函數(shù)應(yīng)該寫成一對(duì)圓括號(hào)姐赡。
() => {函數(shù)聲明}
箭頭函數(shù)中不支持arguments,用剩余運(yùn)算符代替了柠掂。
箭頭函數(shù)的this一旦確定,不可改變
var add = (1, 2) => a + b; console.log(add(1, 2)); //3 var arr = [1,2,3,4,5]; var res = arr.map(item => item * 2); console.log(res); //[2,4,6,8,10] var res = arr.filter(item => item > 3); console.log(res); //[4,5] var arr = [1, 5, 2, 3, 8, 4, 5, 9, 0, 6]; arr.sort(function(a, b) { return a - b; }) arr.sort((a, b) => a - b);//[0, 1, 2, 3, 4, 5, 5, 6, 8, 9]
- 一點(diǎn)小缺陷
- 箭頭函數(shù)是不能new的依沮,它的設(shè)計(jì)初衷就跟構(gòu)造函數(shù)不太一樣
- 箭頭函數(shù)如果要返回一個(gè)JSON對(duì)象涯贞,必須用小括號(hào)包起來(lái)
var test = ()=>({id:3, val=20})
- 箭頭函數(shù)的指向,是看它的外圍this
var obj = { a: 1, init: function() { var div = document.createElement("div"); Object.assign(div.style, { width: '50px', height: "50px", backgroundColor: "red" }); document.body.appendChild(div); div.addEventListener("click", e => { // console.log(this);//因?yàn)橛屑^函數(shù),指向obj,不再指向div this.clickHandler(e); }); }, clickHandler: function(e) { // console.log(this);this指向obj this.a++; e.currentTarget.style.backgroundColor = "blue"; console.log(this); } } obj.init();
-
解構(gòu)賦值
解構(gòu)賦值主要分為對(duì)象的解構(gòu)和數(shù)組的解構(gòu) 细疚。
- 數(shù)組賦值(中括號(hào)賦值)
// 以前我們定義多個(gè)變量寇损,可以這樣寫: var x = 10, y = 20, z = 30; // 現(xiàn)在我們可以這樣寫: let [x, y, z] = [10, 20, 30]; let [x, y, z] = [10, 20]; //z為undefined //數(shù)組賦值允許嵌套: let [x, [a,b], y] = [10, [15,18], 20]; //這并不是在定義數(shù)組毁靶,而是通過(guò)等號(hào)兩邊的結(jié)構(gòu)匹配,進(jìn)行賦值皇拣。 //如果寫的不夠規(guī)范,瀏覽器并不會(huì)報(bào)錯(cuò),依然賦值成功 let [x,y] = [10,20,30]; //結(jié)果x=10,y=20 let [x,[a,b],y] = [10,[5],20]; //結(jié)果x=10,a=5,y=20,b=undefined
- 交換變量
var a = 3, b = 4; [a, b] = [b, a]; console.log(a, b);//4,3
- 對(duì)象賦值(大括號(hào)賦值)
// 聲明的變量和屬性是一致的時(shí)候可以直接內(nèi)容并賦值給聲明的變量 let obj = { hello : "hello world" } let { hello } = obj.hello; console.log(hello); //hello world // 將hello 更名為 hillo; let obj = { hello : "hello world" } let { hello : hillo } = obj; //取出hello的值薄嫡,并替換成hillo console.log(hillo); //hello world console.log(obj.hello); //hello world var obj={a : 1, b : 2, c : {a : 3, b : 4}}; var {a, b, c : {a : a1, b : b1}} = obj; console.log(a, b, a1, b1); //1 2 3 4 console.log(c); //報(bào)錯(cuò)氧急,c is not defined
let {a = 10, b = 20 } = {a : 30}; console.log(a, b); // 30 20 let [a, b, c = 0] = [1, 2];//c的默認(rèn)值是0
- 解構(gòu) JSON
var str = '{"a":1,"b":2}'; var {a, b} = JSON.parse(str); console.log(a, b); //1 2 var str = "[1,2,3,4,5]"; var [a, b, c, d, e] = JSON.parse(str); console.log(a, b); //1 2
- 解構(gòu)字符串
var str = "abcdef"; var [a, b, c, d, e] = str; console.log(a, b, c, d, e); //a b c d e var { length: a1 } = str; console.log(a1, str); //6 "abcdef"
- 參數(shù)傳值
function fn([a, b, c = 0]) { console.log(a + b + c); //4 } fn([1, 3]); let { a = 10 , b = 20} = { a : 20 , b : 30} //相當(dāng)于: 實(shí)參 = > 形參 function foo( { a = 20, b = 30, opt = "+"} = {}){ console.log(a , b , opt) //40 30 + } foo({a:40}); function foo( { a = 20, b, opt = "+"} = {}){ console.log(a , b , opt) //40 undefined + } foo({a:40});
-
擴(kuò)展運(yùn)算符
let obj = { a : 1, b : 2, c : 3 } let targetObj = { ...obj, d : 4 , e : 5 } console.log(targetObj); //{a: 1, b: 2, c: 3, d: 4, e: 5} // 兩個(gè)對(duì)象合并的方法; function newObject(obj){ return{ ····obj } } var obj = { a : 1, b : 2, c : 3 } console.log(newObject(obj)); //{a: 1, b: 2, c: 3, d: {…}} console.log(newObject(obj) === obj); //false obj.a = 100; console.log(newObject(obj).a); //100 //通過(guò)函數(shù)進(jìn)行淺克隆:此時(shí)輸出100是因?yàn)檩敵龅臅r(shí)候,又重新克隆了一邊
-
剩余操作符
將一個(gè)不定數(shù)量的參數(shù)表示為一個(gè)數(shù)組毫深。
let [a,...b] = [1,2,3,4,5,6,7,8,9,0]; console.log(a,b); //1 (9) [2, 3, 4, 5, 6, 7, 8, 9, 0]
-
字符串?dāng)U展方法
- includes()
判斷字符串中是否有該字符,返回布爾值,可以從第幾位開(kāi)始判斷
console.log("asbdwsa".includes("b",3));//false
- startWith()
判斷字符串中從某個(gè)位置開(kāi)始第一個(gè)元素是不是這個(gè)字符,如果沒(méi)有指定位置就是從頭開(kāi)始
console.log("abcedsjks".startsWith("a",0));//true
- endsWith()
判斷字符串中某個(gè)字符是否是最后一個(gè)
console.log("abcedsjks".endsWith("s"));//true
- repeat()
讓某個(gè)字符串重復(fù)若干次
console.log("abc".repeat(2));//abcabc
- trim()
去除字符串兩端的前后空格
console.log(" abc de ".trim()); //abc de
- padStart(參數(shù)1吩坝,參數(shù)2)
在前面增加指定字符,不足參數(shù)1的個(gè)數(shù)時(shí)哑蔫,就補(bǔ)幾個(gè)參數(shù)2
console.log("aaa".padStart(5,"$"));
- padEnd()
與padStart()同理钉寝,在后面增加指定字符,補(bǔ)足要求的長(zhǎng)度闸迷。
- 模板字符串
- 通過(guò)${}替換字符串
- ` 與“最大的區(qū)別是嵌纲,``它支持換行
var sss = 123 var templateString = `hello ${sss} world`; function fn(a){ console.log(a);//["4", raw: Array(1)] } fn `4`;
- EJS是一個(gè)JavaScript模板庫(kù),用來(lái)從JSON數(shù)據(jù)中生成HTML字符串腥沽。
- js語(yǔ)句直接寫在<% %>中
- 綁定的數(shù)據(jù)寫在<%= %>中
<script src="./libs/ejs.js"></script> var arr = [1, 2, 3, 4, 5, 6]; // 模板 => 只包裹JS , 不包裹HTML; var template = ` <% for(var i = 0 ; i < arr.length ; i ++){ %> <li> <a href="#"><%= arr[i] %> </a></li> <% } %> ` var res = ejs.render(template, { arr: arr }) // console.log(res); document.getElementById("list").innerHTML = res;
-
字符串模版封裝
<div id="list"></div> <script type="text/html" id="template"> <% for(var i = 0 ; i < arr.length ; i ++){ %> <li> <a href="javascript:void(0)"> <%= arr[i] %> </a> </li> <% } %> </script> var renderData = {} var tem = document.getElementById("template"); var list = document.getElementById("list"); Object.defineProperty(renderData, "data", { set: function(val) { var html = render(tem.innerHTML, val); list.innerHTML = html; this.$data = val; }, get: function() { return this.$data; } }) function render(template, data) { var html = ""; var normalReg = /<%([^=].*?)%>/g; var outputReg = /<%=(.*?)%>/g; template = template.replace(normalReg, `\`); $1 print(\``); template = template.replace(outputReg, `\`); print($1); print(\``); template = `print(\` ${ template } \`)`; // console.log(template); eval(template); function print(str) { html += str; } } renderData.data = [1, 2, 3, 4, 5, 6, 7, 8];
-
Symbol
唯一逮走,不參與運(yùn)算
let a = Symbol(5); let b = Symbol(5); console.log(a == b); //false
- 取出Symbol中的唯一值
var a = Symbol(5); console.log(a.toString().match(/^Symbol\((.*?)\)$/)[1]);
var obj = {}; var s = "b"; obj["a"] = 5; obj[s] = 10; obj[{a:1}] = 20; console.log(obj[{a:2}]); //20 obj[Symbol()] = 20; //Symbol類型不會(huì)轉(zhuǎn)換為字符串 console.log(obj[Symbol()]);//undefined
- 消除魔術(shù)字符串
var state = ""; const RUN = Symbol(); const WALK = Symbol(); const JUMP = Symbol(); const STAND = Symbol(); function setState(state){ switch(state){ case RUN: console.log("跑"); break; case WALK: console.log("走"); break; case JUMP: console.log("跳") break; case STAND: console.log("站立"); break; } }
-
set
- set不允許重復(fù)的列表,
- 刪除巡球、添加和查找的速度高于數(shù)組言沐,但是無(wú)法尋找到關(guān)系數(shù)據(jù)
- set中只有size ,沒(méi)有l(wèi)ength
let a = new Set(); a.add(2); a.add(3); a.add(5); a.add(3); console.log(a.has(3)); //true 判斷列表中是否含有該值 a.delete(); console.log(a); //{2, 3, 5}
- for of遍歷
let a = new Set([2,3,4,5,6,3,2,4]); for(let value of a){ console.log(value); }
- 數(shù)組去重
var arr = [2, 3, 5, 6, 7, 3, 2, 4, 2, 1, 2, 3, 4, 5]; arr = Array.from(new Set(arr)); console.log(arr);
-
Map hasMap
對(duì)象保存鍵值對(duì)
let map = new Map(); map.set("name","zhangsan"); map.set("age", 30); map.set("sex", "男"); console.log(map.get("age")); //30; console.log(map.size); // 3 console.log(map.has("age")) //true 判斷是否有當(dāng)前屬性 map.delete("age"); console.log(map);//{"name" => "zhangsan", "sex" => "男"} map.clear(); //清空map console.log(map); // {}
- 遍歷鍵
for(let value of map.keys()){ console.log(); }
- 遍歷值
for(let value of map.value()){ console.log(value); }
- 遍歷鍵和值
for(let value of map){ console.log(value); } map.forEach(value, key) =>{ console.log(value, key); }
-
生成器函數(shù)
- function* 這種聲明方式(
function
關(guān)鍵字后跟一個(gè)星號(hào))會(huì)定義一個(gè)生成器函數(shù) (generator function)酣栈,它返回一個(gè) [Generator
] 對(duì)象险胰。 - 生成器函數(shù)在執(zhí)行時(shí)能暫停,后面又能從暫停處繼續(xù)執(zhí)行矿筝。
- yield用來(lái)在生成器函數(shù)中定義暫停位置和進(jìn)行數(shù)值的返回起便,還有進(jìn)行執(zhí)行權(quán)的移交(yield *);
function* getSum(a,b){ yield a; yield b; let sum = a + b; return sum; } var sum = getSum(3, 5); console.log(sum.next());//{value: 3, done: false} console.log(sum.next());//{value: 5, done: false}
function* getSum(a, b) { a++; yield a; b--; yield b; let sum = a + b; yield sum; return sum; } var sum = getSum(3, 5); var first = sum.next(); while (!first.done) { console.log(first.value);//4 4 8 first = sum.next(); } var a = sum.next(); console.log(a.done);//true
異步過(guò)程強(qiáng)制變成同步阻塞
function* setNums() { yield setTimeout(fn1, 2000); yield setTimeout(fn2, 2000); } function fn1() { console.log("aaaa"); a.next(); } function fn2() { console.log("bbb"); } var a = setNums(); a.next();
避免了下面這種函數(shù)的嵌套
setTimeout(function() { setTimeout(function() { setTimeout(function() { }, 2000); }, 2000) }, 2000);
- function* 這種聲明方式(