1. 程式人生 > >撩課-Web架構師養成系列第一篇

撩課-Web架構師養成系列第一篇

前言

Web架構師養成系列共15篇,每週更新一篇,主要分享、探討目前大前端領域(前端、後端、移動端)企業中正在用的各種成熟的、新的技術。
部分文章也會分析一些框架的底層實現,讓我們做到知其然知其所以然。
本篇文章閱讀需要時長:約15分鐘

一、ECMAScript 6/7/8簡介

ECMAScript 6.0,簡稱ES6,第一個版本是在2015年6月進行釋出,所以也稱之為《ECMAScript 2015 標準》(簡稱 ES2015)。

JavaScript是ECMAScript的一種實現(分支),遵循ECMAScript標準的。目前主流瀏覽器已經可以完美相容和使用ES6。ES7/8部分新特性也已經被用於我們的實際開發中。

  image

本篇主要講解ES6的知識點,內容如下:let和const、解構賦值、字串操作、函式、陣列API、集合、物件拷貝、延展操作符、物件補充、Generator、Proxy、Reflect。

二、let和const

ES6新增了let和const來宣告變數,主要是解決var宣告變數所造成的困擾和問題:

  var不能用於定義常量
  
  var可以重複宣告變數
  
  var存在變數提升
  
  var不支援塊級作用域

而let和const解決了以上問題,具體操作如下:

1)不可以重複宣告變數

let site = 'itLike';

let site = 'itLike'; 

console.log(site); 

執行結果:

Identifier 'site' has already been declared

2)不存在變數提升

 console.log(site);
 let site = 'itLike';
 執行結果:

site is not defined

3)可以定義常量

不能給常量重新賦值,但如果是引用型別的話可以進行修改。

// 自然對數的底

const E = 2.718;

E = 2.71; 

console.log(E); 執行結果: Assignment to constant variable. // 引用型別 const LK = { name:'itLike', intro: '喜歡IT, 就上撩課(itLike.com)' }; LK.name = '撩課'; console.log(LK); 執行結果: 
  image

4) 塊級作用域

如果用var定義變數,變數是通過函式或者閉包擁有作用域;但,現在用let定義變數,不僅僅可以通過函式/閉包隔離,還可以通過塊級作用域隔離。
塊級作用域用一組大括號定義一個塊,使用 let 定義的變數在大括號的外部是訪問不到的,此外,let宣告的變數不會汙染全域性作用域。

{let site = 'itLike';}

console.log(site);

執行結果:

site is not defined

if(1){  let str = '小撩'; } console.log(str); 執行結果: str is not defined 

5)案例運用

高階排他實現(不再使用閉包)

  image

三、解構賦值

用於分解js中物件的結構。

1) 用於陣列的結構

//  普通寫法

let nameArr = ['撩課', '小撩', '小煤球']; let name1 = nameArr[0]; let name2 = nameArr[1]; let name3 = nameArr[2]; // 解構寫法 let [name1, name2, name3] = nameArr; console.log(name1, name2, name3); 

2)物件的解構

//  寫法1

let {name, age, sex}

 = {name: '小煤球', age: 1, sex: '公'}; // 結果: 小煤球 1 公 console.log(name, age, sex); // 寫法2: 解構重新命名 let {name: lkName, age: lkAge, sex: lkSex} = {name: '小煤球', age: 1, sex: '公'}; // 結果: 小煤球 1 公 console.log(lkName, lkAge, lkSex); // 寫法3: 可以設定預設值 let {name, age, sex = '公'} = {name: '小煤球', age: 1}; console.log(sex); // 公 // 寫法4:省略解構 let [, , sex] = ['小煤球', 1, '公 ']; console.log(sex); 

3) 應用場景

在封裝ajax的GET和POST請求時, 就可以運用到解構的知識點,程式碼如下:

  image

四、延展操作符

1)延展陣列

  let arr1 = [ 'a', 'b', 'c'];
  
  let arr2 = [1, 2, 3]; let result = [...arr1, ...arr2]; console.log(result); // [ "a", "b", "c", 1, 2, 3 ] 

2)延展物件

  let smallDog = {name:'小煤球', age: 1}; let bigDog = {name: 'Python', age: 2}; let dog = {...smallDog, ...bigDog}; console.log(dog); // {name: "Python", age: 2} 

注意: 如果物件中的屬性一致, 會被覆蓋

3)開發應用場景

  function getMinValue() {
  
       console.log(Math.min(...arguments)); } getMinValue(1, -99, 22, 10, 9); // -99 

五、字串操作

新增字串方法

1) startsWith()

判斷字串是否以 XX 開頭

let url = 'http://www.itlike.com';

console.log(url.startsWith('http'));  // true 

2) endsWith()

判斷字串是否以 XX 結尾

let file = 'index.html';

console.log(file.endsWith('html'));  // true 

3) includes()

判斷字串中是否包含 XX

