真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

關(guān)于 JS 函數(shù)的一切

本文基于: Bilibili - 自由的加百利

成都創(chuàng)新互聯(lián)公司從2013年創(chuàng)立,先為太平等服務(wù)建站,太平等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為太平企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

前置條件:

  • 需掌握函數(shù)的編寫、傳參、返回、調(diào)用
  • 理解作用域、掌握定時(shí)器的用法
  • 知道引用類型和基本數(shù)據(jù)類型的區(qū)別
  • 知道函數(shù)也是引用類型
  • 聽說過同步異步的概念
  • 了解類和對象的關(guān)系

匿名函數(shù)

來看一下一個(gè)函數(shù)的基本屬性:

匿名函數(shù)的自運(yùn)行

我們可以將一個(gè)普通函數(shù)去掉它的名字,這樣就成功的創(chuàng)建了一個(gè)匿名函數(shù),并且編譯器不會(huì)報(bào)錯(cuò)。

那么這個(gè)函數(shù)既然沒有名字,我們又該怎么調(diào)用它呢?這時(shí)只需要使用一個(gè)小括號包裹住整個(gè)函數(shù),再在函數(shù)體的末尾添加一個(gè)小括號就可以在創(chuàng)建函數(shù)之后立即執(zhí)行這個(gè)函數(shù)。

這種寫法,也叫作 匿名函數(shù)的自運(yùn)行

其與直接在外部書寫函數(shù)體內(nèi)部的語句相比,優(yōu)點(diǎn)就是不會(huì)造成變量污染,會(huì)在匿名函數(shù)內(nèi)形成一個(gè) 封閉的作用域

小括號的作用

在匿名函數(shù)的外部加上一個(gè)小括號,實(shí)際的作用是 將該函數(shù)的聲明變成了一個(gè)優(yōu)先計(jì)算的表達(dá)式

( function(){...} )()

而表達(dá)式的運(yùn)算結(jié)果就是這個(gè) 匿名函數(shù) 本身。拿到了函數(shù)本身之后,就可以在其后面加上一個(gè)小括號來調(diào)用它了。

把函數(shù)變成表達(dá)式?

既然小括號的作用是將函數(shù)的聲明變成表達(dá)式,那么在函數(shù)周圍加上運(yùn)算符會(huì)不會(huì)有同樣的效果呢?

+function(){...}()
!function(){...}()
~function(){...}()
void function(){...}()
delete function(){...}()

以上的幾種寫法都可以成功執(zhí)行匿名函數(shù),而且使用 +function(){...}() 這種方式執(zhí)行函數(shù)自運(yùn)行的效率是最高的。

遞歸函數(shù)

遞歸函數(shù) 是指一個(gè)函數(shù)直接或間接的調(diào)用自身,并在特定的情況下結(jié)束并放回運(yùn)行結(jié)果

這里我們舉一個(gè) 階乘 的例子:

function F(N) {
  return N * F(N - 1);
}

表面看上去,這個(gè)函數(shù)可以接收一個(gè)參數(shù),并計(jì)算出這個(gè)數(shù)的階乘。但是仔細(xì)想想就會(huì)發(fā)現(xiàn)不對勁,當(dāng) N = 1 時(shí)函數(shù)并沒有停止自身的繼續(xù)傳遞,也就是說這個(gè)函數(shù)沒有停止條件,最終便會(huì)陷入一個(gè)死循環(huán)。結(jié)果就是 會(huì)在某一時(shí)刻,大量的函數(shù)將內(nèi)存空間占滿導(dǎo)致內(nèi)存溢出。

也就是說我們上面寫的這個(gè)函數(shù),只有 沒有

改造遞歸

我們嘗試改變一下上面的 遞歸函數(shù)
首先要弄清楚,我們需要計(jì)算的是一個(gè)數(shù) 它的階乘是多少。計(jì)算一個(gè)數(shù)字的階乘便是讓這個(gè)數(shù)每次乘以比他自身小 1 的數(shù),直到乘到1。(說得不是很清楚,大家自行理解)

那么關(guān)鍵點(diǎn)就在于這個(gè) 直到

我們不能讓它無止境的傳遞下去,在上面的例子中,參與遞歸的 N 為 1 時(shí)還在繼續(xù)向內(nèi)傳遞,0, -1, -2, -3... 我們所要做的就是當(dāng)函數(shù)傳遞到 N = 1 時(shí)停止向內(nèi)傳遞,直接返回 1 自身,將其自己交給外部的函數(shù)來調(diào)用,代碼更改如下:

function F(N) {
  if (N == 1) return 1;
  return N * F(N - 1);
}

上面 if 語句的作用是:當(dāng) N 為 1 時(shí),直接返回 1

這時(shí)運(yùn)行一下就會(huì)發(fā)現(xiàn),函數(shù)不報(bào)錯(cuò)了,而且也得到了我們想要的結(jié)果。

回調(diào)函數(shù)

回調(diào)函數(shù),并不是指一種特殊的函數(shù),而是指函數(shù)的使用方式

看一下下面的代碼:

function f1(){
  console.log(111);
}
function f2(){
  console.log(222);
}
f1();
f2();

輸出結(jié)果的順序自然是先輸出 111,再輸出 222

但是如果我們給 f1() 添加一個(gè)定時(shí)器呢?

function f1(){
  setTimeout(function(){
    console.log(111);
  }, 1000)
}
function f2(){
  console.log(222);
}
f1();
f2();

