JS函數(shù)對(duì)象

函數(shù)的定義與要素

函數(shù)定義

  • 具名函數(shù)
    function 函數(shù)名(形式參數(shù)1,形式參數(shù)2){
    語(yǔ)句
    return 返回值
    }
  • 匿名函數(shù)
    去掉函數(shù)名就是匿名函數(shù)
    聲明一個(gè)變量把它賦值為函數(shù)表達(dá)式邢锯,a只是容納了它的地址
    let a = function(x,y){return x+y}
    聲明變量=函數(shù)表達(dá)式
  • 箭頭函數(shù)
    let f1 = x => x乘x //x是輸入右邊是輸出
    let f2 = (x,y)=>x*y // 多個(gè)參數(shù)
    let f3 = (x,y)=>{console.log('hi')
    return x+y}如果有花括號(hào)需要寫return
    接受一個(gè)值x 返回一個(gè)對(duì)象
    花括號(hào)優(yōu)先被認(rèn)成塊作用域扬蕊,必須加個(gè)小括號(hào)告訴他是一個(gè)對(duì)象
    let f4 = x =>({name:x})
  • 構(gòu)造函數(shù)(所有函數(shù)都是Function構(gòu)造出來(lái)的包括Object/Array/Function)
    let f = new Function('x','y','return x + y')
  • fn和fn()
    fn是函數(shù)自身,
    fn()調(diào)用函數(shù)

函數(shù)要素

  • 調(diào)用時(shí)機(jī)
  • 作用域
  • 閉包
  • 形式參數(shù)
  • 返回值
  • 調(diào)用棧
  • 函數(shù)提升
  • arguments(箭頭函數(shù)除外)
  • this(箭頭函數(shù)除外)
  • call指定this
  • 立即執(zhí)行函數(shù)

調(diào)用時(shí)機(jī)

時(shí)機(jī)不同 結(jié)果不同

let a = 1
function fn(){
  setTimeout(()=>{
    console.log(a)
  },0)
}
fn()
a=2
打印出2
let i = 0
for(i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}
打印出6個(gè)6

為什么明明setTimeout的時(shí)間設(shè)置為了0丹擎,還是打印出6個(gè)6厨相?
在 js 中,定時(shí)器是一個(gè)異步任務(wù)鸥鹉。 JS 會(huì)優(yōu)先執(zhí)行當(dāng)前的同步任務(wù)蛮穿,在同步代碼執(zhí)行結(jié)束后才會(huì)去處理任務(wù)隊(duì)列中的異步任務(wù)。這樣毁渗,即便定時(shí)器設(shè)置了0践磅,也是在忙完手頭的事情之后才會(huì)去讀取任務(wù)隊(duì)列。
JS 有同步任務(wù)和異步任務(wù)灸异。
同步任務(wù):在主線程上排隊(duì)執(zhí)行的任務(wù)府适,只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù)肺樟;
異步任務(wù)指:不進(jìn)入主線程檐春、而進(jìn)入"任務(wù)隊(duì)列"的任務(wù),只有"任務(wù)隊(duì)列"通知主線程么伯,某個(gè)異步任務(wù)可以執(zhí)行了疟暖,該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行。

for(let i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    });
}JS在for和let一起用的時(shí)候加了一些東西所以
打印出 0 1 2 3 4田柔,
每次循環(huán)會(huì)多創(chuàng)建一個(gè)i

作用域

每個(gè)函數(shù)都會(huì)創(chuàng)建一個(gè)作用域

function fn(){
  let a = 1
}
console.log(a)//a 不存在俐巴,訪問(wèn)不到作用域里面的a
let 作用域就在它最近的花括號(hào)里

全局變量:

  • 在頂級(jí)作用域聲明的變量是全局變量
  • 掛到window上的屬性是全局變量
    比如Object可以直接用,也可以自己寫window.c=xxx硬爆。

局部變量:

  • 函數(shù)里聲明lety或const就是一個(gè)局部變量欣舵,出了作用域不生效。

作用域規(guī)則:
如果多個(gè)作用域有同名的變量a

  • 查找a的聲明時(shí)缀磕,向上取最近的作用域(就近原則)
  • 查找a的過(guò)程與函數(shù)執(zhí)行無(wú)關(guān),但a的值與函數(shù)的執(zhí)行有關(guān)缘圈。

靜態(tài)作用域:

  • 函數(shù)的作用域在函數(shù)定義時(shí)就已經(jīng)確定了劣光,跟函數(shù)執(zhí)行沒(méi)有關(guān)系。
  • 函數(shù)的作用域在運(yùn)行時(shí)才確定糟把,跟函數(shù)執(zhí)行有關(guān)系赎线。