let str = 'liaoke';

console.log(str.includes('ao')); // true 

4) repeat()

拷貝n份

let title = '撩課線上';

console.log(title.repeat(100));

5) padStart() / padEnd()

padStart()用於頭部補全,

padEnd()用於尾部補全; 

第一個引數用來指定字串的最小長度,

第二個引數是用來補全的字串。

//  "2030111111"

let y1 = '2030'.padEnd(10, '1'); // "2030-11-22" let y2 = '11-22'.padStart(10, '2030-MM-DD'); console.log(y1, y2); 

模板字串

1) 模板字串

模板字串用反引號(`)包含,變數用${}括起來; 在開發中使用是非常靈活的。

 let name = '小煤球';
 let sex = '公';
 let result = `我叫 ${name} , 我是 ${sex} 的`; console.log(result); // 我叫 小煤球 , 我是 公 的 

2) 模板字串遍歷插入

  image

3) 模板字串實現原理

let name = '小煤球';
let sex = '公';
let result = `我叫 ${name} , 我是 ${sex} 的`; result = result.replace(/\${([^}]*)}/g); console.log(result); 

六、函式操作

1) 設定預設引數

function logPerson(name, sex = '男', age = 20) { console.log(name); console.log(sex); console.log(age); } // undefined 男 20 logPerson(); 

2)延展引數轉化

 let logName = function (arg1, ...arg2) {
 console.log(arg1, arg2); }; // 宋小寶 , ["趙薇", "王菲", "那英"] logName('宋小寶', '趙薇', '王菲', '那英'); 

3)箭頭函式

箭頭函式簡化了函式的的定義方式;
一般以 "=>" 操作符左邊為輸入的引數;
而右邊則是進行的操作以及返回的值 inputs => output。

 ["趙薇", "王菲", "那英"].forEach(
 val => console.log(val) ); 

注意:

1)多個引數要用()包起來,函式體有多條語句需要用{}包起來;
2)箭頭函式根本沒有自己的this,所以內部的this就是外層程式碼塊的this。 正是因為它沒有this,從而避免了this指向的問題;
3)箭頭函式中沒有arguments物件。

  image

注意:

1)let宣告的變數不會放在window上
2)物件不是作用域

 let site = 'like.com';

 let obj = {

    site: '撩課', func: () => { // this指向window console.log(this); // undefined console.log(this.site); } }; let func = obj.func; func(); 

七、陣列新增方法

ES6中在原有陣列的方法上又新增了一些好用的方法,比如:forEach、findIndex、find、map、reduce、filter、every、some等。

1)Array.from()

將一個數組或者類陣列變成新陣列,是淺拷貝操作。

let oldArr = [

    '小煤球', 10, 
 
     {df1: '小Python', df2: '土豆'} ]; let newArr = Array.from(oldArr); console.log(newArr === oldArr); // false 

2)Array.of()

建立一個具有可變數量引數的新陣列例項,而不考慮引數的數量或型別。

  // [8]
  
  console.log(Array.of(8));
  
  // [1, 2, 3] console.log(Array.of(1, 2, 3)); // [ , , , , , , ] console.log(Array(8)); // [1, 2, 3] console.log(Array(1, 2, 3)); 

3)Array.fill()

用一個固定值填充一個數組中從起始索引到終止索引內的全部元素。
語法結構:arr.fill(value[, start[, end]])

  let array1 = [1, 2, 3, 4, 5]; // 用 撩 替換 索引[2,5]中的內容 console.log(array1.fill('撩', 2, 5)); // 用 撩 替換 索引[1]中的內容 console.log(array1.fill('撩', 1)); // 用 撩 替換 陣列中所有內容 console.log(array1.fill('撩')); 

執行結果:

  image

八、物件操作

8.1 屬性簡寫

如果物件中屬性值和變數名一樣,並且屬性的值就是變量表示值,則簡寫。

  image

8.2 super

通過super可以呼叫prototype上的屬性或方法。

  image

8.3 Object.is

對比兩個值是否相等

> console.log(Object.is(Array, Object));

**8.4 Object.setPrototypeOf** 將一個指定的物件的原型設定為另一個物件或者null let dog1 = { name: '小煤球' }; let obj = {name: 'xxx'}; Object.setPrototypeOf(dog1, obj); let dog2 = { __proto__: obj }; console.log(dog1.__proto__.name); console.log(dog2.__proto__.name); **8.5 物件拷貝-深拷貝和淺拷貝** **1)淺拷貝** Object.assign拷貝 let obj1 = { dog1: { name: '小煤球' } }; let obj2 = { name: '小Python' }; let obj = {}; Object.assign(obj, obj1, obj2); console.log(obj); 延展拷貝 let obj1 = { dog1: { name: '小煤球' } }; let obj2 = { name: '小Python' }; console.log({ ...obj1, ...obj2 }); 

2)深拷貝

  JSON.parse和JSON.stringify
  
  let obj1 = { dog1: { name: '小煤球' } }; let obj2 = { name: '小Python' }; console.log(JSON.parse(JSON.stringify({ ...obj1, ...obj2 }))); 

遞迴呼叫實現

  image

九、類操作

在之前定義類是通過建構函式來操作的,es6新增了class關鍵字,此時,我們也可以像其它語言一樣來建立各種類了。

class Person{

constructor(name, age){

    this.name = name;

    this.age = age;

}

print(){

    console.log('我叫' + this.name + ',今年' + this.age + '歲'); } 

}

類的繼承

小案例:五彩小球

執行效果:

  image

核心程式碼:

  image   image

十、集合操作

1set

一個Set是一堆東西的集合,Set有點像陣列,不過跟陣列不一樣的是,Set裡面不能有重複的內容;

> // 建立一個集合
  
  let set = new Set(['張三', '李四', '王五', '張三', '李四']); console.log(set); // 一個屬性 console.log(set.size); // 四個方法 // add console.log(set.add('劉德華').add('旋之華')); console.log(set); // delete console.log(set.delete('張三')); console.log(set.delete('李四')); console.log(set); // has console.log(set.has('張三')); console.log(set.has('張三1')); // clear console.log(set.clear()); // undefined console.log(set); 

2)map

Map結構提供了“值—值”的對應,是一種更完善的Hash結構實現。
如果你需要“鍵值對”的資料結構,Map比Object更合適。
它類似於物件,也是鍵值對的集合,但是“鍵”的範圍不限於字串,各種型別的值(包括物件)都可以當作鍵。
例項屬性和方法:size、set、get、has、delete、clear

  // 建立一個Map
  
  let obj1 = {a: 1}, obj2 = {b: 2}; const map = new Map([ ['name', '張三'], ['age', 18], ['sex', '男'], [obj1, '今天天氣很好'], [obj2, '適合敲程式碼'], [[1,2], 'hhh'] ]); console.log(map); console.log(map.size); // set和get map.set('friends', ['趙六', '力氣']).set(['dog'], '小花'); console.log(map); console.log(map.get('name')); console.log(map.get(obj1)); // delete map.delete(obj1); console.log(map.delete('xxxx')); console.log(map); // has console.log(map.has(obj1)); console.log(map.has(obj2)); // clear map.clear(); console.log(map); // 遍歷 map.forEach(function (value, index) { console.log(index + ':' + value); }); // 注意事項 map.set({}, '呵呵呵呵呵'); map.set({}, '哈哈哈哈'); console.log(map); console.log({} === {}); 

十一、Generator

為什麼要使用generator?

開發中, 比如在做網路請求時我們會進行非同步呼叫,為了保證呼叫順序的正確性,通常我們會用回撥函式,也可以採用Promise相關的技術來操作。
還有一種常用的解決方案,它就是Generator生成器函式。
顧名思義,它是一個生成器,它也是一個狀態機,內部擁有值及相關的狀態,生成器返回一個迭代器Iterator物件,我們可以通過這個迭代器,手動地遍歷相關的值、狀態,保證正確的執行順序。

1)宣告

Generator的宣告方式類似一般的函式宣告,只是多了個*號,並且一般可以在函式內看到yield關鍵字。

  function* showNames() {
  
      yield '張三';
  
      yield '李四';
  
      return '王五'; } let show = showNames(); // {done: false, value: "張三"} console.log(show.next()); // {done: false, value: "李四"} console.log(show.next()); // {done: true, value: "王五"} console.log(show.next()); // {done: true, value: undefined} console.log(show.next()); 

迭代器有一個next方法,每次執行的時候會返回一個物件,物件裡面有兩個屬性,一個是value表示返回的值,還有就是布林值done,表示是否迭代完成。

2)模擬實現

  image

十二、Proxy&&Reflect (瞭解)

從語法角度講JavaScript不支援過載。
原因很簡單,JS中函式可以傳入任意型別、任意個數的引數,
通通可以通過在函式內使用this.arguments獲得。
這樣,就無法實現同名函式引數列表不同實現不同功能。
當然,在實際使用過程中,可以人為去檢測傳入實參的個數及型別,來進行不同操作。
但是,這不能叫做過載。
ES6帶來了Proxy和Reflect,配合使用可以實現過載。
Proxy用於修改某些操作的預設行為,相當於對原始想進行的操作進行“包裝”;
Reflect物件的方法與Proxy物件的方法一一對應,這使得Proxy物件可以方便的呼叫對應的Reflect方法完成預設行為。

set實現:

  image

PS: 什麼時過載?

簡單說,就是函式或者方法有相同的名稱,但是引數列表不相同的情形,這樣的同名不同引數的函式或者方法之間,互相稱之為過載函式或者方法。

獲取程式碼,有疑惑、答疑,加我微信yejh9522溝通交流即可;下篇更新預告: ES7/8新特性,Async和Promise