前端笔记之ES678WebpackBabel(上)初识ES678Babellet和const解构语法
一、ES版本簡介和調試運行方法
1.1 ECMAScript簡介
MDN手冊:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
JavaScript 的標準是 ECMAScript。截至 2012 年,所有的現代瀏覽器都完整了支持 ECMAScript 5.1。舊式的瀏覽器至少支持 ECMAScript 3 標準。
2015年6月17日,ECMA國際組織發布了 ECMAScript 6.0,該版本正式名稱為ECMAScript 2015,是“JavaScript 語言的下一代標準”。但通常被稱為 ECMAScript 6或ES6。它的目標,是使得 JavaScript 語言可以用來編寫復雜的大型應用程序,成為企業級開發語言。本文檔目前覆蓋了最新ECMAScript的草案,也就是ECMAScript2018。
?
?ES是ECMAScript的簡稱。是JavaScript執行標準的制定者。
??ES6 也稱為ES2015 全稱是ECMAScript2015
??ES7 也稱為ES2016 全稱是ECMAScript2016
??ES8 也稱為ES2017 全稱是ECMAScript2017
??ES9 也稱為ES2018 全稱是ECMAScript2018
?
從 ES6開始ECMA組織每年發布一個版本,以年份作為名稱,因此又稱ECMAScript 2017,簡稱 ES2017。
大家基本上記不住哪個版本的ES更新了什么,所以統稱為ENV(ECMAScript New Version)。
?
1.2 ECMAScript和JavaScript的關系
?一個常見的問題是,ECMAScript 和 JavaScript 到底是什么關系?
講清楚這個問題,需要回顧歷史。1996年11月,JavaScript的創造者Netscape公司,決定將 JavaScript提交給標準化組織ECMA,希望這種語言能夠成為國際標準。次年,ECMA發布262號標準文件(ECMA-262)的第一版,規定了瀏覽器腳本語言的標準,并將這種語言稱為ECMAScript,這個版本就是1.0版。
?
該標準從一開始就是針對JavaScript語言制定的,但是之所以不叫JavaScript,有兩個原因。一是商標,Java是Sun公司的商標,根據授權協議,只有Netscape公司可以合法地使用 JavaScript這個名字,且 JavaScript本身也已經被 Netscape 公司注冊為商標。二是想體現這門語言的制定者是ECMA,不是 Netscape,這樣有利于保證這門語言的開放性和中立性。
?因此,ECMAScript和JavaScript的關系是,前者是后者的標準,后者是前者的一種實現。日常場合,這兩個詞是可以互換的。
?
關于更多ECMAScript請閱讀:http://es6.ruanyifeng.com/#docs/intro
?
1.3瀏覽器兼容性
瀏覽器和NodeJS對ES6新語法特性的支持,要看兼容性。各大瀏覽器的最新版本,對 ES6 的支持可以查看:
?https://www.caniuse.com/
?http://kangax.github.io/compat-table/es6/
?
隨著時間的推移,支持度已經越來越高了,超過 90%的 ES6 語法特性都實現了。
Node 是 JavaScript 的服務器運行環境(runtime),它對 ES6的支持度更高。
?
訪問http://ruanyf.github.io/es-checker可以查看當前瀏覽器的支持ES6的程度
ES-Checker這個工具,可以用來檢查你當前Node支持ES6的程度
運行下面的命令,可以查看你在使用的Node環境對ES6的支持程度
$ npm install -g es-Checker $ es-checkerNodejs現在的最高版本是10,隨著版本的升級,實際上Nodejs本身比如http、fs模塊等幾乎沒什么更新,變化就是對ES的新語法支持,Nodejs 6最高版本,幾乎全部支持了常用的新版ES語法。
?在瀏覽器和node環境都可以運行,但是有很多舊版瀏覽器尚未支持。
?
高級瀏覽器開始逐步支持ES6、7、8這些新特性,比如寫一個“自動解構”語法:
const [a,b,c] = [1,2,3]; console.log(a) console.log(b) console.log(c)二、Babel翻譯器
?????由于瀏覽器的版本和兼容性問題,很多JavaScript的新的方法都不能使用,等到可以大膽使用的時候,可能已經過去了好幾年。Babel就因此而生,它可以讓你放心使用大部分的JavaScript的新的標準的方法,然后編譯成兼容絕大多數的主流瀏覽器的代碼。
Babel是一個廣泛使用的ES6轉碼器,可以將ES6代碼轉為ES5代碼,從而在現有環境執行。這意味著,你可以用 ES6 的方式編寫程序,又不用擔心現有環境是否支持。
?
中文官網:https://babeljs.cn
?
2.1 babel安裝
Babel是我們學習的第一個前端工作流工具,它是一個JavaScript編譯器,能將ES6、7、8的代碼翻譯成IE8能夠識別的ES5語法。
l?什么是前端工作流工具?
用Nodejs編寫的,用npm發布的,一些開發人員在開發的時候能夠運行的便利工具。
?
安裝babel工作流工具:
npm install -g babel-clibabel提供babel-cli工具,用于命令行轉換,-g安裝之后的程序并不是屬于某一個單獨的項目,而是操作系統的全局。CLI表示Command Line Interface,命令行接口,就是用CMD能夠調用這個命令。
?
?安裝完畢后,用命令查看版本是否安裝成功
babel --version?
在項目文件夾中打開CMD命令行窗口,輸入:
babel 01.js -o a.js-o表示output輸出,這條語句能將01.js翻譯為a.js
?
但是發現,并沒有將ES6語法翻譯成ES5語法:
| ? ? | ? ? |
?
因為我們沒有告訴babel,讓它去幫我們翻譯ES6語法,怎么指導它翻譯?
接下來需要配置對應的.babelrc文件才可以發揮完整的作用。
2.2 .babelrc文件preset
必須使用.babelrc文件去指導babel工作。
windows系統不允許用戶創建“.”開頭的文件
?
方法1:用sublime可以新建。
?
方法2:打開cmd窗口,輸入一下命令將a.txt文件重命名為.babelrc
rename a.txt .babelrc?
?預設(presets)
該文件用來設置轉碼規則和插件,使用的時候需要安裝對應的插件,并且寫一些配置:
{"presets":["es2015","es2016"] }用presets設定轉碼規則,就是說babel要翻譯哪些語法,我們一般翻譯es2015、es2016寫在數組中。
?
env表示ECMAScript New Version,就是新的版本ES語法:
{"presets":["env"] }?
接下需要安裝語法依賴:
npm install --save-dev babel-preset-es2015 npm install --save-dev babel-preset-es2016--save-dev表示添加“開發依賴”,--save表示添加“運行依賴”,開發時需要babel翻譯,運行時babel已經翻譯好了,運行就不需要babel了,所以--save-dev是開發才需要的。
?
安裝完插件后,就可以再次使用babel翻譯
babel 01.js -o a.js| 翻譯前: ? ? | 翻譯后: ? ? |
?
Babel的配置和使用總流程:
?
presets字段設定轉碼規則,官方提供以下的規則集,你可以根據需要安裝。
?
最新轉碼規則:
$ npm install --save-dev babel-preset-latest?
不同階段語法提案的轉碼規則(共有4個階段),選裝一個:
$ npm install --save-dev babel-preset-stage-0 $ npm install --save-dev babel-preset-stage-1 $ npm install --save-dev babel-preset-stage-2 $ npm install --save-dev babel-preset-stage-3?
然后,將這些規則加入.babelrc文件。
{"presets": ["latest","react","stage-2"],"plugins": []}上面這些代碼是在全局環境下,進行Babel轉碼。這意味著,如果項目要運行,全局環境必須有安裝Babel,也就是說項目產生了對環境的依賴。另一方面,這樣做也無法支持不同項目使用不同版本的Babel。
?
所以,雖然在你的機器上全局安裝 Babel CLI, 但根據單個項目進行本地安裝會更好一些。
這樣做有兩個主要的原因:
同一機器上的不同項目可以依賴不同版本的 Babel, 這允許你一次更新一個項目。
這意味著在你的工作環境中沒有隱含的依賴項。它將使你的項目更方便移植、更易于安裝。
?
解決辦法是將babel-cli安裝在項目中,通過以下命令本地安裝Babel CLI到項目依賴:
npm install --save-dev babel-cli更多請閱讀:
http://www.ruanyifeng.com/blog/2016/01/babel.html
三、const和let
開始學習ES6、7、8的語法精粹。
更多的去看:http://es6.ruanyifeng.com/
?
3.1 const
const用來定義常量,所謂的常量就是值一旦給定后就不變,一次定義終身不變的量。
const a = 10; a = 20;上面的a就是常量,如果給a重新賦值,會報錯。
?
?
const通常會定義兩種值
l?定義函數
const sum = function(a,b){return a + b; } console.log(sum(3,4))?
l?定義一些特定的字符串和常數
const PI = 3.14; const HELLO_WORLD = "世界,你好";常量名一般全是大寫,如果由多個單詞組成,用下劃線隔開,暗示這個是常量。
3.2 let
let用來定義塊級作用域的變量,只要有“{}”包裹,就表示塊級作用域。
注意:不是JSON,if語句體、函數、while、for是塊,for循環的()部分也是塊級。
{var a = 10; } console.log(a); //10?
var這個定義的變量是函數級作用域,不是塊級作用域。
{let a = 10; } console.log(a); //報錯 a is not defined?
注意:通常在for循環使用let,此時循環體中自動加了閉包:
for(let i = 0;i < 10;i++){} console.log(i);//報錯?
看一個面試題:
var arr = []; for(var i = 0; i < 10;i++){arr.push(function(){console.log(i)}) } console.log(arr) arr[4]();數組中存儲了10個函數,當我們任意調用時,比如arr[4]()函數,會輸出10.
?
因為函數調用時,i已經變成10了,i其實是一根全局變量,要使用IIFE執行函數:
var arr = []; for(var i = 0; i < 10;i++){(function(a){arr.push(function(){console.log(a)})})(i); } console.log(arr) arr[4]();?
現在用let,非常簡單:
var arr = []; for(let i = 0; i < 10;i++){arr.push(function(){console.log(i)}) } console.log(arr) arr[4]();let和for是絕配,let平時沒啥用。
?
總結:
l?const用來定義常量,通常定義函數和常數
l?let用來定義{}塊級的作用域的變量,通常用來定義for循環的變量
常量是塊級作用域,很像使用let,語句定義的變量,常量的值不能通過重新賦值來改變,并且不能重新聲明。
?
let和const的疑點等面試題再加,比如:
console.log(m); let m = 10; //報錯,let沒有變量聲明提升3.3 Babel的翻譯結果
對于const。babel會翻譯var,但是翻譯的時候,會驗證const是否重新賦值了,是就報錯。
| 翻譯前: ? ? | 翻譯后: ? ? |
?
for循環的翻譯:
| 翻譯前: ? ? | 翻譯后: ? ? |
?
四、變量的解構賦值
ES6 允許按照一定模式,從數組和對象中提取值,給變量進行賦值,這被稱為解構。
解構的作用是可以快速取得數組或對象中的元素或屬性,而無需使用arr[x]或obj[key]等傳統方式去賦值。
以前為變量賦值,只能直接指定值:
var a = 1; var b = 2; var c = 3;4.1數組解構
所謂的解構就是一個快速給數組或者對象中的值,快速傳入變量的方法。
數組可以解構,當等號右側是數組的時候,等于左側可以將變量裝入[]中接收,一一對應接收。
var [a,b,c] = [1,2,3]; console.log(a); //1 console.log(b); //2 console.log(c); //3上面代碼表示,可以從數組中提取值,按照對應位置,給變量賦值。
本質上,這種寫法屬于“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。
?
如果數組較為復雜,此時左側結構的那項變量,也有相同的結構
var [a,b,[c,d]] = [1,2, [3,4]]; console.log(a); //1 console.log(b); //2 console.log(c); //3 console.log(d); //4 var [a,b,c] = [1,2, [3,4]]; console.log(a); //1 console.log(b); //2 console.log(c); //[3,4]?
下面是一些嵌套數組進行解構的例子:
let [x, ,y] = [1, 2, 3]; console.log(x) // 1 console.log(y) // 3如果解構不成功,變量的值等于undefined
let [a] = []; let [b,c] = [1]; console.log(a); //undefined console.log(b); //1 console.log(c); //undefined?
另一種情況是不完全解構,即等號左邊的模式,只匹配一部分的等于右邊的數組,這種情況:
let [a,[b],c] = [1,[2,3],4]; console.log(a); //1 console.log(b); //2 console.log(c); //44.2對象解構
對象的結構和數組有個不同點,數組的元素是按照順序排列,變量的取值由它的位置決定。
而對象的屬性沒有順序,但是變量必須與屬性同名,才能取到正確的值。
var {name,id,sex} = {"id":1001, "name":"小明", "sex":"男"}; console.log(id) console.log(name) console.log(sex)上面的例子,等號左邊的變量順序和等號右邊3個同名屬性的順序不一樣,但取值沒有影響。
?
如果變量名和屬性名不一致,必須寫成下面這樣:
var {name:names, id:ids, sex: sexs} = {id:1001, name:"小明", sex:"男"}; console.log(ids) console.log(names) console.log(sexs)實際上說明,對象的解構賦值是上面形式的簡寫。
上面代碼中name是匹配模式,names才是變量,真正被賦值的是names,而不是names。也就是說,對象解構賦值的內部機制,是先找到同名屬性,然后再賦值給對應的變量,真正被賦值的是后者。
4.3默認值
解構賦值允許指定默認值。
let [a = 100] = []; let [x, y = 200] = [100] console.log(a); //100 console.log(x); //100 console.log(y); //200注意:ES6內部使用嚴格相等運算符(===),判斷一個位置是否有值,所以只有當一個數組成員嚴格等于undefined,默認值才會生效。
?
let [a = 88] = [undefined] let [b = 88] = [null] console.log(a); //88 console.log(b); //null上面代碼中有一個數組成員是null,默認值就不生效,因為null不嚴格等于undefined。
更多解構的知識點閱讀:http://es6.ruanyifeng.com/#docs/destructuring
?
字符串也可以解構賦值。這是因為此時,字符串被轉換成了一個類似數組的對象。
const [a, b, c, d, e] = 'hello'; console.log(a) // "h" console.log(b) // "e" console.log(c) // "l" console.log(d) // "l" console.log(e) // "o"4.4擴展運算符(spread operator)
擴展運算符(spread)是三個點(...)。將一個數組轉為用逗號分隔的參數序列,還能強制展開一個對象,通常用于對象的賦值,使用靈活廣泛。
?
l?第一個作用:稱為“展開運算符”,作用和字母意思用于,就是把東西展開,可以用在數組和對象上。
var obj1 = {a : 100,b : 200,c : 300 }var obj2 = { ...obj1,d : 888 }console.log(obj1) console.log(obj2) console.log(obj1 === obj2);?
數組也可以強制展開,通常數組的賦值,比如有兩個數組合并成一個數組:
var arr1 = ["小白","小黑","白無常","黑無常"]; var arr2 = ["小明","小紅","小花","小剛"];var arr = [...arr1, ...arr2]; console.log(arr);?
?原來想把一個數組打散傳入到函數中作為參數,通常用apply:
function sum(a,b,c,d){return a+b+c+d; }var arr = [1,2,3,4]; console.log(sum.apply(null, arr)); //10?
可以用...運算符,將數組強制展開為一個散列的形式
function sum(a,b,c,d){return a+b+c+d; }var arr = [1,2,3,4]; console.log(sum(...arr)); //104.5剩余操作符(rest operator)
第二、三個作用:叫“剩余操作符”是解構的一種,意思是把剩余的參數放到一個數組或對象中賦值給它。一般針對數組或對象。
注意“...”只能出現最后一個參數,并且通過這個例子發現...能將零散的值收納為數組。
var [a,b, ...c] = [1,2,3,4,5,6]; console.log(a); console.log(b); console.log(c);?
邏輯上“...”是一個運算符
console.log(...[1,2,3,4])通過這個實驗發現,“...”能將數組打散為零散值。
?
應用場景1:當寫Ajax時,參數是JSON,此時可以直接將JSON解構
JSON:
{"a":100,"b":200,"c":300}?
傳統方法接收:
$.get("data/1.json", function(data){console.log(data.a)console.log(data.b)console.log(data.c) })?
ES6的解構語法接收數據:
$.get("data/1.json", function({a,b,c}){console.log(a)console.log(b)console.log(c) })?
補充個知識點,在ES6中當一個對象的k和v一致時,可以省略v。
var a = 10; var obj = {a,b : 20,c : 30, } console.log(obj); //{ a: 10, b: 20, c: 30 }?
應用場景2:
以后函數大概率都是接收一個JSON當參數,并且用ES6解構語法寫形參
調用函數的時候傳的參數,一般都是k:v,一直省略v
var name = "小明"; var height = 170; var weight = 100; function buy({name,weight,height}){console.log(name)console.log(height)console.log(weight) }// buy({name:"小明", height:170, weight:100}); // buy({name:name, height:height, weight:weight}); buy({name, height, weight});紅色部分的語句是在創建JSON,綠色的部分是在進行結構。
調用函數時參數順序打亂也不影響結構,因為解構,會自動匹配key。
?
應用場景3
有一個數組arr1,在不改變arr1數組情況下,想往arr1數組前面加一項作為arr2新數組。
var arr1 = [8,9,10,11,12]; var arr2 = [...arr1, 13]; var arr3 = [7, ...arr1]; console.log(arr1) console.log(arr2) console.log(arr3)?
擴展運算符和剩余操作符的區別
簡單的說,在某種程度上,剩余操作符和擴展運算符相反,擴展運算符會“展開”數組變成多個元素,剩余操作符會收集多個零散元素合并成一個元素。
4.6對象解構的翻譯問題
注意:babel會將“[]”和“{}”解構變為一個個的var。
| 數組解構翻譯前 | 數組解構翻譯后 |
| ? ? | ? ? |
?
但是babel不能翻譯“對象解構”,只能翻譯數組解構:
?
原因:object-rest-spread 還處于stage階段(屬于實驗性屬性)。
?
解決方法:安裝babel插件transform-rest-spread,放到.babelrc文件配置上,即可使用。
{"presets":["es2015","es2016"],"plugins":["transform-object-rest-spread"] }.babelrc的presets是用來定義預設,plugins定義插件。
?
安裝依賴:
npm install babel-plugin-transform-object-rest-spread --save-dev此時,babel就可以翻譯對象解構了。
| 對象翻譯前 | 對象翻譯后 |
| ? ? | ? ? |
?
變量的解構賦值用途很多。
五、ES6語法
ES6中對數組新增了幾個函數:map()、filter()、reduce()
ES5新增的forEach()。
都是一些語法糖。
5.1 forEach()遍歷數組
forEach()方法用來循環遍歷數組,方法中的function回調函數接收3個參數
參數1是遍歷的數組內容(item);參數2是對應的數組索引(index),參數3是是數組本身(array)。
[].forEach(function(item,index,array){ ... }) var arr = ["白板","幺雞","紅中","發財","八萬"]; arr.forEach(function(item,index,array){console.log(item,index,array) })forEach函數沒有返回值
for今后是創建數組,遍歷或操作數組可以交給forEach方法。
5.2 map()映射
map方法的作用,“映射”也就是原數組被“映射”成對應的新數組。
[].map(function(item,index,array){ ... }) var arr = ["白板","幺雞","紅中","發財","八萬"]; arr.map(function(item,index,array){console.log(item,index,array) })?
寫一個案例:比如創建一個新數組,每一項都是原數組值的兩倍
var arr = [10,20,30,40,50,99]; var newArr = arr.map(function(item,index,array){return item * 2; //返回一個新的結果,給變量接收,原數組不變 }); console.log(arr) console.log(newArr);?
?map函數的本質是依次遍歷原數組的每一項,將每一項都執行一遍函數中的語句,返回一個新的數組。
注意:
l?函數需要有return值,如果沒有,數組所有項都被映射成undefined。
l?map返回的數組一定和原數組的長度一樣。
?
在實際使用時,可以利用map()方便獲取對象數組中的特定屬性值們,例如下面例子:
var user = [{name:"小明","email":"xiaoming@qq.com"},{name:"小紅","email":"xiaohong@qq.com"},{name:"小剛","email":"xiaogang@qq.com"} ]var emails = user.map(function(item,index,array){return item.email; }) console.log(emails.join(","))5.3 filter()過濾
filter為“過濾、篩選”之意,指原數組中filter某些項后,返回過濾后的新數組,用法和map相似。
比如想從原數組中,挑選所有的偶數,返回新的數組。
var arr = [312,55,77,11,13,15,18,26,30,40,50,99]; var newArr = arr.filter(function(item,index,array){return item % 2 == 0; }); console.log(arr) console.log(newArr)描述:arr中的每一項會依次的執行函數,filter的callback函數需要返回布爾值true或false。true則將值返回到新數組中,false無情地將你拋棄…
?
再比如,從數組中選擇及格的學生:
var arr1 = [{name:"小明","chengji":50},{name:"小紅","chengji":70},{name:"小黑","chengji":56},{name:"小剛","chengji":88} ]// var arr2 = arr1.filter(function(item){ // return item.chengji >= 60; // });// var arr2 = arr1.filter((item)=>{ // return item.chengji >= 60; // });// var arr2 = arr1.filter(item=>{ // return item.chengji >= 60; // });var arr2 = arr1.filter(item => item.chengji >= 60;);console.log(arr1) console.log(arr2)filter和map相同點:都會遍歷數組的每一項
filter和map不同點:map返回數組不會少項,filter可能少項。
5.4 reduce()迭代
reduce中文意思是“減少”、“約簡”,不過從功能來看,是無法與“減少”這種含義聯系起來的,反而更接近于“迭代”、“遞歸(recursion)”
arr.reduce(callback,[initialValue])第一個參數的callback回調函數有四個參數,第二個為設定的初始值(可選)。
callback函數有四個參數:
previous :上一次疊加的結果值或初始值
current : 當前會參與疊加的項
index :當前值的下標
array :原數組本身
?
var arr = ["白板","幺雞","紅中","發財","三餅"]; arr.reduce(function(prev,cur,index,array){console.log(prev,cur) })reduce的原理:從下標為1的項開始遍歷,每次return的值將作為下一項的prev值,這一次的遍歷是cur,prev會有累加的感覺。
案例1:求數組的總和:
var arr = [3,4,5,6]; var sum = arr.reduce(function(prev, cur){console.log(prev); //3、7、12、18// console.log(cur); //4,5,6return prev + cur; })console.log(sum);//18?
求數組的最大值【經典面試題】:
var arr = [43,5,4,6,888,78,554,5,6]; // var max = Math.max.apply(null,arr); var max = arr.reduce(function(a, b){console.log(a); //43、43、43、43、888、888、888...// console.log(b);return a > b ? a : b; })console.log(max);reduce可以設置初始參數(參數自定義),下標從0開始遍歷。
?
求文科狀元是誰?
var arr = [{id:1,name:"小明",sex:"男",yuwen:30},{id:2,name:"小紅",sex:"女",yuwen:60},{id:3,name:"小白",sex:"男",yuwen:130},{id:4,name:"小黑",sex:"男",yuwen:90},{id:5,name:"小花",sex:"男",yuwen:120} ]var newArr = arr.reduce(function(a,b){return a.yuwen > b.yuwen ? a : b; }) console.log(newArr)?
要求最高分:
reduce可以設置初始參數(參數自定義),當reduce有第二個參數時,此時reduce遍歷將從第0項開始遍歷,而不是第1項開始。
var newArr = arr.reduce(function(a,b){console.log(a); //0 return b.yuwen > a ? b.yuwen : a; }, 0); //初始值是0 console.log(newArr)5.5用途-寫純函數
上面的四大數組方法:map、filter、reduce特別有用,做“函數式”編程。
什么是“函數式(蘭姆達式編程)”編程?
????所有的函數都是純函數的時候,此時就是函數式編程。
什么是純函數?
純函數是指不依賴于且不改變它作用域之外的變量狀態的函數。
l?這個函數內部不改變傳入的參數。
l?傳入這個函數一定有參數,一定會返回某一個確定的值。
l?函數中的語句,不能有隨機性,比如Math.random()、new Date(),傳入的參數相同,返回的值必定相同;
l?這個函數里面不能有任何異步語句,比如$.get()、fs.readFile()、setInterval()
一定要好好學純函數,因為react、vue都是純函數(蘭姆達)式編程。
?
【例子1】請寫一個純函數addItem(),接收arr、n當做參數,能夠在arr的尾部增加n。
錯誤的例子:
var arr = [99,88,77]; function addItem(arr,n){arr.push(n); } addItem(arr, 66) console.log(arr);//arr被改變了,addItem不是純函數我們絕對不能改變傳入的參數的值。
?
正確寫法:
var arr = [99,88,77]; function addItem(arr,n){return [...arr, n]; } var arr2 = addItem(arr, 66); //返回一個新數組 console.log(arr); //原數組不變 console.log(arr2);?
【例子2】請寫一個純函數addItem(),接收arr、n當做參數,能夠在arr的頭部增加n。
var arr = [99,88,77]; function addItem(arr,n){return [n,...arr]; } var arr2 = addItem(arr, 66); //返回一個新數組 console.log(arr); //原數組不變 console.log(arr2);?
【例子3】請寫一個純函數removeItem(),接收arr、n當做參數,能夠將arr第下標為n的那項刪除。
var arr = ["白板","幺雞","二條","三萬"]; function removeItem(arr,n){// return arr.filter(function(item,index){// return index != n;// }) return arr.filter((item,index)=> index != n) } var arr2 = removeItem(arr, 2) console.log(arr); console.log(arr2);?
【例子4】請寫一個純函數changeItem(),接收arr、n、a當參數,能將arr第下標為n的那項改變值為a。
var arr = ["白板","幺雞","二條","三萬"]; function changeItem(arr,n,a){return arr.map(function(item,index){return index === n ? a : item;}) } var arr2 = changeItem(arr, 2 ,"九條"); console.log(arr) console.log(arr2)?
比如,寫一個函數,可以刪除數組指定id那項,傳統寫法:
var arr = [{id:1,name:"小明",sex:"男",yuwen:30},{id:2,name:"小紅",sex:"女",yuwen:60},{id:3,name:"小白",sex:"男",yuwen:130},{id:4,name:"小黑",sex:"男",yuwen:90},{id:5,name:"小花",sex:"男",yuwen:120} ] //刪除某一個id學生function delStudent(arr,id){for(var i = 0;i < arr.length;i++){if(arr[i].id == id){arr.splice(i, 1)}} } delStudent(arr, 2) console.log(arr); //arr被改變了,不是純函數這個數組雖然好用,但不是純函數,因為它返回的結果依賴于外部變量arr,并且這個函數改變了原來的數組,它會把原來的數組弄的一團糟,我們絕對不改變傳入的參數的值。
?
?
【以下都是純函數寫】
var arr = [... ] //刪除某一個id學生function delStudent(arr,id){return arr.filter(function(item){//如果item.id不等于傳入的id則為真會被返回,否則不返回return item.id != id;}) } var arr2 = delStudent(arr, 2); //返回一個新數組,原數組不變 console.log(arr) console.log(arr2)上面代碼,我們只計算了作用域內的局部變量,沒有任何的作用域外的變量被改變了。
?
更改指定id的name屬性
var arr = [... ] //改變某一個id學生的name屬性 function changeName(arr, id, name){return arr.map(function(item){// if(item.id == id){// return {...item, name}// }// return item;item.id == id ? {...item, name} : item;}) }?
增加學生:
var arr = [{id:1,name:"小明",sex:"男",yuwen:30},{id:2,name:"小紅",sex:"女",yuwen:60},{id:3,name:"小白",sex:"男",yuwen:130},{id:4,name:"小黑",sex:"男",yuwen:90},{id:5,name:"小花",sex:"男",yuwen:120} ] function addStudent(arr,{id,name,sex,yuwen}){return [...arr,{id,name,sex,yuwen}]; } var s = {id:8,name:"鋼炮",sex:"未知",yuwen:100} var newArr = addStudent(arr, s) console.log(newArr)?
查找所有男同學
var arr = [{id:1,name:"小明",sex:"男",yuwen:30},{id:2,name:"小紅",sex:"女",yuwen:60},{id:3,name:"小白",sex:"男",yuwen:130},{id:4,name:"小黑",sex:"男",yuwen:90},{id:5,name:"小花",sex:"男",yuwen:120} ]function findSex(arr, sex){return arr.filter(function(item){return item.sex == sex;}) } var newArr = findSex(arr, "男");console.log(newArr)刪除用filter、修改用map、增加用...或map
?
l?總結
為什么要煞費苦心地構建純函數?因為純函數非常“靠譜”,執行一個純函數你不用擔心它會干什么壞事,它不會產生不可預料的行為,也不會對外部產生影響。不管何時何地,你給它什么它就會乖乖地吐出什么。如果你的應用程序大多數函數都是由純函數組成,那么你的程序測試、調試起來會非常方便。
?
l?使用純函數的好處
最主要的好處是沒有副作用。純函數不會修改作用域之外的狀態,做到這一點,代碼就變得足夠簡單和清晰:當你調用一個純函數,你只要關注它的返回值,而不用擔心因為別處的問題導致錯誤。
純函數是健壯的,改變執行次序不會對系統造成影響,因此純函數的操作可以并行執行。
純函數非常容易進行單元測試,因為不需要考慮上下文環境,只需要考慮輸入和輸出。
?
函數是接受一些輸入,并產生一些輸出的過程。這些輸入稱為參數,輸出稱為返回值。
?
純函數的返回值只由它調用時的參數決定,它的執行不依賴于系統的狀態(比如:何時、何處調用它)。
?
l?純函數的條件:
l?一個函數的返回結果只依賴于它的參數
l?不依賴外部狀態
l?執行過程中沒有副作用
?
什么叫函數執行過程沒有副作用?
一個函數執行過程中對外部產生了變化,那么就說這個函數是有副作用的。
?
轉載于:https://www.cnblogs.com/rope/p/10729568.html
總結
以上是生活随笔為你收集整理的前端笔记之ES678WebpackBabel(上)初识ES678Babellet和const解构语法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: N - Dragon Balls(并查集
- 下一篇: .NET单点登录实现方法----两种