這時(shí)便會(huì)先輸出 222,一秒后輸出 111。這種含有異步操作的函數(shù)就被稱為 異步函數(shù) ,異步函數(shù)最大的特點(diǎn)就是 后續(xù)的代碼不需要排隊(duì),異步函數(shù)時(shí)可以和后續(xù)的代碼并行的。f1() 就是一個(gè)典型的異步函數(shù),你無法知道 f1()f2() 哪一個(gè)會(huì)先結(jié)束。

回調(diào)函數(shù)引出

那么在有異步函數(shù)的情況下,如果我希望先輸出 111,再輸出222,要怎么做呢?

目前看來,唯一的辦法是 把函數(shù) f2() 放在 f1() 的內(nèi)部調(diào)用

function f1(){
  setTimeout(function(){
    console.log(111);
    f2();
  }, 1000)
}
function f2(){
  console.log(222);
}
f1();

假設(shè)有這樣一個(gè)場景,項(xiàng)目組里有小白、小黃、小綠三個(gè)人,有一個(gè)工具函數(shù) getToken()

function getToken(){
  //異步函數(shù)......
}

它是一個(gè)異步函數(shù),大家都在使用這個(gè)函數(shù)完成自己的業(yè)務(wù),并且每個(gè)人都希望在 getToken() 結(jié)束后執(zhí)行自己的代碼,于是它們將函數(shù)寫成了下面這樣:

但是這種寫法顯然是錯(cuò)誤的,因?yàn)楫惒胶瘮?shù)保證不了函數(shù)的執(zhí)行順序。那么現(xiàn)在只能想辦法將自己所寫的函數(shù)放在異步函數(shù)內(nèi)部,才有機(jī)會(huì)在其后面執(zhí)行。

首先,我們給 getToken() 函數(shù)增加一個(gè)參數(shù) callback

function getToken(callback){
  //異步函數(shù)......
}

之后,三個(gè)人的代碼就可以改成這樣:

把自己的函數(shù)傳進(jìn)去,最后在 getToken() 的最后調(diào)用這個(gè) callback

function getToken(callback){
  //異步函數(shù)......
  callback();
}

現(xiàn)在,所有人的代碼都會(huì)在異步函數(shù)最后執(zhí)行,這極大的提高了代碼的可復(fù)用性,降低了開發(fā)維護(hù)的成本。

這種函數(shù)調(diào)用的方式就叫回調(diào)

字面意思就是:把自己的函數(shù)交給別人,回頭再調(diào)。

構(gòu)造函數(shù)

  • 這一節(jié)需要理解 什么是面向?qū)ο?/li>

一個(gè)函數(shù)除了可以被當(dāng)作函數(shù),還可以被當(dāng)作 class

function fn(){

}
let obj = new fn();
console.log( typeof obj );

我們可以直接使用 new 關(guān)鍵字來聲明一個(gè)對象,這個(gè)時(shí)候,我們就說 fn() 是一個(gè)構(gòu)造函數(shù)

那么 fn() 明明是一個(gè)空函數(shù),這個(gè)對象是怎么來的呢?

構(gòu)造函數(shù)的執(zhí)行流程

問題的關(guān)鍵就在于這個(gè) new 關(guān)鍵字。當(dāng)你調(diào)用函數(shù)時(shí)在前面加上了 new 關(guān)鍵字,瀏覽器就會(huì)啟動(dòng) 構(gòu)造函數(shù) 的執(zhí)行流程:

function fn(){
  this = {}
  // 創(chuàng)建一個(gè)空對象,將其保存在this關(guān)鍵字中
  
  ...... //your code

  return this;
}
let obj = new fn();

當(dāng)然了,上面部分代碼是不可見的。一個(gè)函數(shù)到底是普通函數(shù)還是構(gòu)造函數(shù),取決于你來怎么使用它。

但是通常,按照習(xí)慣,我們會(huì)將構(gòu)造函數(shù)的首字母大寫,普通函數(shù)的首字母小寫。也就是說,如果你看到一個(gè)函數(shù)的首字母是大寫的,在絕大多數(shù)的時(shí)候,它不應(yīng)該被直接調(diào)用。

function User() {
  ......
}

let user = User();  ×
let user = new User();  √

在最新版的 JavaScript 已經(jīng)支持了 class 關(guān)鍵字,你可以像 Java 一樣定義一個(gè)類,并通過構(gòu)造方法來生成對象。

閉包函數(shù)

function a(){
  let x = 1;
  function b(){
    console.log(x);
  }
}

函數(shù) b() 是一個(gè)定義在函數(shù) a() 內(nèi)部的函數(shù),所以其可以訪問到變量 x ,變量 x 相對于函數(shù) b() 來說就是一個(gè)全局變量。

如果我們把函數(shù) b() 作為函數(shù) a() 的返回值:

function a(){
  let x = 1;
  return function b(){
    console.log(x);
  }
}
let c = a();
c();

我們已知,函數(shù) c() 就是函數(shù) b() ,有由于函數(shù) c() 是全局變量,因此,相當(dāng)于在全局范圍調(diào)用了函數(shù) b() ,打破了函數(shù) b() 只能在局部使用的限制,最終我們打印出了變量 x

在這里,函數(shù) a() 所形成的作用域,叫做 閉包,函數(shù) b() 被稱作 閉包函數(shù)

函數(shù)的柯里化

這一節(jié)來源于知乎:https://zhuanlan.zhihu.com/p/#:~:text=函數(shù)柯里化,就是,后,才執(zhí)行原函數(shù)

function add(a, b) {
  return a + b
}

function curry(fn) {
  return function (a) {
    return function (b) {
      return fn(a, b)
    }
  }
}
let fn  = curry(add)(1)(2)

新聞名稱:關(guān)于 JS 函數(shù)的一切
轉(zhuǎn)載源于:http://weahome.cn/article/dsojpsd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部