1. 程式人生 > >前端進階-ES6函式

前端進階-ES6函式

箭頭函式

將函式轉換為箭頭函式

const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { 
  return name.toUpperCase();
});

將現有的"普通"函式轉換為箭頭函式只需幾步:

  • 刪掉關鍵字 function
  • 刪掉圓括號
  • 刪掉左右花括號
  • 刪掉關鍵字 return
  • 刪掉分號
  • 在引數列表和函式主體之間新增一個箭頭(=>
const upperizedNames = ['Farrin', 'Kagure'
, 'Asser'].map(name => name.toUpperCase());

使用箭頭函式

普通函式可以是函式宣告函式表示式,但是箭頭函式始終是表示式。實際上,它們的全稱是“箭頭函式表示式

  • 儲存在變數中
  • 當做引數傳遞給函式
  • 儲存在物件的屬性中
const greet = name => `Hello ${name}!`;
greet('Asser');
//  Hello Asser!

引數列表出現在箭頭函式的箭頭(即 =>)前面。如果列表中只有一個引數,那麼可以像上述示例那樣編寫程式碼。但是,如果列表中有兩個或多個引數

,或者有零個,則需要將引數列表放在圓括號內:

// 空引數列表需要括號
const sayHi = () => console.log('Hello Udacity Student!');
sayHi();
// Hello Udacity Student!

// 多個引數需要括號
const orderIceCream = (flavor, cone) => console.log(`Here's your ${flavor} ice cream in a ${cone} cone.`);
orderIceCream('chocolate', 'waffle');
// Here's your chocolate ice cream in a waffle cone.

簡寫主體語法

  • 在函式主體周圍沒有花括號
  • 自動返回表示式
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
  name => name.toUpperCase()
);

常規主體語法

  • 它將函式主體放在花括號內
  • 需要使用 return 語句來返回內容
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => {
  name = name.toUpperCase();
  return `${name} has ${name.length} characters in their name`;
});

箭頭函式很強大!

  • 語法簡短多了
  • 更容易編寫和閱讀的簡短單行函式
  • 使用簡寫主體語法時,自動返回內容

this” 和箭頭函式

對於普通函式,this 的值基於函式如何被呼叫。對於箭頭函式,this 的值基於函數週圍的上下文。換句話說,箭頭函式內的,this 的值與函式外面的 this 的值一樣。

普通函式

// 建構函式
function IceCream() {
  this.scoops = 0;
}

// 為 IceCream 新增 addScoop 方法
IceCream.prototype.addScoop = function() {
  setTimeout(function() {
    this.scoops++;
    console.log('scoop added!');
  }, 500);
};

const dessert = new IceCream();
dessert.addScoop(); // scoop added!
console.log(dessert.scoops); // 0
console.log(scoops); // NaN

傳遞給 setTimeout() 的函式被呼叫時沒用到 newcall()apply(),也沒用到上下文物件。意味著函式內的 this 的值是全域性物件,不是 dessert 物件。實際上發生的情況是,建立了新的 scoops 變數(預設值為 undefined),然後遞增(undefined + 1 結果為 NaN)。

使用閉包

// 建構函式
function IceCream() {
  this.scoops = 0;
}

// 為 IceCream 新增 addScoop 方法
IceCream.prototype.addScoop = function() {
  const cone = this; // 設定 `this` 給 `cone`變數
  setTimeout(function() {
    cone.scoops++; // 引用`cone`變數
    console.log('scoop added!');
  }, 0.5);
};

const dessert = new IceCream();
dessert.addScoop();
console.log(dessert.scoops); // 1

上述程式碼沒有在函式內使用 this,而是將 cone 變數設為 this,然後當函式被呼叫時查詢 cone 變數。這樣可行,因為使用了函式外面的 this 值。

將傳遞給 setTimeout() 的函式替換為箭頭函式:

// 建構函式
function IceCream() {
  this.scoops = 0;
}

// 為 IceCream 新增 addScoop 方法
IceCream.prototype.addScoop = function() {
  setTimeout(() => { // 一個箭頭函式被傳遞給setTimeout
    this.scoops++;
    console.log('scoop added!');
  }, 0.5);
};

const dessert = new IceCream();
dessert.addScoop();
console.log(dessert.scoops); // 1

因為箭頭函式從周圍上下文繼承了 this 值,所以這段程式碼可行!當 addScoop() 被呼叫時,addScoop() 中的 this 的值指的是 dessert。因為箭頭函式被傳遞給 setTimeout(),它使用周圍上下文判斷它裡面的 this 指的是什麼。因為箭頭函式外面的 this 指的是 dessert,所以箭頭函式裡面的 this 的值也將是 dessert

如果我們將 addScoop() 方法改為箭頭函式,你認為會發生什麼?

