【前端】ECMAScript6從入門(mén)到進(jìn)階
1.ES6簡(jiǎn)介及環(huán)境搭建
1.1.ECMAScript 6簡(jiǎn)介
(1)ECMAScript 6是什么
ECMAScript 6.0(以下簡(jiǎn)稱(chēng) ES6)是 JavaScript 語(yǔ)言的下一代標(biāo)準(zhǔn),已經(jīng)在2015年6月正式發(fā)布了。它的目標(biāo),是使得 JavaScript 語(yǔ)言可以用來(lái)編寫(xiě)復(fù)雜的大型應(yīng)用程序,成為企業(yè)級(jí)開(kāi)發(fā)語(yǔ)言。
(2)ECMAScript 和 JavaScript 的關(guān)系
ECMAScript是JavaScript的標(biāo)準(zhǔn),JavaScript是ECMAScript的實(shí)現(xiàn)。換句話(huà)說(shuō),如果說(shuō)JavaScript是一門(mén)語(yǔ)言的話(huà),那么ECMAScript就是這門(mén)語(yǔ)言遵循的語(yǔ)法書(shū)。
(3)ES6 與 ECMAScript 2015 的關(guān)系
2011年的時(shí)候,ECMAScript 5.1版本發(fā)布,ECMA組織就開(kāi)始準(zhǔn)備6.0版本了。但因?yàn)檫@個(gè)版本引入的語(yǔ)法功能太多了,所以不可能通過(guò)一個(gè)版本就將所有功能涵蓋。所以,標(biāo)準(zhǔn)委員會(huì)決定,標(biāo)準(zhǔn)在每年的6月份正式發(fā)布一次,作為當(dāng)年的正式版本。接下來(lái)的時(shí)間,就在這個(gè)版本的基礎(chǔ)上做改動(dòng),直到下一年的6月份,草案就自然變成了新一年的版本。這樣一來(lái),就不需要以前的版本號(hào)了,只要用年份標(biāo)記就可以了。
就這樣ES6的第一個(gè)版本就在2015.6正式發(fā)布了,正式名稱(chēng)就是《ECMAScript 2015標(biāo)準(zhǔn)》(簡(jiǎn)稱(chēng)ES2015)。
1.2.babel工具搭建ES6環(huán)境
采用 ECMAScript 2015+ 語(yǔ)法編寫(xiě)的代碼轉(zhuǎn)換為向后兼容的 JavaScript 語(yǔ)法,以便能夠運(yùn)行在當(dāng)前和舊版本的瀏覽器或其他環(huán)境中。
- 首先確保環(huán)境中有node
node安裝:http://nodejs.cn/download/
- 初始化工程項(xiàng)目
// 使用默認(rèn)配置初始化項(xiàng)目
npm init -y
- 安裝對(duì)應(yīng)的依賴(lài)包
// 本地安裝babel-cli及對(duì)應(yīng)的轉(zhuǎn)化規(guī)則
npm install --save-dev babel-cli babel-preset-es2015
// 阿里巴巴定制的鏡像源
npm install -g cnpm --registry=https://registry.npm.taobao.org
-
創(chuàng)建項(xiàng)目目錄
-
src目錄用于存放編寫(xiě)的es6代碼
-
dist目錄用于存放由es6轉(zhuǎn)化后的代碼
-
-
配置babel
新建.babelrc
文件
// 配置用于轉(zhuǎn)化當(dāng)前代碼的規(guī)則集
{
"presets": ["es2015"]
}
babel的基本用法
// -o 參數(shù)指定輸出文件
node_modules/.bin/babel src/index.js -o dist/index.js
// -d 參數(shù)指定輸出目錄
node_modules/.bin/babel src -d dist
配置package.json文件實(shí)時(shí)編譯
// 配置啟動(dòng)腳本的命令
"scripts": {
// 監(jiān)聽(tīng)index.js文件,一發(fā)生變化就執(zhí)行babel轉(zhuǎn)譯的命令
"dev": "babel src -w -d dist",
}
2.新的聲明及數(shù)據(jù)賦值方式
2.1.變量聲明let與const
作用域就是變量的有效范圍,之前只有全局作用域和函數(shù)作用域,現(xiàn)在新增塊級(jí)作用域。es6中新增let和const兩種變量聲明方式。
(1)let和const的相同點(diǎn)
- 只在聲明的代碼塊內(nèi)有效
if (true) {
var a = "a";
}
console.log(a);
// let聲明變量,const同理
if (true) {
let b = "b";
}
console.log(b);
- 在同一作用域內(nèi)不允許重復(fù)聲明
- 沒(méi)有變量提升,在聲明變量前,不能使用該變量
console.log(a);
var a = 'a';
console.log(b);
let b = '1';
用var聲明的變量會(huì)存在變量提升的問(wèn)題,如果用let或者const就會(huì)消除變量提升問(wèn)題,在遇到未定義的變量直接拋錯(cuò)。
(2)let和const的區(qū)別
- const用來(lái)聲明一個(gè)只讀的變量
const x = 10;
x = 13;
console.log(x);
注意:const聲明的變量同時(shí)必須立即賦值,如聲明的是簡(jiǎn)單類(lèi)型的數(shù)據(jù),變量的值不可改變。
2.2.ES6新數(shù)據(jù)類(lèi)型Symbol
在ES6之前JavaScript的原始數(shù)據(jù)類(lèi)型有Number、String、Boolean、Null、Undefined。ES6中增加新的Symbol獨(dú)一無(wú)二的類(lèi)型。
對(duì)象的屬性名容易產(chǎn)生命名沖突,為保證鍵名的唯一性,故es6引入Symbol這種新的原始類(lèi)型數(shù)據(jù),確保創(chuàng)建的每個(gè)變量都是獨(dú)一無(wú)二的。
- Symbol類(lèi)型的數(shù)據(jù)是類(lèi)似字符串的數(shù)據(jù)類(lèi)型。
- 由于Symbol函數(shù)返回的值是原始類(lèi)型的數(shù)據(jù),不是對(duì)象,故Symbol函數(shù)前不能使用new命令,否則會(huì)報(bào)錯(cuò)。
let s = Symbol();
console.log(typeof s);
let s1 = Symbol();
let s2 = Symbol();
console.log(s1===s2);
let l1 = Symbol('lixiang');
let l2 = Symbol('lixiang');
console.log(l1===l2);
定義對(duì)象的唯一屬性名
// 在對(duì)象里用Symbol作為屬性名的三種寫(xiě)法
let s = Symbol();
// 第一種方式: 借助數(shù)組讀取s變量,此時(shí)不能用點(diǎn)運(yùn)算符,點(diǎn)運(yùn)算符默認(rèn)后面的參數(shù)是字符串
let a = {};
a[s] = 'lixiang'
// 第二種方式: 構(gòu)造時(shí)聲明
let a = {
[s]: 'lixiang'
}
// 第三種 Object.defineProperty
let a = {};
Object.defineProperty(a, s, { value: 'lixiang' });
定義常量
const s = Symbol("李祥");
2.3.解構(gòu)賦值詳解
(1)什么是解構(gòu)賦值
解構(gòu)賦值可以理解為賦值操作的語(yǔ)法糖,它是針對(duì)數(shù)組或者對(duì)象進(jìn)行模式匹配,然后對(duì)其中的變量進(jìn)行賦值。代碼書(shū)寫(xiě)上言簡(jiǎn)意賅,語(yǔ)義明確,也方便了對(duì)象數(shù)組的讀取操作。
ES6中只要某種數(shù)據(jù)可以循環(huán)迭代,都可以進(jìn)行解構(gòu)賦值。
(2)數(shù)組解構(gòu)
// 變量多時(shí),對(duì)應(yīng)不上的變成undefined
let [a, b, c] = [1, 2];
console.log(a, b, c);
// 變量默認(rèn)值,聲明變量時(shí)將c默認(rèn)成6
let [a, b, c = 6] = [1, 2];
console.log(a, b, c);
// 分割數(shù)組,將1賦值給a,2,3成一個(gè)新數(shù)組
let [a, ...other] = [1, 2, 3];
console.log(a, other);
// 空內(nèi)容,將a賦值為1,b賦值為3
let [a,,b] = [1, 2, 3];
console.log(a, b);
(3)對(duì)象解構(gòu)
//1賦值為a,2賦值為b
let { a, b } = { a: 1, b: 2 };
console.log(a, b);
//重命名
let { a: aa, b: bb } = { a: 1, b: 2 };
console.log(aa, bb);
(4)讀取接口返回的數(shù)據(jù)
function fun() {
return {
name: "張三",
hobby: [
{
title: "籃球",
},
{
title: "唱",
},
{
title: "RAP",
},
{
title: "跳",
},
],
};
}
let {
name,
hobby: [{ title }],
} = fun();
console.log(name, title);
3.ES6新增的數(shù)據(jù)操作方法
3.1.ES6提供的新的字符串方法
(1)新增的API
方法 | 描述 |
---|---|
includes(string, index) | 判斷字符串中是否包含指定字符串,返回值是布爾值 |
startsWith(string, index) | 判斷字符串的開(kāi)頭是否包含指定字符串,返回值是布爾值 |
endsWith(string, index) | 判斷字符串的尾部是否包含指定字符串,返回值是布爾值 |
repeat(n) | repeat() 方法返回一個(gè)新字符串,表示將原字符串重復(fù)n 次。 |
padStart(length, str) | 字符串補(bǔ)齊,用于頭部補(bǔ)全 |
padEnd(length, str) | 字符串補(bǔ)齊,用于尾部補(bǔ)全 |
//判斷str是否包含an
let str = 'lixiang';
console.log(str.includes('an'));
//從下標(biāo)為5的字符開(kāi)始判斷是否含an
console.log(str.includes('an',5));
//判斷str是否以l開(kāi)頭
let str = 'lixiang';
console.log(str.startsWith('l'));
//從下標(biāo)為3的字符開(kāi)始判斷是否以l開(kāi)頭
console.log(str.startsWith('l',3));
//判斷str是否以g結(jié)尾
let str = 'lixiang';
console.log(str.endsWith('g'));
//從下標(biāo)為3的字符開(kāi)始判斷是否以g結(jié)尾
console.log(str.startsWith('g',3));
//入?yún)?shù)字為2,重復(fù)兩次
let str = 'lixiang';
console.log(str.repeat(2));
//在lixiang前面補(bǔ)a,補(bǔ)夠10位
let str = 'lixiang';
console.log(str.padStart(10, 'a'));
//在lixiang后面補(bǔ)a,補(bǔ)夠10位
let str = 'lixiang';
console.log(str.padEnd(10, 'a'));
(2)模板字符串
在ES5的時(shí)候拼接字符串我們往往這樣寫(xiě)。
const name = '李祥';
const age = 18;
const hobbies = '寫(xiě)代碼';
const str = '我叫'+name+',今年'+age+'歲,'+'喜歡'+hobbies+'。'
在ES6中新引入的模版字符串,寫(xiě)法如下。
const str = `我叫${name},今年${age}歲,喜歡${hobbies}。`
console.log(str);
(3)使用模板字符串的注意事項(xiàng)
- 使用模板字符串表示多行字符串時(shí),所有的空格和縮進(jìn)都會(huì)被保留在輸出之中。
- 模板字符串中引入變量,要用 ${變量名} 這樣的形式引入才可以。
- 模板字符串中的${…} 大括號(hào)內(nèi)部可以放入任意的 JavaScript 表達(dá)式,可以進(jìn)行運(yùn)算、可以引用對(duì)象屬性、可以調(diào)用函數(shù)、可以甚至還能嵌套,甚至還能調(diào)用自己本身。
3.2.ES6擴(kuò)展運(yùn)算符的使用
(1)深拷貝一維數(shù)組
const list = [1, 2, 3, 4, 5];
const listCopy = [...list];
console.log(listCopy);
(2)分割數(shù)組
const list = [1, 2, 3, 4, 5];
const [, ...list1] = list;
console.log(list1);
(3)將數(shù)組轉(zhuǎn)化成參數(shù)傳遞給函數(shù)
const list = [1, 2];
function fun(a, b) {
console.log(a + b);
}
fun(...list);
3.3.ES6數(shù)組的擴(kuò)展方法
(1)fill:替換數(shù)組中的元素,會(huì)改變?cè)瓟?shù)組。想要不改變?cè)瓟?shù)組的值,可以采用深拷貝。
const list = [1, 2, 3, 4, 5];
//全部替換成6
const list1 = [...list].fill(6);
//下標(biāo)從1開(kāi)始到下表為4之間左閉右開(kāi),全部替換成6
const list2 = [...list].fill(6, 1, 4);
console.log(list);
console.log(list1);
console.log(list2);
(2)find:查詢(xún)數(shù)組中符合條件的元素。
const list = [
{ name: "李祥", age: 15 },
{ name: "張三", age: 10 },
{ name: "李四", age: 19 },
{ name: "王武", age: 20 },
];
const result = list.find(function (item) {
return item.name === "李祥";
});
console.log(result);
(3)findIndex:查詢(xún)數(shù)組中符合條件的元素的索引。
const result = list.findIndex(function (item) {
return item.name === "李祥";
});
console.log(result);
(4)flat:用于合并數(shù)組。
const list = [1, 2, 3, [4, 5, 6, [ 7, 8]]];
const list2 = list.flat(2);
console.log(list2);
(5)filter:過(guò)濾出符合條件的元素,與find不同的是filter返回一個(gè)數(shù)組。
const result = list.filter(function (item) {
return item.name === "李祥";
});
console.log(result);
3.4.ES6數(shù)組中map方法
map用于將一個(gè)類(lèi)型的數(shù)字轉(zhuǎn)換成另外一個(gè)類(lèi)型。
const list = [
{ name: "李祥", age: 15 },
{ name: "張三", age: 10 },
{ name: "李四", age: 19 },
{ name: "王武", age: 20 },
];
//遍歷集合中每一項(xiàng),創(chuàng)建obj對(duì)象,將原對(duì)象屬性復(fù)制到新的obj中
//然后給obj增加一個(gè)屬性state
const mapList = list.map(function (i) {
let obj = {};
//對(duì)象拷貝
Object.assign(obj, i);
obj.sex = 0;
return obj;
});
console.log(mapList);
3.5.ES6對(duì)象的新特性
創(chuàng)建對(duì)象
const a = {
name: 'lixiang',
age: 21,
address: {
city: 'BeiJing',
town: 'ChangYang'
},
};
(1)深拷貝簡(jiǎn)單對(duì)象
const b = { ...a };
console.log(b);
(2)給對(duì)象設(shè)置默認(rèn)值
const b = { ...a, name: 'zhangsan' };
console.log(b);
(3)合并對(duì)象
const b = { sex:'0' };
const c = {...a,...b}
console.log(c);
(4)屬性初始化、方法的簡(jiǎn)寫(xiě)
(5)Object新增的方法
- Object.is:判斷兩個(gè)對(duì)象是否相等
let res = Object.is({name:'lx'}, {name:'lx'});
console.log(res);
let res1 = Object.is(NaN, NaN);
console.log(res1);
- Object.assign:對(duì)象復(fù)制
let a = { name: 'lx', age: 24 };
let b = {};
let c = Object.assign(b, a);
console.log(c);
- Object.keys:獲取對(duì)象所有的key
let a = { name: 'lx', age: 24 };
const arr = Object.keys(a);
console.log(arr);
- Object.values:獲取對(duì)象所有的value
let a = { name: 'lx', age: 24 };
const arr = Object.values(a);
console.log(arr);
- Object.entries:獲取key和value
let a = { name: 'lx', age: 24 };
const arr = Object.entries(a);
console.log(arr);
3.6.ES6新增Map與WeakMap
JavaScript中的對(duì)象,實(shí)質(zhì)就是鍵值對(duì)的集合,但是在對(duì)象里卻只能用字符串作為鍵名。在一些特殊的場(chǎng)景里就滿(mǎn)足不了我們的需求了,正因?yàn)榇?,Map這一數(shù)據(jù)提出了,它是JavaScript中的一種更完善Hash結(jié)構(gòu)。
Map對(duì)象:用于保存鍵值對(duì),任何值(對(duì)象或者原始值)都可以作為一個(gè)鍵名或一個(gè)值。
- 屬性及方法
屬性/方法 | 作用 | 例子 |
---|---|---|
size | 返回鍵值對(duì)的數(shù)量 | m.size |
clear() | 清除所有鍵值對(duì) | m.clear() |
has(key) | 判斷鍵值對(duì)中是否有指定的鍵名,返回值是布爾值 | m.has(key) |
get(key) | 獲取指定鍵名的鍵值,如不存在則返回undefined | m.get(key) |
set(key, value) | 添加鍵值對(duì),如鍵名已存在,則更新鍵值對(duì) | m.set(key, value) |
delete(key) | 刪除指定鍵名的鍵值對(duì) | m.delete(key) |
(1)創(chuàng)建一個(gè)Map
//創(chuàng)建一個(gè)空map
let map = new Map();
//創(chuàng)建一個(gè)帶有默認(rèn)值的map
let mapDef = new Map([
['name','lx'],
['age',12]
]);
console.log(map);
console.log(mapDef);
(2)API演示
//創(chuàng)建一個(gè)空map
let map = new Map();
//map中增加一個(gè)元素
map.set('name','lx');
map.set('age',20);
console.log(map);
//map中修改一個(gè)元素
//map中set方法如果有key則覆蓋,沒(méi)有則新增
map.set('name','zs');
console.log(map);
//返回鍵值對(duì)的數(shù)量
console.log(map.size);
//判斷是否有某個(gè)key
console.log(map.has('name'));
//獲取某個(gè)key的value
console.log(map.get('name'));
//刪除某個(gè)key
map.delete('name');
console.log(map);
//清空
map.clear();
console.log(map);
(3)遍歷器生成函數(shù)
const keys = map.keys();
const values = map.values();
const entries = map.entries();
console.log(Array.from(keys));
console.log(Array.from(values));
console.log(Array.from(entries));
WeakMap:只接受對(duì)象作為鍵名,而且無(wú)法遍歷
const weakMap = new WeakMap([[{ name: 'lx' ,age: 21},{id:1,hobby:'唱、跳、rap、籃球'}]]);
console.log(weakMap);
3.7.ES6新增Set與WeakSet
Set是ES6給開(kāi)發(fā)者提供的一種類(lèi)似數(shù)組的數(shù)據(jù)結(jié)構(gòu),可以理解為值的集合。它和數(shù)組的最大的區(qū)別就在于: 它的值不會(huì)有重復(fù)項(xiàng)。
Set保證成員值唯一,用于集合去重。
- 屬性及方法
屬性/方法 | 作用 | 例子 |
---|---|---|
add | 新增元素 | s.add(key) |
size | 返回成員個(gè)數(shù) | s.size |
clear() | 清除所有成員 | s.clear() |
has(value) | 判斷鍵值對(duì)中是否有指定的值,返回值是布爾值 | s.has(key) |
delete(value) | 刪除指定值 | s.delete(key) |
(1)創(chuàng)建一個(gè)Set
const a = { name: 'lx' };
const set = new Set([a]);
console.log(set);
const list = new Set([1, 2, 3, 4]);
console.log(list);
(2)API演示
const set = new Set([1, 2, 3, 4]);
console.log(set);
//獲取set長(zhǎng)度
console.log(set.size);
//判斷是否存在2元素
console.log(set.has(2));
//刪除2元素
set.delete(2);
console.log(set.has(2));
WeakSet:數(shù)組成員必須是對(duì)象
- WeakSet結(jié)構(gòu)也提供了add( ) 方法,delete( ) 方法,has( )方法給開(kāi)發(fā)者使用,作用與用法跟Set結(jié)構(gòu)完全一致。
- WeakSet 結(jié)構(gòu)不可遍歷。因?yàn)樗某蓡T都是對(duì)象的弱引用,隨時(shí)被回收機(jī)制回收,成員消失。所以WeakSet 結(jié)構(gòu)不會(huì)有keys( ),values( ),entries( ),forEach( )等方法和size屬性。
3.8.Array與Set的轉(zhuǎn)換
// 數(shù)組轉(zhuǎn)set
const list = [1, 2, 3];
const set = new Set(list);
console.log(set);
// set轉(zhuǎn)數(shù)組
const arr = Array.from(set);
console.log(arr);
3.9.Object與Map的轉(zhuǎn)換
// 對(duì)象轉(zhuǎn)map
const obj = { nane: 'lx', age:24 };
const map = new Map(Object.entries(obj));
console.log(map);
// map轉(zhuǎn)對(duì)象
const obj1 = Object.fromEntries(map);
console.log(obj1);
4.ES6新增高階知識(shí)點(diǎn)
4.1.ES6中新增代理Proxy
(1)Proxy簡(jiǎn)介
正如Proxy的英譯"代理"所示,Proxy是ES6為了操作對(duì)象引入的API。它不直接作用在對(duì)象上,而是作為一種媒介,如果需要操作對(duì)象的話(huà),需要經(jīng)過(guò)這個(gè)媒介的同意。
(2)使用方式
/* @params
** target: 用Proxy包裝的目標(biāo)對(duì)象
** handler: 一個(gè)對(duì)象,對(duì)代理對(duì)象進(jìn)行攔截操作的函數(shù),如set、get
*/
let p = new Proxy(target, handler)
(3)案例實(shí)戰(zhàn)
const house = {
name: '三室一廳-次臥',
price: 1000,
phone: '18823139921',
id: '20230131',
state: '**',
};
const handle = {
get: function (obj, key) {
switch (key) {
case 'price':
return obj[key] + 500;
case 'phone':
return obj[key].substring(0, 3) + '****' + obj[key].substring(7);
default:
return obj[key];
}
},
set: function (obj, key, value) {
if (key === 'state') {
obj[key] = value;
}
},
};
const houseproxy = new Proxy(house, handle);
console.log(houseproxy.id);
console.log(houseproxy.phone);
console.log(houseproxy.price);
houseproxy.state='****';
console.log(houseproxy.state);
4.2.ES6中新增反射Refect
(1)Reflect簡(jiǎn)介
與Proxy相同,ES6引入Reflect也是用來(lái)操作對(duì)象的,它將對(duì)象里一些明顯屬于語(yǔ)言?xún)?nèi)部的方法移植到Reflect對(duì)象上,它對(duì)某些方法的返回結(jié)果進(jìn)行了修改,使其更合理,更具語(yǔ)義化,并且使用函數(shù)的方式實(shí)現(xiàn)了Object的命令式操作。
- 屬性及方法
屬性/方法 | 作用 |
---|---|
Reflect.apply(target, thisArg, args) | 對(duì)一個(gè)函數(shù)進(jìn)行調(diào)用操作,同時(shí)可以傳入一個(gè)數(shù)組作為調(diào)用參數(shù)。 |
Reflect.construct(target, args) | 對(duì)構(gòu)造函數(shù)進(jìn)行 new 操作,相當(dāng)于執(zhí)行 new target(…args)。 |
Reflect.get(target,name, receiver) | 獲取對(duì)象身上某個(gè)屬性的值,類(lèi)似于 target[name]。如果沒(méi)有該屬性,則返回undefined。 |
Reflect.set(target, name,value, receiver) | Reflect.defineProperty方法基本等同于Object.defineProperty,直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,不同的是,Object.defineProperty返回此對(duì)象。而Reflect.defineProperty會(huì)返回布爾值 |
Reflect.has(target,name) | 判斷一個(gè)對(duì)象是否存在某個(gè)屬性,和 in 運(yùn)算符 的功能完全相同。 |
Reflect.ownKeys(target) | 返回一個(gè)包含所有自身屬性(不包含繼承屬性)的數(shù)組。(類(lèi)似于 Object.keys(), 但不會(huì)受enumerable影響, Object.keys返回所有可枚舉屬性的字符串?dāng)?shù)組). |
Reflect.isExtensible(target) | 判斷一個(gè)對(duì)象是否是可擴(kuò)展的(是否可以在它上面添加新的屬性),類(lèi)似于 Object.isExtensible()。返回表示給定對(duì)象是否可擴(kuò)展的一個(gè)Boolean 。(Object.seal 或 Object.freeze 方法都可以標(biāo)記一個(gè)對(duì)象為不可擴(kuò)展。) |
Reflect.preventExtensions(target) | 讓一個(gè)對(duì)象變的不可擴(kuò)展,也就是永遠(yuǎn)不能再添加新的屬性。 |
4.3.Proxy實(shí)現(xiàn)數(shù)據(jù)雙向綁定
(1)需求
實(shí)現(xiàn)一個(gè)雙向的數(shù)據(jù)綁定。
(2)實(shí)現(xiàn)
- 編寫(xiě)html代碼
<body>
請(qǐng)輸入內(nèi)容:<input type="text" id = "input"/><br/>
實(shí)時(shí)內(nèi)容展示:<span id = "span"></span>
<script src="./js/index.js"></script>
</body>
- 編寫(xiě)js代碼
// 獲取dom節(jié)點(diǎn)
const input = document.getElementById("input");
const span = document.getElementById("span");
//定義雙向綁定的對(duì)象
let obj = {};
//定義代理對(duì)象的handle方法
const handle = {
get: function (target, key) {
return target[key];
},
set: function (target, key, value) {
if (key === "text" && value) {
span.innerHTML = value;
return (target[key] = value);
}
},
};
//創(chuàng)建代理對(duì)象
const proxy = new Proxy(obj, handle);
//創(chuàng)建鍵盤(pán)的監(jiān)聽(tīng)事件
input.addEventListener("keyup", function (e) {
proxy.text = e.target.value;
console.log(proxy.text);
});
5.函數(shù)的擴(kuò)展、類(lèi)及模塊化
5.1.函數(shù)參數(shù)的擴(kuò)展
(1)函數(shù)參數(shù)可設(shè)置默認(rèn)值
//求和方法,當(dāng)a和b都不傳值時(shí),默認(rèn)都為1
function sum(a = 1, b = 1) {
return a + b;
}
console.log(sum());
console.log(sum(3));
console.log(sum(3,5));
(2)rest參數(shù),可變參數(shù)
//求和方法,可變參數(shù)
function sum(...rest) {
let num = 0;
rest.forEach((e)=>{
num+=e;
})
return num;
}
console.log(sum(...[1,2]));
console.log(sum(...[1,2,4]));
5.2.ES6新增箭頭函數(shù)
(1)箭頭函數(shù)簡(jiǎn)介
ES6中允許使用=>來(lái)定義函數(shù)。箭頭函數(shù)相當(dāng)于[匿名函數(shù),并簡(jiǎn)化了函數(shù)定義。
箭頭函數(shù)在語(yǔ)法上比普通函數(shù)簡(jiǎn)潔多。箭頭函數(shù)就是采用箭頭=>來(lái)定義函數(shù),省去關(guān)鍵字function。
無(wú)參:()=>{},等同于:function (){}
有參:(a,b)=>{},等同于:function (a,b){}
(2)箭頭函數(shù)不綁定this
//箭頭函數(shù)this指當(dāng)前塊級(jí)作用域
const obj = {
num: 10,
sum() {
setTimeout(() => {
console.log(this.num);
}, 1000);
},
};
obj.sum();
如果不是箭頭函數(shù),setTimeout()函數(shù)調(diào)用指的是當(dāng)前window。
const obj = {
num: 10,
sum() {
setTimeout(function (){
console.log(this);
}, 1000);
},
};
obj.sum();
(3)什么情況下不能箭頭函數(shù)
- 定義對(duì)象的方法
const obj = {
num: 10,
sum:() => {
setTimeout(() => {
console.log(this.num);
}, 1000);
},
};
obj.sum();
- 箭頭函數(shù)沒(méi)有arguments
const fun = () => {
console.log(arguments);
};
fun();
- 定義構(gòu)造函數(shù)
const Car = () => {
console.log(this);
};
let car = new Car();
- 定義DOM事件的回調(diào)函數(shù)
const span = document.getElementById("span");
span.addEventListener("click", () => {
console.log(this);
this.innerHTML = "觸發(fā)事件";
});
const span = document.getElementById("span");
span.addEventListener("click", function () {
console.log(this);
this.innerHTML = "觸發(fā)事件";
});
5.3.ES6中新引入類(lèi)的概念
ES6之前javascript中只有對(duì)象,沒(méi)有類(lèi)的概念。它是基于原型的面向?qū)ο笳Z(yǔ)言。原型對(duì)象特點(diǎn)就是將自身的屬性共享給新對(duì)象。
(1)定義類(lèi)
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`我是${this.name},今年${this.age}歲`);
}
}
const person = new Person("張三", 18);
person.sayHello();
console.log(person);
(2)類(lèi)的繼承,重寫(xiě)父類(lèi)的方法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
hello() {
console.log(`我是${this.name},今年${this.age}歲`);
}
}
class Student extends Person {
//子類(lèi)重寫(xiě)父類(lèi)屬性
constructor(name, age, sex) {
super(name, age);
this.sex = sex;
}
hello() {
console.log(`我是${this.name},今年${this.age}歲,性別:${this.sex === '1'?'男':'女'}`);
}
}
const person = new Student('張三', 18,'1');
person.hello();
console.log(person);
(3)靜態(tài)方法和靜態(tài)屬性
//靜態(tài)方法和靜態(tài)屬性只能由類(lèi)名進(jìn)行調(diào)用
class Person {
static eyes = '眼睛';
static hello(){
console.log(`我是${this.name}`);
}
}
console.log(Person.eyes);
Person.hello();
5.4.ES6新增模塊化開(kāi)發(fā)
ES6之前是沒(méi)有類(lèi)的概念的,也就沒(méi)有模塊這一說(shuō)法。理想情況下,開(kāi)發(fā)者應(yīng)該只注重核心業(yè)務(wù)的開(kāi)發(fā),對(duì)于其他有一定通用性的業(yè)務(wù)可以直接引入,也就是模塊。多人開(kāi)發(fā),本應(yīng)如此。
- CommonJS:Commonjs是作為Node中模塊化規(guī)范以及原生模塊面世的。
- AMD和RequireJs:AMD是"Asynchronous Module Definition"的縮寫(xiě),意思就是"異步模塊定義"。它采用異步方式加載模塊,模塊的加載不影響它后面語(yǔ)句的運(yùn)行。所有依賴(lài)這個(gè)模塊的語(yǔ)句,都定義在一個(gè)回調(diào)函數(shù)中,等到所有依賴(lài)加載完成之后(前置依賴(lài)),這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。
Import 和 export案例
- export.js
const name = '李祥';
function hello(){
console.log('hello word');
}
class Car{
constructor(name){
this.name=name;
}
run(){
console.log(this.name+'跑起來(lái)了');
}
}
export default{
name,
hello,
Car,
}
- Import.js
import test from './export.js';
console.log(test.name);
test.hello();
- html中js引入要改成module類(lèi)型
<script src="./js/import.js" type="module"></script>
6.ES6改進(jìn)異步編程
6.1.Promise簡(jiǎn)介及案例
(1)什么是回調(diào)地獄
當(dāng)異步操作想要有順序時(shí),只能在一個(gè)異步成功以后的回調(diào)函數(shù)里面嵌套另一個(gè)異步的操作,如果嵌套的層數(shù)過(guò)多就形成了回調(diào)地獄。
回調(diào)地獄的弊端:后期代碼維護(hù)比較困難。
promise就是用來(lái)解決回調(diào)地獄。
promise封裝了異步操作。創(chuàng)建一個(gè)promise對(duì)象,寫(xiě)一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)參數(shù)有兩個(gè)參數(shù),分別是resolve和reject。函數(shù)內(nèi)部寫(xiě)異步操作,成功調(diào)resolve,失敗調(diào)reject。這時(shí)promise對(duì)象就可以知道異步操作的狀態(tài)。p.then(成功執(zhí)行)p.catch(失敗執(zhí)行)。
promise本質(zhì)就是一個(gè)狀態(tài)機(jī),記錄異步內(nèi)部操作的狀態(tài)。
在es6之前寫(xiě)法代碼耦合,出錯(cuò)時(shí),無(wú)法排除。
function request() {
axios.get("a.json").then((res) => {
if (res && res.data.code === 0) {
console.log(res.data.data.data);
axios.get("b.json").then((res) => {
if (res && res.data.code === 0) {
console.log(res.data.data.data);
axios.get("c.json").then((res) => {
console.log(res.data.data.data);
});
}
});
}
});
}
request();
- 簡(jiǎn)單說(shuō)Promise就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。
- 從語(yǔ)法上說(shuō),Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的的最終狀態(tài)(成功或失敗)。
- Promise 是一個(gè)構(gòu)造函數(shù),提供統(tǒng)一的 API,Promise里不僅可以存放著異步的代碼,也可以放同步的代碼。
// 準(zhǔn)備階段
new Promise((resolve, reject) => {})
// 成功狀態(tài)
new Promise((resolve, reject) => {
resolve('成功'); // 同步代碼
}).then((res) => {
console.log(res);
});
// 失敗狀態(tài)
new Promise((resolve, reject) => {
reject('失敗');
}).catch((err) => {
console.log(err);
});
-
Promise對(duì)象的狀態(tài)不受外界影響
-
pending 初始狀態(tài)
-
resolve 成功狀態(tài)
-
rejected 失敗狀態(tài)
Promise 有以上三種狀態(tài),只有異步操作的結(jié)果可以決定當(dāng)前是哪一種狀態(tài),其他任何操作都無(wú)法改變這個(gè)狀態(tài)
-
-
Promise的狀態(tài)一旦改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果,狀態(tài)不可以逆,只能由 pending變成resolve或者由pending變成rejected
(2)Promise解決回調(diào)地獄案例
//先定義三個(gè)函數(shù)
function requestA() {
return new Promise((resolve, reject) => {
axios.get("a.json").then((res) => {
resolve(res);
});
});
}
function requestB() {
return new Promise((resolve, reject) => {
axios.get("b.json").then((res) => {
resolve(res);
});
});
}
function requestC() {
return new Promise((resolve, reject) => {
axios.get("c.json").then((res) => {
resolve(res);
});
});
}
function request() {
requestA().then((res) => {
console.log(res);
return requestB();
}).then((res) => {
console.log(res);
return requestC();
}).then((res) => {
console.log(res);
});
}
request();
(3)Promise.all方法
- Promise.all 實(shí)際上是一個(gè)函數(shù),它接受一個(gè)
promise
數(shù)組并返回一個(gè)promise
。然后當(dāng)所有的promise
都完成時(shí)會(huì)得到結(jié)果數(shù)組或者當(dāng)其中一個(gè)被拒絕時(shí)會(huì)拋出錯(cuò)誤。 - 返回值將會(huì)按照參數(shù)內(nèi)的
promise
順序排列,而不是由調(diào)用promise
的完成順序決定。
function requestAll() {
Promise.all([requestA(), requestB(), requestC()])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
requestAll();
(4)Promise.race方法
Promse.race就是賽跑的意思,傳入的promise
數(shù)組里面哪個(gè)結(jié)果獲得的快,就返回那個(gè)結(jié)果,不管結(jié)果本身是成功狀態(tài)還是失敗狀態(tài)。
function requestRace() {
Promise.race([requestA(), requestB(), requestC()])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
}
requestRace();
6.2.優(yōu)雅的異步編程async
(1)什么是async
async是異步的簡(jiǎn)寫(xiě),Generator(生成器)的語(yǔ)法糖,用于聲明一個(gè)函數(shù)是異步函數(shù)。
async function sum(a,b) {
await console.log(a+b);
}
sum(1,2);
async
寫(xiě)在函數(shù)前,返回一個(gè)Promise
對(duì)象。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-729494.html
async await改造promise.then異步調(diào)用。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-729494.html
async function request() {
try {
const a = await requestA();
const b = await requestB();
const c = await requestC();
console.log(a, b, c);
} catch (err) {
console.log(err);
}
}
request();
到了這里,關(guān)于【前端】ECMAScript6從入門(mén)到進(jìn)階的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!