var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();
}
bar();

JavaScript采用靜態(tài)作用域的方式訪問(wèn)變量,所以打印出1.
JavaScript之靜態(tài)作用域 - 簡(jiǎn)書 (jianshu.com)

閉包:JS函數(shù)會(huì)就近尋找最近的變量

function f1(){
  let a = 1
  function f2(){
    let a = 2
    function f3(){
      console.log(a)
    }
    a = 22
    f3()
  }
  console.log(a)
  a = 100
  f2()
}
f1()

如果一個(gè)函數(shù)用到了外部的變量,那么這個(gè)函數(shù)加這個(gè)變量就叫做閉包糊饱。上面f2中的a和f3組成閉包垂寥。

形式參數(shù)

形式參數(shù)的意思就是非實(shí)際參數(shù)

let a = 1
let b =2
function add(x, y){
  x+1
  y+2
  return x+y
}
其中x和y就是形參,因?yàn)椴⒉皇菍?shí)際的參數(shù)
add(a,b)
調(diào)用 add 時(shí)另锋,a 和 b 是實(shí)際參數(shù)滞项,會(huì)被賦值給 x y
  • JS傳參
    傳值:在上面的代碼中,a和b在賦值給x夭坪、y的時(shí)候文判,會(huì)被復(fù)制一份傳進(jìn)去。函數(shù)中對(duì)形參的修改并不會(huì)影響到實(shí)際參數(shù)本身室梅。函數(shù)執(zhí)行完后還是a =1 b =2戏仓。
    傳址:但是傳遞的參數(shù)時(shí)對(duì)象時(shí)。此時(shí)傳進(jìn)去的就是對(duì)象的地址亡鼠,對(duì)對(duì)象做出的修改會(huì)影響到對(duì)象本身赏殃。
    其實(shí)無(wú)所謂傳值和傳址。就是把stack內(nèi)存中的東西復(fù)制過(guò)去而已间涵。

形參可認(rèn)為是變量聲明仁热。上面代碼近似等價(jià)于下面代碼。

function add(){
  var x=arguments[0]//參數(shù)的第0個(gè)
  var y=arguments[1]
  return x+y
}

返回值

  • 每個(gè)函數(shù)都有返回值
    function hi(){console.log('hi') }
    hi()
    沒(méi)寫return勾哩,所以返回值是undefined
    function hi(){ return console.log('hi')}
    hi()
    返回值為console.log('hi')的值抗蠢,即undefined
  • 函數(shù)執(zhí)行完了后才會(huì)返回
  • 只有函數(shù)有返回值
    錯(cuò)誤:1+2返回值為3
    正確:1+2值為3

調(diào)用棧

什么是調(diào)用棧

  • JS引擎在調(diào)用一個(gè)函數(shù)前
  • 需要把函數(shù)所在的環(huán)境push到一個(gè)數(shù)組里
  • 這個(gè)數(shù)組叫做調(diào)用棧
  • 等函數(shù)執(zhí)行完了,就會(huì)把環(huán)境彈(pop)出來(lái)
  • 然后return到之前的環(huán)境思劳,繼續(xù)執(zhí)行后續(xù)代碼

作用:

  • 由于我每次進(jìn)入一個(gè)函數(shù)我都得記下來(lái)我等會(huì)回到哪迅矛,所以把回到的地址寫到棧里邊。如果進(jìn)入一個(gè)函數(shù)之后還要進(jìn)入一個(gè)函數(shù)潜叛,就再把這個(gè)地址放到棧里邊秽褒,函數(shù)執(zhí)行完了就彈棧 。

舉例

function first() {
 console.log('first')
 function second() {
     console.log("second")
 }
 second();
 third();
}

function third() {
    console.log("third")
}
// 調(diào)用 first
first();

調(diào)用的是函數(shù) first, 此時(shí) first 進(jìn)入函數(shù)棧钠导,接著在 first 中調(diào)用函數(shù) second,second 入棧震嫉,當(dāng) second 執(zhí)行完畢后森瘪,second 出棧牡属,third 入棧,接著 third 執(zhí)行完出棧扼睬,執(zhí)行 first 其他代碼逮栅,直至 first 執(zhí)行完悴势,函數(shù)棧清空。


調(diào)用棧

遞歸函數(shù):

階乘
function f(n){
  return n !==1 ? n*f(n-1) : 1 
}

