概念:函數(shù)是一塊js代碼塊俺孙,被定義一次但可以執(zhí)行和調(diào)用多次辣卒,js中的函數(shù)也是對(duì)象可以像其他對(duì)象那樣操作和執(zhí)行,js函數(shù)也被稱(chēng)為函數(shù)對(duì)象睛榄。
一荣茫、調(diào)用方式和返回值:(foo)
調(diào)用方式:直接調(diào)用foo()、對(duì)象的方法o.method()场靴、構(gòu)造器new Foo()啡莉、call/apply/bind。
1旨剥、一般的調(diào)用函數(shù)的返回值依賴(lài)于return 語(yǔ)句咧欣,若沒(méi)有return語(yǔ)句 將在代碼執(zhí)行完后返回undefined;
2泞边、函數(shù)作為構(gòu)造函數(shù)(使用new調(diào)用)该押,如果沒(méi)有return語(yǔ)句疗杉,或者return后是基本數(shù)據(jù)類(lèi)型阵谚,會(huì)將this作為返回值蚕礼;反之如果return了對(duì)象,則以此對(duì)象為返回值梢什。
二奠蹬、關(guān)于this:
this是js中的一個(gè)關(guān)鍵字:它代表函數(shù)運(yùn)行時(shí),自動(dòng)生成的一個(gè)內(nèi)部對(duì)象嗡午。在不同是使用場(chǎng)景下囤躁,this的值會(huì)發(fā)生變化。但是有一個(gè)總的原則荔睹,那就是this指的是狸演,調(diào)用函數(shù)的那個(gè)對(duì)象
1、this如何被創(chuàng)建僻他、以及如何指向
如何被創(chuàng)建:在每一次function被執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)內(nèi)部對(duì)象宵距,其中的信息包括: 傳入了哪些參數(shù), 函數(shù)是如何調(diào)用(invoked)的, 函數(shù)是在哪里被調(diào)用(called)的,等等。該對(duì)象中還有一個(gè)重要的屬性是?this?引用, 函數(shù)是哪個(gè)對(duì)象的方法吨拗,this?就會(huì)自動(dòng)綁定到該對(duì)象满哪。
指向誰(shuí):在function中this的指向和上下文有關(guān)(context,?函數(shù)在調(diào)用時(shí)刻所處的環(huán)境)劝篷,this?的作用域(scope) 與函數(shù)定義的位置沒(méi)有關(guān)系, 而是取決于函數(shù)在哪里被調(diào)用哨鸭。
測(cè)試如下:
每一行JavaScript代碼都是在執(zhí)行上下文(execution context)中運(yùn)行的。this?指向的對(duì)象在每次進(jìn)入新的執(zhí)行上下文后是固定的, 直到跳轉(zhuǎn)(shifted)到另一個(gè)不同的上下文才發(fā)生改變哈恰。決定執(zhí)行上下文(以及?this?的綁定)需要我們?nèi)フ页稣{(diào)用點(diǎn)(call-site), 調(diào)用點(diǎn)即函數(shù)在代碼中調(diào)用的位置坟桅。
2、不同情景下的this指向:
a蕊蝗、全局模式下和一般函數(shù)調(diào)用:
全局模式下的this指向window: this === window仅乓;
一般函數(shù)調(diào)用:
function simpleCall(){
? console.log(this);
}
simpleCall();
// output: the Window object? ??
在這種情況下,this值沒(méi)有被 call 設(shè)置。因?yàn)榇a不是運(yùn)行在嚴(yán)格模式下,?this?又必須是一個(gè)對(duì)象, 所以他的值默認(rèn)為全局對(duì)象蓬戚。
如果是在嚴(yán)格模式(strict mode)下, 進(jìn)入執(zhí)行上下文時(shí)設(shè)置為什么值那就是什么值夸楣。如果沒(méi)有指定, 那么就一直是undefined
function simpleCall(){
? "use strict";
? console.log(this);
}
simpleCall();
// output: undefined
b、作為對(duì)象方法被調(diào)用時(shí):
將函數(shù)保存為對(duì)象的屬性, 這樣就轉(zhuǎn)化為一個(gè)方法, 可以通過(guò)對(duì)象調(diào)用這個(gè)方法子漩。當(dāng)函數(shù)被當(dāng)成對(duì)象的方法來(lái)調(diào)用時(shí), 里面的?this?值就被設(shè)置為調(diào)用方法的對(duì)象豫喧。
c、構(gòu)造函數(shù)中的this
當(dāng)函數(shù)被new關(guān)鍵字 來(lái)調(diào)用時(shí)涉兽,該函數(shù)將不在是一個(gè)普通函數(shù)而成為了一個(gè)函數(shù)構(gòu)造器(也就是一個(gè)對(duì)象工廠)虱饿,與普通函數(shù)和對(duì)象方法不同的是拥诡,構(gòu)造器調(diào)用會(huì)傳入一個(gè)全新的對(duì)象來(lái)作為this的值, 并且隱式地返回新構(gòu)造的這個(gè)對(duì)象作為結(jié)果(簡(jiǎn)言之, 新構(gòu)造對(duì)象的內(nèi)存是 new 操作符分配的, 構(gòu)造函數(shù)只是做了一些初始化工作)氮发。
當(dāng)一個(gè)函數(shù)作為構(gòu)造器使用時(shí)(通過(guò)?new?關(guān)鍵字), 它的?this?值綁定到新創(chuàng)建的那個(gè)對(duì)象渴肉。如果沒(méi)使用?new?關(guān)鍵字, 那么他就只是一個(gè)普通的函數(shù),?this?將指向?window?對(duì)象。
function Message(content){
? this.content = content;
? this.showContent = function(){
? ? console.log(this.content);
? };
}
var message = new Message("I'm JavaScript!");
message.showContent();
// output: I'm JavaScript!
在上面的示例中, 有一個(gè)名為?Message()?的構(gòu)造函數(shù)爽冕。通過(guò)使用?new?操作符創(chuàng)建了一個(gè)全新的對(duì)象,名為?message。同時(shí)還通傳給構(gòu)造函數(shù)一個(gè)字符串, 作為新對(duì)象的content屬性迁霎。通過(guò)最后一行代碼中可以看到這個(gè)字符串成功地打印出來(lái)了, 因?yàn)?this?指向的是新創(chuàng)建的對(duì)象, 而不是構(gòu)造函數(shù)本身考廉。
d、原型鏈上的this
e、call和apply:
在JavaScript中,所有的函數(shù)都是對(duì)象, 因此函數(shù)也可以有自己的方法。所有的函數(shù)都有的兩個(gè)方法敷钾, 是?apply()?和?call(). 侨赡。我們可以通過(guò)這兩個(gè)方法來(lái)改變函數(shù)的上下文, 在任何時(shí)候都有效, 用來(lái)顯式地設(shè)置?this?的值眨攘。
apply()?方法接收兩個(gè)參數(shù): 第一個(gè)是要設(shè)置為?this?的那個(gè)對(duì)象, 第二個(gè)參數(shù)是可選的共螺,如果要傳入?yún)?shù), 則封裝為數(shù)組作為?apply()?的第二個(gè)參數(shù)即可该肴。
call()?方法 和?apply()?基本上是一樣的, 除了后面的參數(shù)不是數(shù)組, 而是分散開(kāi)一個(gè)一個(gè)地附加在后面藐不。
測(cè)試如下:
f:bind方法:
bind方法有es5提供匀哄,bind()方法會(huì)創(chuàng)建一個(gè)新函數(shù),稱(chēng)為綁定函數(shù)雏蛮,當(dāng)調(diào)用這個(gè)綁定函數(shù)時(shí)涎嚼,綁定函數(shù)會(huì)以創(chuàng)建它時(shí)傳入?bind()方法的第一個(gè)參數(shù)作為?this,傳入?bind()?方法的第二個(gè)以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時(shí)本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來(lái)調(diào)用原函數(shù)挑秉。
測(cè)試如下: