目錄
1 函數(shù)的定義方式
1.1 函數(shù)聲明
1.2 函數(shù)表達(dá)式
1.3 函數(shù)聲明與函數(shù)表達(dá)式的區(qū)別
1.4 構(gòu)造函數(shù)Function(了解即可,一般不用)
2 函數(shù)的調(diào)用方式
3 函數(shù)內(nèi) this 的指向
4 call、apply、bind
4.1 call,apply
4.1.1 新的函數(shù)調(diào)用方式apply和call方法
4.1.2 apply和call可以改變this的指向
4.2 call,apply使用
4.3 bind
4.4 總結(jié)
5 函數(shù)的其它成員(了解)
6 高階函數(shù)
6.1 作為參數(shù)
6.2 作為返回值
7 總結(jié)
1 函數(shù)的定義方式
定義函數(shù)的方式有三種:
-
函數(shù)聲明
-
函數(shù)表達(dá)式
-
new Function
(一般不用)
1.1 函數(shù)聲明
-
-
-
console.log("我是JS中的一等公民-函數(shù)!!!哈哈");
-
-
1.2 函數(shù)表達(dá)式
函數(shù)表達(dá)式就是將一個匿名函數(shù)賦值給一個變量。函數(shù)表達(dá)式必須先聲明,再調(diào)用。
-
-
-
console.log("我是JS中的一等公民-函數(shù)!!!哈哈");
-
-
1.3 函數(shù)聲明與函數(shù)表達(dá)式的區(qū)別
-
函數(shù)聲明必須有名字。
-
函數(shù)聲明會函數(shù)提升,在預(yù)解析階段就已創(chuàng)建,聲明前后都可以調(diào)用。
-
函數(shù)表達(dá)式類似于變量賦值。
-
函數(shù)表達(dá)式可以沒有名字,例如匿名函數(shù)。
-
函數(shù)表達(dá)式?jīng)]有變量提升,在執(zhí)行階段創(chuàng)建,必須在表達(dá)式執(zhí)行之后才可以調(diào)用。
下面是一個根據(jù)條件定義函數(shù)的例子:
-
-
-
-
-
-
-
-
-
以上代碼執(zhí)行結(jié)果在不同瀏覽器中結(jié)果不一致。我們可以使用函數(shù)表達(dá)式解決上面的問題:
-
-
-
-
-
-
-
-
-
-
-
函數(shù)聲明如果放在if-else的語句中,在IE8的瀏覽器中會出現(xiàn)問題,所以為了更好的兼容性我們以后最好用函數(shù)表達(dá)式,不用函數(shù)聲明的方式。
1.4 構(gòu)造函數(shù)Function(了解即可,一般不用)
在前面的學(xué)習(xí)中我們了解到函數(shù)也是對象。注意:函數(shù)是對象,對象不一定是函數(shù),對象中有__proto__原型,函數(shù)中有prototype原型,如果一個東西里面有prototype,又有__proto__,說明它是函數(shù),也是對象。
-
-
-
-
-
對象都是由構(gòu)造函數(shù)創(chuàng)建出來的,函數(shù)既然是對象,創(chuàng)建它的構(gòu)造函數(shù)又是什么呢?事實上所有的函數(shù)實際上都是由Function構(gòu)造函數(shù)創(chuàng)建出來的實例對象。
所以我們可以使用Function構(gòu)造函數(shù)創(chuàng)建函數(shù)。
語法:new Function(arg1,arg2,arg3..,body);
arg是任意參數(shù),字符串類型的。body是函數(shù)體。
-
-
var f1 = new Function("num1", "num2", "return num1+num2");
-
-
console.log(f1.__proto__ == Function.prototype);
-
-
-
-
2 函數(shù)的調(diào)用方式
-
普通函數(shù)
-
構(gòu)造函數(shù)
-
對象方法
-
-
-
console.log("我是普通函數(shù)");
-
-
-
-
-
-
console.log("我是構(gòu)造函數(shù)");
-
-
-
-
-
-
-
-
-
-
-
3 函數(shù)內(nèi) this
的指向
函數(shù)的調(diào)用方式?jīng)Q定了 this
指向的不同:
調(diào)用方式
|
非嚴(yán)格模式
|
備注
|
普通函數(shù)調(diào)用
|
window
|
嚴(yán)格模式下是 undefined
|
構(gòu)造函數(shù)調(diào)用
|
實例對象
|
原型方法中 this 也是實例對象
|
對象方法調(diào)用
|
該方法所屬對象
|
緊挨著的對象
|
事件綁定方法
|
綁定事件對象
|
|
定時器函數(shù)
|
window
|
|
-
-
-
-
-
-
-
-
-
-
-
this.sayHi = function() {
-
-
-
-
-
Person.prototype.eat = function() {
-
-
-
-
-
-
-
-
-
-
-
4 call、apply、bind
了解了函數(shù) this 的指向之后,我們知道在一些情況下我們?yōu)榱耸褂媚撤N特定環(huán)境的 this 引用,需要采用一些特殊手段來處理,例如我們經(jīng)常在定時器外部備份 this 引用,然后在定時器函數(shù)內(nèi)部使用外部 this 的引用。
然而實際上 JavaScript 內(nèi)部已經(jīng)專門為我們提供了一些函數(shù)方法,用來幫我們更優(yōu)雅的處理函數(shù)內(nèi)部 this 指向問題。這就是接下來我們要學(xué)習(xí)的 call、apply、bind 三個函數(shù)方法。call()、apply()、bind()這三個方法都是是用來改變this的指向的。
4.1 call,apply
call()
方法調(diào)用一個函數(shù), 其具有一個指定的 this
值和分別地提供的參數(shù)(參數(shù)的列表)。
apply()
方法調(diào)用一個函數(shù), 其具有一個指定的 this
值,以及作為一個數(shù)組(或類似數(shù)組的對象)提供的參數(shù)。
注意:call()
和 apply()
方法類似,只有一個區(qū)別,就是 call()
方法接受的是若干個參數(shù)的列表,而 apply()
方法接受的是一個包含多個參數(shù)的數(shù)組。
call語法:
fun.call(thisArg[, arg1[, arg2[, ...]]])
call參數(shù):
-
thisArg
-
在 fun 函數(shù)運行時指定的 this 值
-
如果指定了 null 或者 undefined 則內(nèi)部 this 指向 window
-
arg1, arg2, ...
apply語法:
fun.apply(thisArg, [argsArray])
apply參數(shù):
apply()
與 call()
相似,不同之處在于提供參數(shù)的方式。
apply()
使用參數(shù)數(shù)組而不是一組參數(shù)列表。例如:
fun.apply(this, ['eat', 'bananas'])
4.1.1 新的函數(shù)調(diào)用方式apply和call方法
-
-
console.log("結(jié)果是:" + (x + y) + this);
-
-
-
-
-
-
-
-
-
-
f1.apply(null, [10, 20]);
-
-
-
-
var result1 = f1.apply(null, [10, 20]);
-
var result2 = f1.call(null, 10, 20);
-
-
4.1.2 apply和call可以改變this的指向
-
-
function Person(name, sex) {
-
-
-
-
-
Person.prototype.sayHi = function(x, y) {
-
console.log("您好啊:" + this.name);
-
-
-
var per = new Person("小三", "男");
-
var r1 = per.sayHi(10, 20);
-
-
console.log("==============");
-
-
function Student(name, age) {
-
-
-
-
var stu = new Student("小舞", 18);
-
var r2 = per.sayHi.apply(stu, [10, 20]);
-
var r3 = per.sayHi.call(stu, 10, 20);
-
-
-
-
4.2 call,apply使用
apply和call都可以改變this的指向。調(diào)用函數(shù)的時候,改變this的指向:
-
-
-
console.log((x + y) + ":===>" + this);
-
-
-
-
var r1 = f1.apply(null, [1, 2]);
-
-
var r2 = f1.call(null, 1, 2);
-
-
console.log("=============>");
-
-
-
-
-
-
var r3 = f1.apply(obj, [1, 2]);
-
-
var r4 = f1.call(obj, 1, 2);
-

調(diào)用方法的時候,改變this的指向:
-
-
-
-
-
Person.prototype.sayHi = function(x, y) {
-
console.log((x + y) + ":====>" + this.age);
-
-
-
-
-
-
var per = new Person(10);
-
var stu = new Student(100);
-
-
-
per.sayHi.apply(stu, [10, 20]);
-
per.sayHi.call(stu, 10, 20);
總結(jié)
apply的使用語法:
1 函數(shù)名字.apply(對象,[參數(shù)1,參數(shù)2,...]);
2 方法名字.apply(對象,[參數(shù)1,參數(shù)2,...]);
call的使用語法
1 函數(shù)名字.call(對象,參數(shù)1,參數(shù)2,...);
2 方法名字.call(對象,參數(shù)1,參數(shù)2,...);
它們的作用都是改變this的指向,不同的地方是參數(shù)傳遞的方式不一樣。
如果想使用別的對象的方法,并且希望這個方法是當(dāng)前對象的,就可以使用apply或者是call方法改變this的指向。
4.3 bind
bind() 函數(shù)會創(chuàng)建一個新函數(shù)(稱為綁定函數(shù)),新函數(shù)與被調(diào)函數(shù)(綁定函數(shù)的目標(biāo)函數(shù))具有相同的函數(shù)體(在 ECMAScript 5 規(guī)范中內(nèi)置的call屬性)。當(dāng)目標(biāo)函數(shù)被調(diào)用時 this 值綁定到 bind() 的第一個參數(shù),該參數(shù)不能被重寫。綁定函數(shù)被調(diào)用時,bind() 也可以接受預(yù)設(shè)的參數(shù)提供給原函數(shù)。一個綁定函數(shù)也能使用new操作符創(chuàng)建對象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。提供的 this 值被忽略,同時調(diào)用時的參數(shù)被提供給模擬函數(shù)。
bind方法是復(fù)制的意思,本質(zhì)是復(fù)制一個新函數(shù),參數(shù)可以在復(fù)制的時候傳進(jìn)去,也可以在復(fù)制之后調(diào)用的時候傳入進(jìn)去。apply和call是調(diào)用的時候改變this指向,bind方法,是復(fù)制一份的時候,改變了this的指向。
語法:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
參數(shù):
-
thisArg
-
當(dāng)綁定函數(shù)被調(diào)用時,該參數(shù)會作為原函數(shù)運行時的 this 指向。當(dāng)使用new 操作符調(diào)用綁定函數(shù)時,該參數(shù)無效。
-
arg1, arg2, ...
-
當(dāng)綁定函數(shù)被調(diào)用時,這些參數(shù)將置于實參之前傳遞給被綁定的方法。
返回值:
返回由指定的this值和初始化參數(shù)改造的原函數(shù)的拷貝。
示例1:
-
-
-
-
Person.prototype.play = function() {
-
console.log(this + "====>" + this.name);
-
-
-
-
-
-
var per = new Person("人");
-
var stu = new Student("學(xué)生");
-
-
-
var ff = per.play.bind(stu);
-
示例2:
-
-
-
-
this.number = parseInt(Math.random() * 10 + 1);
-
-
-
ShowRandom.prototype.show = function() {
-
-
window.setTimeout(function() {
-
-
-
console.log(this.number);
-
-
-
-
var sr = new ShowRandom();
-
-
4.4 總結(jié)
-
call 和 apply 特性一樣
-
都是用來調(diào)用函數(shù),而且是立即調(diào)用
-
但是可以在調(diào)用函數(shù)的同時,通過第一個參數(shù)指定函數(shù)內(nèi)部
this
的指向
-
call 調(diào)用的時候,參數(shù)必須以參數(shù)列表的形式進(jìn)行傳遞,也就是以逗號分隔的方式依次傳遞即可
-
apply 調(diào)用的時候,參數(shù)必須是一個數(shù)組,然后在執(zhí)行的時候,會將數(shù)組內(nèi)部的元素一個一個拿出來,與形參一一對應(yīng)進(jìn)行傳遞
-
如果第一個參數(shù)指定了
null
或者 undefined
則內(nèi)部 this 指向 window
-
bind
-
可以用來指定內(nèi)部 this 的指向,然后生成一個改變了 this 指向的新的函數(shù)
-
它和 call、apply 最大的區(qū)別是:bind 不會調(diào)用
-
bind 支持傳遞參數(shù),它的傳參方式比較特殊,一共有兩個位置可以傳遞
-
在 bind 的同時,以參數(shù)列表的形式進(jìn)行傳遞
-
在調(diào)用的時候,以參數(shù)列表的形式進(jìn)行傳遞
-
那到底以 bind 的時候傳遞的參數(shù)為準(zhǔn)呢?還是以調(diào)用的時候傳遞的參數(shù)為準(zhǔn)呢?
-
兩者合并:bind 的時候傳遞的參數(shù)和調(diào)用的時候傳遞的參數(shù)會合并到一起,傳遞到函數(shù)內(nèi)部。
5 函數(shù)的其它成員(了解)
-
arguments
-
caller
-
length
-
name
-
函數(shù)的名字,name屬性是只讀的,不能修改
-
-
-
-
console.log(arguments.callee === fn)
-
-
-
-
-
-
-
-
-
6 高階函數(shù)
函數(shù)可以作為參數(shù),也可以作為返回值。
6.1 作為參數(shù)
函數(shù)是可以作為參數(shù)使用,函數(shù)作為參數(shù)的時候,如果是命名函數(shù),那么只傳入命名函數(shù)的名字,沒有括號。
-
-
console.log("我是函數(shù)f1");
-
-
-
-
-
-
console.log("我是匿名函數(shù)");
-
-
-
-
console.log("我是函數(shù)f2");
-
-

作為參數(shù)排序案例:
-
var arr = [1, 100, 20, 200, 40, 50, 120, 10];
-
-
arr.sort(function(obj1, obj2) {
-
-
-
} else if (obj1 == obj2) {
-
-
-
-
-
-
6.2 作為返回值
-
-
console.log("函數(shù)f1");
-
-
console.log("我是函數(shù),此時作為返回值使用");
-
-
-
-
-
-
作為返回值排序案例:
-
-
-
function File(name, size, time) {
-
-
-
-
-
var f1 = new File("jack.avi", "400M", "1999-12-12");
-
var f2 = new File("rose.avi", "600M", "2020-12-12");
-
var f3 = new File("albert.avi", "800M", "2010-12-12");
-
-
-
-
-
return function getSort(obj1, obj2) {
-
if (obj1[attr] > obj2[attr]) {
-
-
} else if (obj1[attr] == obj2[attr]) {
-
-
-
-
-
-
-
console.log("按照名字排序:**********");
-
-
-
-
-
for (var i = 0; i < arr.length; i++) {
-
console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);
-
-
-
console.log("按照大小排序:**********");
-
-
-
-
-
for (var i = 0; i < arr.length; i++) {
-
console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);
-
-
-
console.log("按照創(chuàng)建時間排序:**********");
-
-
-
-
-
for (var i = 0; i < arr.length; i++) {
-
console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);
-
-