f(4)
= 4 * f(3)
= 4 * (3 * f(2))
= 4 * (3 * (2 * f(1)))
= 4 * (3 * (2* (1)))
= 4 * (3 * (2))
= 4 * (6)
=24
先遞進(jìn)措伐,后回歸
  • 遞歸的調(diào)用棧
    1特纤、進(jìn)入f(4)并壓棧
    2、得到4 * f(3) 進(jìn)入f(3)并壓棧(把4也記錄下來(lái))
    3侥加、得到3 * f(2) 進(jìn)入f(2)并壓棧(把3
    也記錄下來(lái))
    4捧存、得到2* (1)進(jìn)入f(1)并壓棧(把2也記錄下來(lái))
    5、得到1
    6担败、彈棧2
    得到2
    7昔穴、彈棧3得到6
    8、彈棧4
    得到24
    9提前、彈椔鸹酰回到第一行
  • 我們可以看到f(4)壓棧4次
  • 所以f(10000)壓棧10000次

爆棧:如果調(diào)用棧中壓入的幀過(guò)多,程序就會(huì)崩潰

棧的長(zhǎng)度:

function computeMaxCallStackSize(){
  try{
    return  1+ computeMaxCallStackSize()
   }catch(e){
//報(bào)錯(cuò)說(shuō)明 stack overflow
    return 1
  }
}

函數(shù)提升

定義:
不管你把具名函數(shù)function fn(){}聲明在哪里狈网,它都會(huì)跑到第一行宙搬。

這種不行
let fn = function(){}
這是賦值,右邊的匿名函數(shù)聲明不會(huì)提升

let不允許有一個(gè)函數(shù)add的時(shí)候再聲明一個(gè)add,var可以:

let add = 1
function add(){}
報(bào)錯(cuò)
var add = 1
function add(){}
console.log(add)
此時(shí)add是1

arguments和this

每個(gè)函數(shù)都有拓哺,除了箭頭函數(shù)

argements:

  • 包含所有參數(shù)的偽數(shù)組
  • 通過(guò)array.from 可以把它變?yōu)閿?shù)組
  • 調(diào)用fn即可傳arguments
  • fn(1,2)那么arguments就是【1勇垛,2】偽數(shù)組

打印出來(lái)看一下
function fn(){console.log(arguments)}


arguments

this

  • 打印出來(lái)看一下
    function fn(){console.log(this)}
  • 我們發(fā)現(xiàn)如果單純打印this不給任何條件的情況下this默認(rèn)指向window

如何傳this和arguments

  • 使用fn.call(1,2,3,4)傳this和arguments
    1是this(第一個(gè)參數(shù)) 2,3,4是arguments
  • xxx如果不是對(duì)象JS會(huì)自動(dòng)把他轉(zhuǎn)化成對(duì)象(JS糟粕)
  • 在函數(shù)中加'use strick'即可制止
    自動(dòng)轉(zhuǎn)成對(duì)對(duì)象

    use strick

    this要解決的問(wèn)題:
  • 我們寫一個(gè)函數(shù)的時(shí)候需要得到一個(gè)對(duì)象
  • 但是不知道對(duì)象的名字,可能那個(gè)對(duì)象還沒(méi)出生
  • 怎樣在不知道一個(gè)對(duì)象的名字情況下拿到對(duì)象的引用
let sayHi = function(){
  console.log(person.name)
}
我在寫這個(gè)函數(shù)之前我怎么能確定后面這個(gè)變量是person呢
let person = {
  name:'frank',
  'sayHi':sayHi
}
如果我person改名字了士鸥,sayHi函數(shù)就掛了
sayHi甚至可能在另一個(gè)文件中
所以我們不希望sayHi函數(shù)出現(xiàn)person的引用
class Person{
  constructor(name){
    this.name = name//這里this強(qiáng)制指定的
  }
  sayHi(){
    console.log(???)
  }
}
這里只有類窥摄,還沒(méi)有創(chuàng)建對(duì)象,故不可能拿到對(duì)象的引用

JS是如何解決問(wèn)題的

  • JS在每個(gè)函數(shù)里加了this
  • 在任何函數(shù)里面可以用this獲取那個(gè)你目前還不知道名字的對(duì)象
let person = {
  name:'frank',
  sayHi(){
    console.log(this.name)
這里的this就表示以后出現(xiàn)的那個(gè)對(duì)象
  }
}
  • person.sayHi()相當(dāng)于person.sayHi(person)然后person地址被傳給了this
  • person.sayHi()會(huì)隱式地把person作為this傳給sayHI础淤,方便sayHi獲取person對(duì)應(yīng)的對(duì)象

函數(shù)的兩種調(diào)用方法

  • person.sayHi()會(huì)自動(dòng)把person傳到函數(shù)里作為this
  • person.sayHi.call(person)手動(dòng)把person傳到函數(shù)里作為this(推薦)

call指定this

call

this寫foreach

foreach

1

2

默認(rèn)把a(bǔ)rray當(dāng)作this

