ES6相关操作方法
es6入門
一、es6 簡介
1.什么是es6?
Es6是簡稱,全稱是ECMAScript 6.0。由于es6是2015年6月份發(fā)布的標(biāo)準(zhǔn)。又可以稱之為ECMAScript 2015,或es2015。它的目標(biāo),是使得 JavaScript 語言可以用來編寫復(fù)雜的大型應(yīng)用程序,成為企業(yè)級開發(fā)語言。
2.ECMAScript和JavaScript的關(guān)系
請問二者相等嗎?
ECMAScript != JavaScript
稍微回顧js的歷史。
ECMAScript是一個語言標(biāo)準(zhǔn)。
JavaScript則是這個語言標(biāo)準(zhǔn)的一個具體實現(xiàn)。在瀏覽器環(huán)境中的具體實現(xiàn)。
再如,微軟的Jscript。Flash中的ActionScript,服務(wù)器端的node。
ECMAScript只是提供了js語法。
JavaScript通常是指瀏覽器的ECMAScript的實現(xiàn),除了有ECMAScript語法之外,還有瀏覽器相應(yīng)的接口,比如documnet.getElmentById。
由于js和ECMAScript并不是同一個概念,所以在es6之后,就不再叫javascript了,而是回歸到本來的名稱。
3.ECMAScript的歷史
ES6從開始制定到最后發(fā)布,整整用了15年。
1997年發(fā)布ECMAScript 1.0
1998年6月發(fā)布ECMAScript 2.0
1999年12月發(fā)布 ECMAScript 3.0(巨大成功,奠定js的基本語法)
2000年,其實有一個4.0版本,由于激進,沒有獲得通過。
2009年12月,ECMAScript5.0 版正式發(fā)布
2015年6月,ECMAScript 6.0 正式通過,成為國際標(biāo)準(zhǔn)。
ECMA決定:從2015年開始,每一年發(fā)布一個新的版本。
2016年6月,小幅修訂的《ECMAScript 2016標(biāo)準(zhǔn)》即 ES6.1 版
根據(jù)計劃,2017年6月發(fā)布 ES2017 標(biāo)準(zhǔn)。
還有es6、es7和es8的說法。
ES6 既是一個歷史名詞,也是一個泛指,含義是5.1版以后的 JavaScript 的下一代標(biāo)準(zhǔn),涵蓋了ES2015、ES2016、ES2017等等,有時也泛指“下一代 JavaScript 語言
4.為什么要學(xué)習(xí)ES6?
es6的出現(xiàn),給前端開發(fā)人員帶來了新的驚喜,它包含了一些很棒的新特性,可以更加方便的實現(xiàn)很多復(fù)雜的操作,提高開發(fā)人員的效率。
二、let
let的作用,和var是類似的。是用來聲明變量的
let聲明的變量有一些特性:
-
塊作用域
-
不能聲明提前
-
在同一個塊作用域中,不允許重復(fù)聲明變量
-
暫時性死區(qū)
(1)基本使用
let a=200; console.log(a);a=400; console.log(a); // 從這個層面來講,和var是一樣的效果(2)塊級作用域
首先需要搞清楚,在es5中,有沒有塊作用域?
沒有,在es5中,變量的作用域只有兩種:
-
全局變量
-
局部變量
它們是以函數(shù)作為分界線的。
以單層函數(shù)為例:函數(shù)外部的,就是全局變量,如果是在函數(shù)內(nèi)部聲明的變量,就是局部變量。
Let則提供了塊作用域的用法。
也就說,在es6中,使用let來聲明變量,就有三種作用域:
-
全局作用域
-
局部作用域
-
塊級作用域
定義一個塊級的變量如下:
<script>{let b = 20;const c = 30;console.log(b); console.log(c);}console.log(b);</script>使用let聲明的變量,只在當(dāng)前塊有效果
//在進行for循環(huán)時,使用let來聲明計數(shù)器變量,如下: for (let i = 0; i < 10; i++) {....... } console.log(i)此處說明,這個i并不是一個全局變量,而是塊級變量。
小結(jié):****let聲明的變量,局部塊級作用域特性,具體體現(xiàn)在兩個地方:****
-
{}
-
for循環(huán)中聲明的計數(shù)器
(3)不能聲明提前
和var對比,var可以聲明提前,但是let不可以。
{console.log(s);let s = "let es6"console.log(s)}所以,在使用let聲明變量時,必須要先聲明,然后才能使用發(fā),否則報錯
(4)不能重復(fù)聲明
在同一個塊級作用域中,不能重復(fù)聲明
{let a=100;let a=200;console.log(a); }在不同的作用域中,我們是可以聲明的。
let a=400; //全局的 console.log(a) {let a=100; //塊級的console.log(a); }(5)暫時性死區(qū)–(面試)
只要塊級作用域內(nèi)存在let命令,它所聲明的變量就“綁定”(binding)這個區(qū)域,不再受外部的影響。
在代碼塊內(nèi),使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時性死區(qū)”,temporal dead zone,簡稱 ****TDZ****。
<script> var world = 'globalWorld';function fn(){console.log(s1);let world = 'location';console.log(world)}fn() </script> var world = 'globalWorld';function fn(){//暫時性死區(qū)開始了//console.log(s1);//暫時性死區(qū)結(jié)束了let world = 'location';console.log(world)}fn()let還有哪些應(yīng)用呢?
//給li循環(huán)綁定點擊事件,當(dāng)點擊的時候,分別彈出0,1,2,3 //一般可能會這么寫?var lis = document.getElementsByTagName("li"); for(var i=0;i<lis.length;i++){lis[i].onclick=function(){alert(i)}} //執(zhí)行之后,發(fā)現(xiàn)每一個li點擊之后彈出的都是4,并不是我們期望的0,1,2和3。原因何在?
其實,我們一定要搞清楚,代碼的編寫和執(zhí)行是分開的。換言之,事件的執(zhí)行一定是分兩個過程:
-
注冊過程,綁定過程
-
觸發(fā)了,執(zhí)行注冊好代碼
在注冊的過程中,for語句一定會執(zhí)行。但是函數(shù)中的alert是不會執(zhí)行的
循環(huán)完畢,相當(dāng)于是如下代碼:
lis[0].onclick=function(){alert(i)}lis[1].onclick=function(){alert(i)}lis[2].onclick=function(){alert(i)}lis[3].onclick=function(){alert(i)}其中的i,由于沒有執(zhí)行,仍然是i.
循環(huán)完畢,i的值已經(jīng)是4了.
然后,當(dāng)我們點擊具體的某一個li時,才會真正的執(zhí)行function代碼.
此時,i的值就是外部的i,都會彈出4.
解決方法有二:
-
人為的給每一個li元素對象增加一個索引值
-
利用自執(zhí)行函數(shù)或閉包
a.增加索引
var lis = document.getElementsByTagName("li"); for(var i=0;i<lis.length;i++){lis[i].index = i;lis[i].onclick=function(){alert(this.index)}} //測試,okb.自執(zhí)行函數(shù)和閉包
for(var i=0;i<lis.length;i++){lis[i].onclick=function(n){return function(){alert(n);}}(i)} //測試,ok這里之所以,可以就是因為針對每一個li綁定的處理函數(shù)中,都有一個自己是局部變量,值依次是i循環(huán)的值,分別是0,1,2和3。
c.let 的方式
for(let i=0;i<lis.length;i++){lis[i].onclick=function(){alert(i)}} //測試,ok盡管現(xiàn)在看到只有一個i,但是這個i不是全局的i,而是每一個事件處理函數(shù)自己的i。
實際上,let 的出現(xiàn),其實就是為了解決這一類的問題。
三、const
作用:是用于定義常量的。
在es5中,js中是沒有常量的概念。所有的都是通過var來定義
const PI=3.1415926;console.log(PI);PI=3.14;console.log(PI)和let對比,let定義的變化,其值是可以修改的。而const定義的量是不能修改的。
-
const在聲明的時候必須要賦值。
const num;num = 20.5;console.log(num);
除了上述兩個區(qū)別,其他let局部的幾大特性,const也都具備
-
不存在聲明提前
-
只在當(dāng)前的塊級作用域內(nèi)有效
-
不能重復(fù)聲明
-
存在暫時性死區(qū)
注意:****常量的本質(zhì)****
const定義的常量是不能修改的
對于應(yīng)用數(shù)據(jù)類型:
- 直接修改了指向
- 只是修改了屬性,
實際上,我們說const真正不變的是常量保存的內(nèi)容。
如果是基本數(shù)據(jù)類型,就是值
如果是引用數(shù)據(jù)類型,就是指對象的地址,地址不變就ok。
到了es6中,大家在編寫代碼的時候,就不要再寫var了。
需要使用let或者const。
如果這個值需要變化,就使用let。
如果這個值不會變化,就使用const。
四、try catch
我們編譯運行程序出錯的時候,編譯器就會拋出異常。同時程序下面的代碼不能執(zhí)行,這對開發(fā)不是很好,但是有一種更為合理的語法結(jié)構(gòu) try..catch,它會在捕捉到異常的同時不會使得代碼停止執(zhí)行而是可以做一些更為合理的操作。
function rand(){? var i = Math.random()*10;? if(i<5){? throw Error ("發(fā)生了錯誤")? }else{? return i? }? }? try {? console.log(rand())? } catch (error) {? console.log(error)? }? console.log(22)它按照以下步驟執(zhí)行:
五、變量解構(gòu)賦值
? 1.*什么是解構(gòu)賦值*
? ES6 允許按照一定模式,從數(shù)組和對象中提取值,對變量進行賦值,這被稱為解構(gòu)(Destructuring)。
包括:****數(shù)組、對象、函數(shù)參數(shù)****、字符串、數(shù)值和布爾值。null和undefined不行。
在實際開發(fā)時,真正使用比較多的是數(shù)組、對象和函數(shù)參數(shù)的解構(gòu)。
解構(gòu),通俗的講法,****就是批量定義變量****。本質(zhì)是定義變量的。
可以理解為變量的取出
- 數(shù)組的解構(gòu)賦值
上面代碼表示,可以從數(shù)組中提取值,按照對應(yīng)位置,對變量賦值。
本質(zhì)上,這種寫法屬于“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應(yīng)的值。
如果解構(gòu)失敗,變量的值等于undefined。
- 對象的解構(gòu)賦值
解構(gòu)不僅可以用于數(shù)組,還可以用于對象。對象的解構(gòu)與數(shù)組有一個重要的不同。數(shù)組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。如果解構(gòu)失敗,變量的值等于undefined。
<script> let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; foo // "aaa" bar // "bbb"let { baz } = { foo: 'aaa', bar: 'bbb' }; baz // undefined </script>六、箭頭函數(shù)
箭頭函數(shù) ES6 允許使用“箭頭”(=>)定義函數(shù)。箭頭函數(shù)實際還是函數(shù)
箭頭函數(shù)的寫法
在setInterval和setTimeout中傳入函數(shù)時,函數(shù)中的this會指向window對象。
七、函數(shù)默認值
在ES6之前,不能直接為函數(shù)的參數(shù)指定默認值,只能采取變通的方法。
<script> function log(x,y){y = y||'world';console.log(x,y); } log('hello'); //hello world// es6 寫法 function log(x ,y="world"){console.log(x,y); } log('hello'); //hello world </script>數(shù)組的擴展
經(jīng)典面試題:請列出常見的數(shù)組方法,不少于10個。
****push、pop****、shift、unshif、join、reverse、sort、****slice、splice****、concat、indexOf.
es5中新增數(shù)組方法:
在es5中,新增了如下幾個方法:
-
Array.isArray()
-
forEach()
-
*map()*
-
*filter()*
-
reduce
-
some()
-
every()
除了isArray方法之外,其他的方法都是用于對數(shù)組進行遍歷操作。
八、數(shù)組的靜態(tài)操作方法
(1)Array.isArray
? 作用:判斷某個數(shù)據(jù)是否是數(shù)組 返回布爾值
function fun(a,b){console.log( Array.isArray(arguments)); //false 偽數(shù)組} fun(2,3)(2)Array.from
Array.from方法用于將類數(shù)組對象轉(zhuǎn)為真正的數(shù)組(類數(shù)組對象比如arguments)
類數(shù)組對象特點 表現(xiàn)像數(shù)組 卻沒有數(shù)組該有的方法 比如push
(3)Array.of
作用:將一組值轉(zhuǎn)換為數(shù)組。
它的出現(xiàn),主要目的是彌補構(gòu)造器****Array()的不足****
const arr1 = new Array(3); //3xemptyconst arr2 = new Array(3,5); //3,5 const arr3 = new Array("3",'html'); //3,"html"console.log(arr1,arr2,arr3);
在使用Array構(gòu)造器的時候,根據(jù)參數(shù)類型的變化,得到的結(jié)果完全不一樣。
在es6中,就提出了Array.of,來替代new Array的用法。
const arr4 = Array.of(3); const arr5 = Array.of(3,5);const arr6 = Array.of("3","html");console.log(arr4,arr5,arr6);使用Array.of之后,表現(xiàn)就統(tǒng)一了,都是定義數(shù)組的元素。
九、數(shù)組常見操作方法
常用的數(shù)組的操作 map、filter、forEach、some、every、includs、find、findIndex 、reduce
(1)forEach
? 作用:用****于遍歷數(shù)組,對數(shù)組中的每一個元素進行某個操作****。沒有返回值,也不需要返回值。
? 格式:
? \ 數(shù)組.forEach(*******function********(value,index,arr){*
? *\ })*
其中,value就是數(shù)組元素
Index,就是元素對應(yīng)的索引
Arr就是表示當(dāng)前數(shù)組,這個不常用
foreach 相當(dāng)于for循環(huán) 對數(shù)據(jù)進行便利
var arr=[1,2,3,4,'html','css','js'];arr.forEach(function(el,index){console.log(el); //1,2,3,4,'html','css','js'console.log(index);//0,1,2,3,4,5,6,7}) //箭頭函數(shù)的寫法 arr.forEach(el=>console.log(el+1)); //結(jié)果: //2,3,4,5,'html1','css1','js1'var array1 = ['a', 'b', 'c']; array1.forEach(function(element) {console.log(element); }); //結(jié)果: // "a" // "b" // "c"(2)map
map() JavaScript 數(shù)組map()方法主要創(chuàng)建一個新的數(shù)組使用調(diào)用此數(shù)組中的每個元素上所提供的函數(shù)的結(jié)果。即對數(shù)組中的每一項運行給定函數(shù),返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。對數(shù)據(jù)進行操作 返回新的數(shù)據(jù)
格式:
數(shù)組.map(function(value,index,arr){
})
參數(shù)含義和forEach一致。
<script> var list = [1,2,3,4]; var newList = list.map(ele =>{return ele*2 }); console.log(list,newList) // [1,2,3,4] [2,4,6,8] </script>在使用map的時候,注意兩點:
-
在回調(diào)函數(shù)中,一定要使用return返回
-
map方法調(diào)用之后,會返回一個全新的數(shù)組,原來的數(shù)組不變。
(3) filter
作用:****就是用于進行過濾,篩選出符合條件的元素,組成一個新的數(shù)組返回****。
格式:
數(shù)組.filter(function(value,index,arr){})
基本上和map是差不多的。
filter 方法創(chuàng)建一個新的數(shù)組,新數(shù)組中的元素是通過檢查指定數(shù)組中符合條件的所有元素
<script>var list = [1,2,3,4]; var newList = list.filter(ele => ele > 2); console.log(list,newList) // [1,2,3,4] [3,4]</script>(4)find/findIndex
- find
數(shù)組實例的find方法,用于找出第一個符合條件的數(shù)組成員。它的參數(shù)是一個回調(diào)函數(shù),所有數(shù)組成員依次執(zhí)行該回調(diào)函數(shù),直到找出第一個返回值為true的成員,然后返回該成員。如果沒有符合條件的成員,則返回 undefined。
find方法的回調(diào)函數(shù)可以接受三個參數(shù),依次為當(dāng)前的值、當(dāng)前的位置和原數(shù)組。
- findIndex
數(shù)組實例的findIndex方法的用法與find方法非常類似,返回第一個符合條件的數(shù)組成員的下標(biāo),如果所有成員都不符合條件,則返回-1。
(5)every與some
every()與some()方法都是JS中數(shù)組的迭代方法。
every()是對數(shù)組中每一項運行給定函數(shù),如果該函數(shù)對每一項返回true,則返回true。
some()是對數(shù)組中每一項運行給定函數(shù),如果該函數(shù)對任一項返回true,則返回true。
<script> var arr = [ 1, 2, 3, 4, 5, 6 ]; console.log( arr.some( function( item, index, array ){ return item > 3; })); // true console.log( arr.every( function( item, index, array ){ return item > 3; })); // false </script>(6)includes
includes 方法用來判斷一個數(shù)組是否包含一個指定的值,如果是返回 true,否則false。
[1, 2, 3].includes(2); // true [1, 2, 3].includes(4); // false [1, 2, 3].includes(3, 3); // false [1, 2, 3].includes(3, -1); // true [1, 2, NaN].includes(NaN); // true(7)reduce
作用:將****前一項*和*后一項****的值進行運算,返回累積的結(jié)果
格式:數(shù)組.reduce(function(prev,next){…})
其中,prev表示前一項,next表示后一項。
運算規(guī)則:
默認情況下,會把數(shù)組的第一個元素作為prev的初始值。
每循環(huán)一次,把累積的結(jié)果賦給prev,next就變?yōu)橄乱粋€數(shù)組元素
var arr3 = [10,22,23,25,50];const total = arr3.reduce(function(pre,next){console.log(pre+"----"+next);return pre+next;})console.log(total);實際上,reduce方法還有第二個參數(shù),****如果傳遞了第二個參數(shù),就作為prev的初始值****。同時next就是數(shù)組的第一個元素。
<script>const total = arr3.reduce(function(pre,next){console.log(pre+"----"+next);return pre+next;},100)console.log(total);</script>小結(jié)一下:請列出js中的常用的數(shù)組方法。
*push、pop、shift、unshift、sort、slice、splice、reverse、join、concat*
*forEach、map、filter、reduce、some、every、find、findIndex、fill、*
*Array.isArray、Array.from、Array.of*
十、字符串?dāng)U展
(1)字符串模板
字符串拼接是開發(fā)時一個必不可少的環(huán)節(jié),也是很惡心的一個環(huán)節(jié),尤其是又臭又長的html字符串拼接。
為什么說html字符串拼接很惡心呢,主要有以下幾點:
es6的模板字符串解決了以上問題
- 拼接字符串
- 插入變量
補位,repeat
擴展運算符
擴展運算符(spread)是三個點(…)。它好比 rest 參數(shù)的逆運算,將一個數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列
(2)repeat
作用:按照指定此時重復(fù)指定的內(nèi)容
格式:****字符串.repeat(n)****
var str="你好" console.log(str.repeat(3)) //你好你好你好十一、對象的擴展
Object.assign方法用于對象的合并,將源對象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對象(target)。
Object.assign方法的第一個參數(shù)是目標(biāo)對象,后面的參數(shù)都是源對象。Object.assign有返回值 返回值是目標(biāo)對象(target)
淺拷貝
Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源對象某個屬性的值是對象,那么目標(biāo)對象拷貝得到的是這個對象的引用。
十二、Symbol
ES6 引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨一無二的值。它是 JavaScript 語言的第七種數(shù)據(jù)類型,前六種是:undefined、null、布爾值(Boolean)、字符串(String)、數(shù)值(Number)、對象(Object)。
ES5 的對象屬性名都是字符串,這容易造成屬性名的沖突。比如,你使用了一個他人提供的對象,但又想為這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現(xiàn)有方法產(chǎn)生沖突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的沖突。這就是 ES6 引入Symbol的原因。
- Symbol 的值都是唯一的 永不相等
- 標(biāo)識
Symbol函數(shù)接受一個可選參數(shù),可以添加一段文本描述即將創(chuàng)建的Symbol,這段屬描述不可用于屬性訪問,但是建議每次創(chuàng)建Symbol時都添加一段描述,便于閱讀代碼和調(diào)試Symbol程序。
- 獲取Symbol里面的描述信息 .description
- 作為屬性名的 Symbol
由于每一個 Symbol 值都是不相等的,這意味著 Symbol 值可以作為標(biāo)識符,用于對象的屬性名,就能保證不會出現(xiàn)同名的屬性。這對于一個對象由多個模塊構(gòu)成的情況非常有用,能防止某一個鍵被不小心改寫或覆蓋。
注意,Symbol 值作為對象屬性名時,不能用點運算符。- 賦值的第一種方式
- 賦值的第二種方式
十三、Set 和 Map 數(shù)據(jù)結(jié)構(gòu)
- Set
ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set。它類似于數(shù)組,但是成員的值都是唯一的,沒有重復(fù)的值。
Set 本身是一個構(gòu)造函數(shù),用來生成 Set 數(shù)據(jù)結(jié)構(gòu)。
上面代碼通過add方法向 Set 結(jié)構(gòu)加入成員,結(jié)果表明 Set 結(jié)構(gòu)不會添加重復(fù)的值。
- size屬性
Set.prototype.size:返回Set實例的成員總數(shù)。array.length - size 方法
Set.prototype.add(value):添加某個值,返回 Set 結(jié)構(gòu)本身。
Set.prototype.delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。 // 刪除成功 返回true 否則 false
Set.prototype.has(value):返回一個布爾值,表示該值是否為Set的成員。
Set.prototype.clear():清除 清空set數(shù)據(jù)結(jié)構(gòu)
- Set實現(xiàn)數(shù)組去重
- Map
ES6 提供了 Map 數(shù)據(jù)結(jié)構(gòu)。它類似于對象,也是鍵值對的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對象)都可以當(dāng)作鍵。也就是說,Object 結(jié)構(gòu)提供了“字符串—值”的對應(yīng)(對象,數(shù)字,函數(shù)都可以作為作為鍵值),Map 結(jié)構(gòu)提供了“值—值”的對應(yīng),是一種更完善的 Hash 結(jié)構(gòu)實現(xiàn)。
<script> const m = new Map(); const o = {p: 'Hello World'};m.set(o, 'content') m.get(o) // "content"m.has(o) // true m.delete(o) // true m.has(o) // false </script>Map實例的屬性和操作方法
- size 屬性
size屬性返回 Map 結(jié)構(gòu)的成員總數(shù)。 - Map.prototype.set(key, value)
set方法設(shè)置鍵名key對應(yīng)的鍵值為value,然后返回整個 Map 結(jié)構(gòu)。如果key已經(jīng)有值,則鍵值會被更新,否則就新生成該鍵。
- Map.prototype.get(key)
get方法讀取key對應(yīng)的鍵值,如果找不到key,返回undefined。
- Map.prototype.has(key)
has方法返回一個布爾值,表示某個鍵是否在當(dāng)前 Map 對象之中。
- Map.prototype.delete(key)
delete方法刪除某個鍵,返回true。如果刪除失敗,返回false。
- Map.prototype.clear()
clear方法清除所有成員,沒有返回值。
十四、Proxy
Proxy 可以理解成,在目標(biāo)對象之前架設(shè)一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這里表示由它來“代理”某些操作,可以譯為“代理器”。
ES6 原生提供 Proxy 構(gòu)造函數(shù),用來生成 Proxy 實例。
var proxy = new Proxy(target, handler); // 例 var obj = {name:"" } var proxy = new Proxy(obj, {get: function(target, propKey) {return 35;} });proxy.time // 35 proxy.name // 35 proxy.title // 35上面代碼中,作為構(gòu)造函數(shù),Proxy接受兩個參數(shù)。第一個參數(shù)是所要代理的目標(biāo)對象,即如果沒有Proxy的介入,操作原來要訪問的就是這個對象;第二個參數(shù)是一個配置對象,對于每一個被代理的操作,需要提供一個對應(yīng)的處理函數(shù),該函數(shù)將攔截對應(yīng)的操作。比如,上面代碼中,配置對象有一個get方法,用來攔截對目標(biāo)對象屬性的訪問請求。get方法的兩個參數(shù)分別是目標(biāo)對象和所要訪問的屬性。可以看到,由于攔截函數(shù)總是返回35,所以訪問任何屬性都得到35。
注意**,要使得Proxy起作用,必須針對Proxy實例(上例是proxy對象)進行操作,而不是針對目標(biāo)對象(上例是空對象)進行操作。**
如果handler沒有設(shè)置任何攔截,那就等同于直接通向原對象。
Proxy常見操作
-
get(target, propKey, receiver):攔截對象屬性的讀取,比如proxy.foo和proxy['foo']
get方法用于攔截某個屬性的讀取操作,可以接受三個參數(shù),依次為目標(biāo)對象、屬性名和 proxy 實例本身(嚴(yán)格地說,是操作行為所針對的對象),其中最后一個參數(shù)可選。
// 如果訪問目標(biāo)對象不存在的屬性,會拋出一個錯誤。如果沒有這個攔截函數(shù),訪問不存在的屬性,只會返回undefined。 var person = {name: "張三" };var proxy = new Proxy(person, {get: function(target, propKey) {if (propKey in target) {return target[propKey];} else {throw new ReferenceError("Prop name " + propKey + " does not exist.");}} });proxy.name // "張三" proxy.age // 拋出一個錯誤 -
set(target, propKey, value, receiver):攔截對象屬性的設(shè)置,比如proxy.foo = v或proxy['foo'] = v,返回一個布爾值。
set`方法用來攔截某個屬性的賦值操作,可以接受四個參數(shù),依次為目標(biāo)對象、屬性名、屬性值和 Proxy 實例本身,其中最后一個參數(shù)可選。
var person = {? name: "張三",? age:20};var proxy = new Proxy(person, {? set(target , key , val){? if(key == "age"){? if(val>150){? throw new Error("年齡不符合要求")? }else{? target[key] = val? }? }? }});proxy.age = 200;proxy實現(xiàn)雙向綁定
<div id="app"><h2>input框的值為:<span id="val"></span></h2><input type="text" id="ipt" /></div><script>var ipt = document.getElementById("ipt");var span = document.getElementById("val");var obj = {val: ipt.value};var proxy = new Proxy(obj, {set(target, key, val) {span.innerText = val;ipt.value = val;},get(target, propKey) {span.innerText = target[propKey];return target[propKey];}});document.getElementById("ipt").oninput = function() {proxy.val = document.getElementById("ipt").value;};十五、class
引用類型的數(shù)據(jù)在使用typeof判斷類型的時候返回的都是object 如果向單獨的判斷引用數(shù)據(jù)的類型可以使用instanceof來進行判斷(某個對象是不是另一個對象的實例)
constructor 屬性返回對創(chuàng)建此對象的數(shù)組函數(shù)的引用,指向生成這個實例的函數(shù)。。
constructor 返回的是構(gòu)造函數(shù) 而instanceof返回的是true或false- es6中的類和對象
-
對象
對象的定義是一組無序的相關(guān)屬性和方法的集合,所有的事物都是對象 -
class類
在ES6中,class (類)作為對象的模板被引入,可以通過 class 關(guān)鍵字定義類。class 的本質(zhì)是 function (class Person() ; typeof Person == Function)。
它可以看作一個語法糖,讓對象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法。 -
對象和類的區(qū)別
類抽象了對象的公共部分(封裝了公共的屬性和方法),他泛指某一大類(class),
對象特指某一個,通過類實例化一個具體的對象
他倆之間的關(guān)系可以理解為設(shè)計圖(類)和實物(對象)的關(guān)系 -
類的使用
上面是es6 class的寫法 下面是es5構(gòu)造函數(shù)的寫法
-
- 類的注意事項及特點
- 構(gòu)造函數(shù)為了與普通函數(shù)更好的區(qū)分 一般構(gòu)造函數(shù)的首字母都是大寫
- 類里面的constructor(構(gòu)造函數(shù))函數(shù) 可以接收實例傳遞過來的參數(shù) 同時返回實例對象
- constructor函數(shù) 只要new生成實例時 就會自動調(diào)用這個函數(shù) 即使不寫這個函數(shù) 也會自動生成
- 生成實例的時候 new關(guān)鍵字不能省略
- 類里面的函數(shù) 不能加function
- 類里面的多個函數(shù)之間不需要加,
- 類里面的所有方法都是定義在原型上面
- 類的繼承
利用原型讓一個引用類型繼承另一個引用類型的屬性和方法,即讓原型對象等于另一個類型的實例(即要繼承的對象的實例)
Class 可以通過extends關(guān)鍵字實現(xiàn)繼承
十六、Promise
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大。它由社區(qū)最早提出和實現(xiàn),ES6 將其寫進了語言標(biāo)準(zhǔn),統(tǒng)一了用法,原生提供了Promise對象。
所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API,各種異步操作都可以用同樣的方法進行處理。
<script>var p = new Promise(function(resolve , reject){setTimeout(() => {var num = Math.random()*10;if(num>6){resolve(num)}else{reject("小于6")}}, 1000);})p.then(function(val){console.log(val)}).catch(function(val){console.log(val)}) </script>Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject。它們是兩個函數(shù),由 JavaScript 引擎提供,不用自己部署。
resolve函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α?#xff08;即從 pending 變?yōu)?resolved),在異步操作成功時調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;reject函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 ?#xff08;即從 pending 變?yōu)?rejected),在異步操作失敗時調(diào)用,并將異步操作報出的錯誤,作為參數(shù)傳遞出去。
Promise實例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。
Promise最大的好處是在異步執(zhí)行的流程中,把執(zhí)行代碼和處理結(jié)果的代碼清晰地分離了 解決了層層嵌套
<script>var status = 1,isLogin=false;var login = (resolve , reject)=>{setTimeout(()=>{if(status == 1){isLogin = trueresolve({code : 1,token:"ad31nu891nv",msg:"登陸成功!"})}else{isLogin = falsereject("失敗")}},2000)};var getInfo = (resolve , reject)=>{setTimeout(()=>{if(isLogin){resolve("獲取用戶信息成功!")}else{reject("獲取失敗")}},1000)};new Promise(login).then(res =>{console.log(res);return new Promise(getInfo);}).then(res =>{console.log(res);}) </script>十七、async await
ES2017(es7) 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。
- async await
async函數(shù)返回一個 Promise 對象,可以使用then方法添加回調(diào)函數(shù)。當(dāng)函數(shù)執(zhí)行的時候,一旦遇到await就會先返回,等到異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語句。
async await 最大的好處是讓前端有了能力 以同步的方式寫異步的代碼- async
async函數(shù)返回一個 Promise 對象 語義上理解 當(dāng)函數(shù)前面加上async表示函數(shù)內(nèi)部有異步操作
- async
- await
await 關(guān)鍵字要在 async 關(guān)鍵字函數(shù)的內(nèi)部,await 寫在外面會報錯。
await右側(cè)如果是函數(shù),那么函數(shù)的return值就是「表達式的結(jié)果」
await右側(cè)如果是一個 ‘hello’ 或者什么值,那表達式的結(jié)果就是 ‘hello’
await關(guān)鍵字會阻塞后面代碼的運行(通過阻塞特點 控制ajax 或者settimeout的執(zhí)行順序)
async await 重構(gòu)ajax
function getUser(){return $.ajax({url:'http://bufantec.com/api/test/user/list?start=10'})}function getuserInfo(val){return $.ajax({url:`http://bufantec.com/api/test/user/detail?id=${val}`})} async function getResult(){const result1 = await getUser();const result2 = await getuserInfo(result1.data.list[1].userId);console.log(result2);} getResult() - es6中的類和對象
總結(jié)