// 建構函式
function IceCream() {
    this.scoops = 0;
}

// 為 IceCream 新增 addScoop 方法
IceCream.prototype.addScoop = () => { // addScoop 現在是一個箭頭函式
  setTimeout(() => {
    this.scoops++;
    console.log('scoop added!');
  }, 0.5);
};

const dessert = new IceCream();
dessert.addScoop();
console.log(dessert.scoops); // 0

addScoop() 方法外面,this 的值是全域性物件。因此如果 addScoop() 是箭頭函式,addScoop() 中的 this 的值是全域性物件。這樣的話,傳遞給 setTimeout() 的函式中的 this 的值也設為了該全域性物件!

預設函式引數

function greet(name = 'Student', greeting = 'Welcome') {
  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

要建立預設引數,需要新增等號 ( = ) 以及當引數未提供時引數應該設為的預設值。在上述程式碼中,兩個引數的預設值都是字串,但是可以為任何 JavaScript 資料型別!

預設值和解構

預設值和解構陣列

function createGrid([width = 5, height = 5]) {
  return `Generates a ${width} x ${height} grid`;
}

createGrid([]); // Generates a 5 x 5 grid
createGrid([2]); // Generates a 2 x 5 grid
createGrid([2, 3]); // Generates a 2 x 3 grid
createGrid([undefined, 3]); // Generates a 5 x 3 grid

createGrid() 函式預期傳入的是陣列。它通過解構將陣列中的第一項設為 width,第二項設為 height。如果陣列為空,或者只有一項,那麼就會使用預設引數,並將缺失的引數設為預設值 5

createGrid(); // throws an error
// Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined

出現錯誤,因為 createGrid() 預期傳入的是陣列,然後對其進行解構。因為函式被呼叫時沒有傳入陣列,所以出現問題。但是,我們可以使用預設的函式引數!

function createGrid([width = 5, height = 5] = []) {
  return `Generating a grid of ${width} by ${height}`;
}
createGrid(); // Generates a 5 x 5 grid

預設值和解構物件

function createSundae({scoops = 1, toppings = ['Hot Fudge']}) {
  const scoopText = scoops === 1 ? 'scoop' : 'scoops';
  return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`;
}

createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings.
createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings.
createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings.
createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings.

createSundae(); // throws an error
// Uncaught TypeError: Cannot match against 'undefined' or 'null'.

通過新增空物件作為預設引數,以防未提供引數,現在呼叫函式時沒有任何引數將可行。

function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) {
  const scoopText = scoops === 1 ? 'scoop' : 'scoops';
  return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`;
}
createSundae(); // Your sundae has 1 scoop with Hot Fudge toppings.
function houseDescriptor({houseColor = 'green', shutterColors = ['red']} = {}) {
  return `I have a ${houseColor} house with ${shutterColors.join(' and ')} shutters`;
}

// 下面的可以正常執行
houseDescriptor({});
houseDescriptor();
houseDescriptor({houseColor = 'red'});
houseDescriptor({shutterColors = ['orange', 'blue']});
houseDescriptor({houseColor = 'red', shutterColors = ['orange', 'blue']});

陣列預設值與物件預設值

陣列預設值相比,物件預設值具備的一個優勢是能夠處理跳過的選項

function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) {}
createSundae({toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']});

使用陣列預設值進行解構的同一函式相對比:

function createSundae([scoops = 1, toppings = ['Hot Fudge']] = []) {}
createSundae([undefined, ['Hot Fudge', 'Sprinkles', 'Caramel']]);

因為陣列是基於位置的,我們需要傳入 undefined 以跳過第一個引數(並使用預設值)來到達第二個引數。

除非你有很充足的理由來使用陣列預設值進行陣列解構,否則建議使用物件預設值進行物件解構!

類預覽

class Dessert {
  constructor(calories = 250) {
    this.calories = calories;
  }
}

class IceCream extends Dessert {
  constructor(flavor, calories, toppings = []) {
    super(calories);
    this.flavor = flavor;
    this.toppings = toppings;
  }
  addTopping(topping) {
    this.toppings.push(topping);
  }
}
  • class
  • extends
  • super()

對 JavaScript 類的錯覺

var cookie = new Dessert();

ECMAScript 為我們提供了一些新的關鍵字,如 classextendssuper 等,但是這並不意味著整個語言的運作機制發生了變化,所以 JS 核心仍然在使用函式和原型繼承,我們只是有了一種更清晰易懂的方式來實現相同的功能。語言的基本功能並沒有發生改變,所以JS 並不是一門基於類的語言。它使用函式來建立物件,並通過原型(prototype)將它們關聯在一起。JS 只是給常規函式和原型披上了一層類的外衣。

JavaScript 類

ES5 “類”總結

function Plane(numEngines) {
  this.numEngines = numEngines;
  this.enginesActive = false;
}

// 由所有例項 "繼承" 的方法
Plane.prototype.startEngines = function () {
  console.log('starting engines...');
  this.enginesActive = true;
};

const richardsPlane = new Plane(1);
richardsPlane.startEngines();

const jamesPlane = new Plane(4);
jamesPlane.startEngines();

在上述程式碼中,Plane 函式是一個建構函式,它將用來建立新的 Plane 物件。具體的 Plane 物件的資料被傳遞給 Plane 函式,並設定到該物件上。每個 Plane 物件繼承的方法被放置在 Plane.prototype 物件上。

需要注意的事項:

  • 建構函式使用 new 關鍵字被呼叫
  • 按照慣例,建構函式名以大寫字母開頭
  • 建構函式控制將被建立的物件的資料的設定
  • 繼承”的方法被放在建構函式的原型物件

在 ES6 類都在底層幫你設定了所有這些。

class Plane {
  constructor(numEngines) {
    this.numEngines = numEngines;
    this.enginesActive = false;
  }

  startEngines() {
    console.log('starting engines…');
    this.enginesActive = true;
  }
}

將函式轉換為類

在這裡插入圖片描述

使用 JavaScript 類

類只是一種函式

class Plane {
  constructor(numEngines) {
    this.numEngines = numEngines;
    this.enginesActive = false;
  }

  startEngines() {
    console.log('starting engines…');
    this.enginesActive = true;
  }
}
typeof Plane; // function

沒錯,它只是個函式!甚至沒有向 JavaScript 新增新型別。

靜態方法

class Plane {
  constructor(numEngines) {
    this.numEngines = numEngines;
    this.enginesActive = false;
  }

  static badWeather(planes) {
    for (plane of planes) {
      plane.enginesActive = false;
    }
  }

  startEngines() {
    console.log('starting engines…');
    this.enginesActive = true;
  }
}

這樣使得 badWeather() 成為 Plane 類中可以直接訪問的方法,因此你可以這樣呼叫它:

Plane.badWeather([plane1, plane2, plane3]);

面向物件的 JavaScript

類的優勢

  • 設定內容更少
  • 清晰地定義了建構函式
  • 全部都包含起來了

使用類時需要注意的事項

  • class 不是魔術,關鍵字 class 帶來了其它基於類的語言中的很多思想觀念。它沒有像變魔術一樣向 JavaScript 類添加了此功能。
  • class 是原型繼承的抽象形式,JavaScript 類實際上使用的就是原型繼承
  • 使用類需要用到 new,在建立 JavaScript 類的新例項時,必須使用關鍵字 new

ES6 中的子類

現在使用新的 superextends 關鍵字擴充套件類。

class Tree {
  constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) {
    this.size = size;
    this.leaves = leaves;
    this.leafColor = null;
  }

  changeSeason(season) {
    this.leafColor = this.leaves[season];
    if (season === 'spring') {
      this.size += 1;
    }
  }
}

class Maple extends Tree {
  constructor(syrupQty = 15, size, leaves) {
    super(size, leaves);
    this.syrupQty = syrupQty;
  }

  changeSeason(season) {
    super.changeSeason(season);
    if (season === 'spring') {
      this.syrupQty += 1;
    }
  }

  gatherSyrup() {
    this.syrupQty -= 3;
  }
}

const myMaple = new Maple(15, 5);
myMaple
            
           

相關推薦

前端-ES6函式

箭頭函式 將函式轉換為箭頭函式 const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { return name.toUpperCase(); }); 將現有的"普通"函式轉換為