真foreach中
foreach

this就是一個(gè)參數(shù)而已崭放,我傳什么就是什么默認(rèn)就是array

this的兩種使用方法

  • 隱式傳遞
    fn(1,2)=== fn.call(undefined,1,2)
    obj.child.fn(1) ===等價(jià)于obj.child.fn.call(obj,child,1)
  • 顯示傳遞 call apply
    fn.call(undefined,1,2)
    fn.apply(undefined,[1,2])

bind綁定this

function f1(p1,p2){
  console.log(this,p1,p2)
}
let f2 = f1.bind({name:'frank'})
f2就是f1綁定了this之后的新函數(shù)
f2()===f1.call({name:'frank'})

其他參數(shù)
let f3 = f1.bind({name:'frank'},'hi')
f2()===f1.call({name:'frank'},'hi')

箭頭函數(shù)

沒(méi)有arguments和this
箭頭函數(shù)里面的this就是外面的this加call也沒(méi)用

  • console.log(this) //this是window
  • let a = ()=> console.log(this)
    a() //還是window
  • a.call(1) //還是window

立即執(zhí)行函數(shù)(沒(méi)啥用)

  • 以前只有var的時(shí)候 如果想聲明一個(gè)局部變量必須在一個(gè)函數(shù)里聲明才是局部(所以現(xiàn)在直接let就好了)
  • 我就想要一個(gè)局部變量不想要全局函數(shù)
  • 采用匿名函數(shù)并直接調(diào)用鸽凶,會(huì)報(bào)錯(cuò)所以前面加個(gè)币砂!


    立即執(zhí)行函數(shù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市玻侥,隨后出現(xiàn)的幾起案子决摧,更是在濱河造成了極大的恐慌,老刑警劉巖凑兰,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掌桩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡姑食,警方通過(guò)查閱死者的電腦和手機(jī)波岛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)音半,“玉大人则拷,你說(shuō)我怎么就攤上這事贡蓖。” “怎么了煌茬?”我有些...
    開封第一講書人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵斥铺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我坛善,道長(zhǎng)晾蜘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任眠屎,我火速辦了婚禮笙纤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘组力。我一直安慰自己省容,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開白布燎字。 她就那樣靜靜地躺著腥椒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪候衍。 梳的紋絲不亂的頭發(fā)上笼蛛,一...
    開封第一講書人閱讀 49,837評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音蛉鹿,去河邊找鬼滨砍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妖异,可吹牛的內(nèi)容都是我干的惋戏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼他膳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼响逢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起棕孙,我...
    開封第一講書人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤舔亭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蟀俊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钦铺,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年肢预,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了矛洞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡误甚,死狀恐怖缚甩,靈堂內(nèi)的尸體忽然破棺而出谱净,到底是詐尸還是另有隱情窑邦,我是刑警寧澤擅威,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站冈钦,受9級(jí)特大地震影響郊丛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞧筛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一厉熟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧较幌,春花似錦揍瑟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至岛琼,卻和暖如春底循,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背槐瑞。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工熙涤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人困檩。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓祠挫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親悼沿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茸歧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)是一個(gè)函數(shù) 定義一個(gè)函數(shù) 具名函數(shù) function 函數(shù)名(參數(shù)1,參數(shù)2){語(yǔ)句return 返回值} 匿...
    陳情閱讀 246評(píng)論 0 2
  • 本節(jié)課主要講解函數(shù)對(duì)象显沈,JS的第二座大山this 其它1.對(duì)象:object對(duì)象软瞎、數(shù)組對(duì)象、函數(shù)對(duì)象(函數(shù)是一種特...
    珍惜時(shí)間小李閱讀 194評(píng)論 0 0
  • 一 函數(shù)預(yù)定義屬性和方法: 二 拉讯、自定義函數(shù)屬性和方法(可以在函數(shù)體內(nèi)或體外定義). 自定義屬性的應(yīng)用:某個(gè)函數(shù)的...
    gis杭州閱讀 443評(píng)論 0 0
  • 1.ES5和ES6的關(guān)于構(gòu)造函數(shù)的區(qū)別 Es6中的class語(yǔ)法就是Es5中構(gòu)造函數(shù)的另一種寫法涤浇,一種更高級(jí)的寫法...
    天馬行空_eaa7閱讀 1,343評(píng)論 0 20
  • 引子 看到這個(gè)代碼境蔼,第一個(gè)反應(yīng)是1扭弧,結(jié)果告訴我是錯(cuò)的。 答案是10!我疑惑條件語(yǔ)句if(!foo)并不會(huì)執(zhí)行洒嗤,為什...
    如夢(mèng)初醒Tel閱讀 1,309評(píng)論 0 4