日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

初探JS的函数

發布時間:2025/4/16 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初探JS的函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是函數

函數是對象的一種,也是一段可以重復使用的代碼塊,開發人員為了完成某項功能,把相關代碼塊放到一起。

函數內部可以傳參,也可以被當做參數傳遞

目前定義函數有五種方法

具名函數來定義

function f(x, y){return x + y } f.name //'f' 復制代碼

匿名函數來定義

var f f = function(x, y){return x + y } f.name //'f' 復制代碼

具名函數定義了又賦值給了變量

var f1 f1 = function f(a, b){return a + b } f1.name //'f' 復制代碼

要注意:雖然f1.name='f',但是f只在函數內部可用,實際上函數的名字還是f1

window.Function來構造

var f2 = new Function('x', 'y', 'return x + y') f2.name //'anonymous' 復制代碼

箭頭函數

var f3 = (x, y) => {return x - y} var sum = (x, y) => x + y //函數體內只有一行代碼,可以省略大括號和return var n2 = n => n*n //只有一個參數,可以省略小括號 復制代碼

常用的定義方法是1、2、5這三種方法。

函數的一些必備知識

函數的name屬性

由上面的五種定義方法,我們可以知道函數具有name屬性,而且不同的定義方法,name屬性也很奇葩。

函數如何調用

為了理解后面的this,推薦使用call()方法,而不是使用常見的f()

以第一種定義方法為例

f.call(undefined, 1, 3) 4 復制代碼

call()方法的第一個參數就是this,后面的參數才是函數的執行參數。

下面用代碼檢驗一下

function f1(m, n){console.log(this)console.log(m + n) } undefined f1.call(undefined, 1, 3) Window {postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window,?…} //不是應該打印undefined,為啥是window呢? 4 //這才是函數的執行內容 復制代碼

執行f1.call(undefined, 1, 3)后,this不是應該打印出undefined嗎,為啥打印了Window呢(注意實際上是個小寫的window,不是瀏覽器打印的大寫的Window),可以用代碼驗證打印的就是小寫的window

function f1(m, n){console.log(this === window)console.log(m + n) } undefined f1.call(undefined, 1, 3) true //說明是小寫的window 4 function f1(m, n){console.log(this === Window)console.log(m + n) } undefined f1.call(undefined, 1, 3) false //并不是大寫的Window 4 復制代碼

我真是服啦,那window和Window有啥區別呢。真是蛋疼啊,竟然考慮這個問題……

答案就是 var object = new Object,那var window = new Window。而且Window毫無探討的意義,倒是這個window是個全局屬性,多少有點用。


有時候自己真是有點鉆牛角尖,鉆進去后,還不會舉一反三。如果立刻想到obj的例子就不用浪費時間了。


這就是藏著的this

這是因為瀏覽器搗的鬼,他把undefined變成了window。接下來使用嚴格模式,讓undefined現身

function f1(m, n){ 'use strict'console.log(this)console.log(m + n) } undefined f1.call(undefined, 1, 3) undefined //這個undefined就是call()方法的第一個參數undefined 4 復制代碼
  • 而且call()的第一個參數是啥,this就是啥
function f1(m, n){ 'use strict'console.log(this)console.log(m + n) } undefine f1.call('我是啥this就是啥', 1, 3) 我是啥this就是啥 //打印的依然是call()的第一個參數 4 復制代碼

arguments

前面分析了call()的第一個參數,那后倆參數是啥呢。

對,你沒猜錯,那就是arguments。

當你寫call(undefined, 1, 3)的時候。undefined可以被認為是this,[1, 3]就是arguments

函數的call stack

上面我們接觸了call()方法,現在我們學習一下當有多個函數調用的時候,JavaScript解析器是如何調用棧的。

MDN的解釋如下

調用棧是解析器(如瀏覽器中的的javascript解析器)的一種機制,可以在腳本調用多個函數時,跟蹤每個函數在完成執行時應該返回控制的點。(如什么函數正在執行,什么函數被這個函數調用,下一個調用的函數是誰)

  • 當腳本要調用一個函數時,解析器把該函數添加到棧中并且執行這個函數。
  • 任何被這個函數調用的函數會進一步添加到調用棧中,并且運行到它們被上個程序調用的位置。
  • 當函數運行結束后,解釋器將它從堆棧中取出,并在主代碼列表中繼續執行代碼。
  • 如果棧占用的空間比分配給它的空間還大,那么則會導致“堆棧溢出”錯誤。