前端-ES6內建功能

Symbol Symbol 簡介 Symbol 是 JS 原始資料型別列表中(numbers、strings、booleans、null、undefined)的最新補充。Symbol 是一個唯一識別符號,常用於唯一標識物件中的屬性。 碗這個物件中有幾個水果屬性(水果也是

前端-執行時函式

一級函式 函式是一級函式 在 JavaScript 中,函式是一級函式。這意味著,就像物件一樣,你可以像處理其他元素(如數字、字串、陣列等)一樣來處理函式。JavaScript 函式可以: 儲存在變數中 從一個函式返回 作為引數傳遞給另一個函式

web前端突破瓶頸的前者經驗

想要 使用 post 有用 details 教程 for pap 看大牛 這裏再說一下自己為什麽會迷茫,技術學到某個階段就很難提升了,更多只能靠自己摸索,沒有人可以指導,就像是創業公司的CEO,突然想起之前的一家公司老板當時說的話,你看我現在好像是成功了,但是每天

前端: 響應式開發與常用框架 [MP4]

進階 第四章 解壓 ebs 清除 標簽 sets 上進 html5 ├─第一章 前期準備│ │ └─第一章 前期準備│ │ │ │ 響應式1-1│ │ 響應式1-2│ │ 響應式1-3│

前端知識

1.for和forEach區別:     foreach適用於只是進行集合或陣列遍歷,for則在較複雜的迴圈中效率更高。   foreach不能對陣列或集合進行修改(新增刪除操作),如果想要修改就要用for迴圈。   foreach適用於迴圈次數未知,或者計算迴圈次數比較麻煩情況下使用效率更高,但是更為

MySQL19--函式的建立(舉例)/設定mysql的建立函式的許可權/檢視(show)/刪除(drop) / 舉4個栗子

/*MySQL進階19 函式 儲存過程和函式:都類似於java中的方法; 儲存過程和函式通用好處: 1.提高程式碼的重用性 2.簡化操作 好處: 減少操作次數,減少了編譯次數,減少了和伺服器的連線次數,提高了效率 --------------- #區別

Python3()-偏函式functools.prtial()

functools.partial(FuncA,p1,p2,…)用於把函式FuncA的前幾個引數分別固定為p1,p2,… 例 from functools import partial def add(a, b, c): print("a=", a) print(

前端」完全吃透async/await,深入JavaScript非同步

完全吃透async/await 導論: 首先,必須瞭解Promise 主要研究基本語法 對比Promise與Async 異常處理 參考: Async +Await 理解 as

前端」完全吃透Promise,深入JavaScript非同步

完全吃透Promise Promise晉級,需要的全部都在這 主要內容: promise基本實現原理 promise 使用中難點(鏈式呼叫,API基本上返回都是一個新Promise,及引數傳遞) promise 對異常處理 pr

前端:vue中的computed和watch的異同

前言 心情很忐忑,當我寫下這個標題。想起年初時在杭州求職,電面了一家武漢的公司,面試官就拋了這樣一個問題。那時候還懵懵懂懂,就知道如何使用,並沒有太清楚兩者的區別。 開始 有時候寫這些東西,真的怕誤導了一些人,以下描述的異同,只是我個人的觀點。如果有什麼不當之處,還望各位博友指出~感謝

前端:一些好的部落格博文分享

前言 之前在讀書會聽到的,人與人思考同一問題時,心理表徵是不同的。在技術圈,各路大神大牛雲集。向他們看齊,學習他們發現問題、分析問題以及解決問題的方式,能讓我們更好地看到差距,提升自我。 開始 我不盲目追隨誰,只是取人所長,提升自我。以下是一些我自己在平時擴充套件學習中,發現的較好的部落

web前端知識之JavaScript記憶體機制講解

  一 背景     var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因為JavaScript具有自動垃圾回收機制,所以對於前端開發來

Python每日--filter函式的使用

一、描述 filter() 函式用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。 該接收兩個引數,第一個為函式,第二個為序列,序列的每個元素作為引數傳遞給函式進行判,然後返回 True 或 False,最後將返回 True 的元素放到新列表中。 二、語法

(27)函式

函式的五種宣告方式       1.具名函式      function f(x,y){         return x+y     }   &nbs

前端課程之物件屬性特性詳解

一. js中物件到底是什麼? 首先,大家想象我們平時都使用了物件的哪些物件? 常見的可能就是建立物件,然後取值,設值,例子如下: var obj = { name: 'aaa' //定義屬性 } obj.name = 'bbb'; //設定屬性值 console.log(obj.name); //

前端能力

css預處理框架的學習(簡單易懂網址) 1.Less的學習:https://less.bootcss.com/, 簡單理解路線:基於javascript的css前處理器,兩種方式運用(node.js中,瀏覽器中外聯引入); 主要語法:變數,混合,函式,運算,巢狀,maps,作用域,Nam

函式節流與函式防抖

原文標題:函式節流與函式防抖 原文地址:https://justclear.github.io/throttle-and-debounce/ 原文作者:justclear   什麼是函式節流與函式防抖 舉個栗子,我們知道目前的一種說法是當 1 秒內連續播放 24 張以上

前端(第一期)-呼叫堆疊筆記

1-1 理解 Javascript 執行上下文和執行棧 原文地址 知識點有: JavaScript程式的內部執行機制; 理解執行上下文和執行棧; 理解以上知識點有助於理解JavaScript的提升機制、作用域和閉包 執行上下文 執行上下文就是當前JavaScript程式碼被解析

Python04 函式的引數傳遞

def func(a, b, c): return a + b + c # 位置傳遞 print(func(1, 2, 3)) # 關鍵字傳遞 print(func(c=3, b=2, a=1)) # 關鍵字傳遞可以和位置傳遞混用 print(func(1, c=3, b=2