以下是通過三個方面去理解call stack這個概念的。

普通調用

代碼如下,直觀的動圖可以看上述的鏈接

function a(){console.log('a')return 'a' }function b(){console.log('b')return 'b' }function c(){console.log('c')return 'c' }a.call() b.call() c.call() 復制代碼

如上的代碼,先有三個函數聲明,然后是三個調用。瀏覽器先執行a.call(),然后執行b.call(),c.call(),下面結合圖具體詳細分析。

  • 第一步:瀏覽器入口是a.call(),a函數入棧,執行a函數內部代碼
  • 第二步:console.log('a')執行完畢,就出棧,接著a函數結束,出棧死亡
  • 第三步:b.call()入棧,執行b函數內部代碼
  • 第四步: console.log('b')執行完畢就出棧,接著b函數結束,出棧死亡
  • 第五步:c.call()入棧,執行c函數內部代碼
  • 第六步:console.log('c')執行完畢就出棧,接著c函數結束,出棧死亡。
  • 整個代碼結束,瀏覽器恢復平靜。

嵌套調用

function a(){console.log('a1')b.call()console.log('a2')return 'a' } function b(){console.log('b1')c.call()console.log('b2')return 'b' } function c(){console.log('c')return 'c' } a.call() console.log('end') 復制代碼

  • 第一步:瀏覽器的入口還是a.call(),a.call()入棧,執行a函數內部的代碼
  • 第二步: a函數的第一行語句console.log('a1'),入棧,打印出a1,這句話就出棧死亡。此時a函數繼續執行下面的代碼。
  • 第三步: a函數的第二行語句b.call()入棧。執行b函數內部的代碼。
    • 第四步:進入b函數內部,b函數的第一行語句console.log('b1')入棧,打印出b1,就出棧死亡。
    • 第五步:b函數的第二行c.call()入棧,又進入c函數內部
      • 第六步:進入c函數的內部,第一行語句console.log('c')入棧,打印出c,就出棧死亡。
      • 第七步:c函數執行完畢,出棧死亡。
    • 第八步:回到b函數內部,執行第三行代碼console.log('b2')入棧,打印出b2,出棧死亡。
    • 第九步: b函數執行完畢,出棧死亡。
  • 第十步: 回到a函數內部,執行第三行代碼console.log('a2'),入棧,打印出a2,就出棧死亡。
  • 第十一步:a函數執行完畢,出棧死亡。
  • 第十二步:console.log('end')入棧,打印出end,出棧死亡。
  • 整個代碼運行完,瀏覽器歸于平靜。

遞歸調用

遞歸調用就是上面的嵌套調用的復雜變化,細心點,分析就能明白具體的代碼順序。

函數作用域

除了全局變量,其他變量只能在自己的函數內部被訪問到,其他區域無法訪問。通過幾個面試題來學習一下。

  • 第一道面試題
var a = 1 function f1(){alert(a) // 是多少var a = 2 } f1.call() 復制代碼

問:alert出什么東西?

這種題切忌上去就做,容易打錯成了 a是2 一定要先把變量提升。變成如下這樣的

var a = 1 function f1(){var a alert(a) a = 2 } f1.call() 復制代碼

這樣一提升就知道啦,答案:a是undefined

  • 第二道面試題
var a = 1 function f1(){var a = 2f2.call() } function f2(){console.log(a) // 是多少 } f1.call() 復制代碼

問:a是多少

這個題用就近原則好做。

用樹形結構來分析,當上面的代碼被瀏覽器渲染之后

  • 全局變量里面有:var a = 1,f1、f2函數
  • f1函數作用域里面又重新聲明了一個var a = 2
  • f2函數作用域里面是console.log(a)

所以打印的那個a就是全局的a,答案是a=1

總結

以上是生活随笔為你收集整理的初探JS的函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。