跟我學(xué)習(xí)javascript的函數(shù)調(diào)用和構(gòu)造函數(shù)調(diào)用
一、函數(shù)調(diào)用
Function絕對(duì)是JavaScript中的重中之重。在JavaScript中,F(xiàn)unction承擔(dān)了procedures, methods, constructors甚至是classes以及modules的功能。
在面向?qū)ο蟪绦蛟O(shè)計(jì)中,functions,methods以及class constructor往往是三件不同的事情,由不同的語(yǔ)法來(lái)實(shí)現(xiàn)。但是在JavaScript中,這三個(gè)概念都由function來(lái)實(shí)現(xiàn),通過(guò)三種不同的模式。
最簡(jiǎn)單的使用模式就是function 調(diào)用:
function hello(username) {
return "hello, " + username;
}
hello("Keyser Söze"); // "hello, Keyser Söze"
二、方法的調(diào)用
而methods這一概念在JavaScript中的表現(xiàn)就是,一個(gè)對(duì)象的屬性是一個(gè)function:同樣的是函數(shù),將其賦值給一個(gè)對(duì)象的成員以后,就不一樣了。將函數(shù)賦值給對(duì)象的成員后,那么這個(gè)就不在稱(chēng)為函數(shù),而應(yīng)該叫做方法。
var obj = {
hello: function() {
return "hello, " + this.username;
},
username: "Hans Gruber"
};
obj.hello(); // "hello, Hans Gruber"
真正的行為是,調(diào)用本身才會(huì)決定this會(huì)綁定到哪個(gè)對(duì)象,即:
obj1.hello()會(huì)將this綁定到obj1,obj2.hello()則會(huì)將this綁定到obj2。記住一句話,誰(shuí)調(diào)用,this就指向誰(shuí)
正因?yàn)閠his綁定的這種規(guī)則,在下面的用法也是可行的:
function hello() {
return "hello, " + this.username;
}
var obj1 = {
hello: hello,
username: "Gordon Gekko"
};
obj1.hello(); // "hello, Gordon Gekko"
var obj2 = {
hello: hello,
username: "Biff Tannen"
};_
obj2.hello(); // "hello, Biff Tannen"
但是,在一個(gè)普通的函數(shù)中,如上面的hello函數(shù),使用this關(guān)鍵字是不太好的方式,當(dāng)它被直接調(diào)用的時(shí)候,this的指向就成了問(wèn)題。在這種情況下,this往往被指向全局對(duì)象(GlobalObject),在瀏覽器上一般就是window對(duì)象。
而這種行為是不確定和沒(méi)有意義的。
所以在ES5標(biāo)準(zhǔn)中,如果使用了strict mode,那么this會(huì)被設(shè)置為undefined:
function hello() {
"use strict";
return "hello, " + this.username;
}
hello(); // error: cannot read property "username" of undefined
以上這種做法是為了讓潛在的錯(cuò)誤更快的暴露出來(lái),避免了誤操作和難以找到的bug。
區(qū)別普通函數(shù)調(diào)用和方法調(diào)用,直接看這個(gè)例子就明確了。
var func = function() {
alert(this);
};
var o = {};
o.fn = func;
// 比較
alert(o.fn === func);//true
// 調(diào)用
func();//[object Window]
o.fn();//[object Object]
這里的運(yùn)行結(jié)果是,兩個(gè)函數(shù)是相同的,因此打印結(jié)果是 true。但是由于兩個(gè)函數(shù)的調(diào)用是不一樣的,func 的調(diào)用,打印的是 [object Window],而o.fn 的打印結(jié)果是 [object Object]。
這里便是函數(shù)調(diào)用與方法調(diào)用的區(qū)別,函數(shù)調(diào)用中,this 專(zhuān)指全局對(duì)象 window,而在方法中 this 專(zhuān)指當(dāng)前對(duì)象,即 o.fn 中的 this 指的就是對(duì)象o。
三、構(gòu)造函數(shù)的調(diào)用
function的第三種使用模式就是講它作為constructor:
構(gòu)造器中的this
我們需要分析創(chuàng)建對(duì)象的過(guò)程,方能知道this的意義. 如下面代碼:
var Person = function() {
this.name = "小平果";
};
var p = new Person();
這里首先定義了函數(shù)Person,下面分析一下整個(gè)執(zhí)行:
- 程序在執(zhí)行到這一句的時(shí)候,不會(huì)執(zhí)行函數(shù)體,因此 JavaScript的解釋器并不知道這個(gè)函數(shù)的內(nèi)容.
- 接下來(lái)執(zhí)行new關(guān)鍵字,創(chuàng)建對(duì)象,解釋器開(kāi)辟內(nèi)存,得到對(duì)象的引用,將新對(duì)象的引用交給函數(shù).
- 緊接著執(zhí)行函數(shù),將傳過(guò)來(lái)的對(duì)象引用交給this. 也就是說(shuō),在構(gòu)造方法中,this就是剛剛被new創(chuàng)建出來(lái)的對(duì)象.
- 然后為this 添加成員,也就是為對(duì)象添加成員.
- 最后函數(shù)結(jié)束,返回this,將this交給左邊的變量.
分析過(guò)構(gòu)造函數(shù)的執(zhí)行以后,可以得到,構(gòu)造函數(shù)中的this就是當(dāng)前對(duì)象.
構(gòu)造器中的return
在構(gòu)造函數(shù)中return的意義發(fā)生了變化,首先如果在構(gòu)造函數(shù)中,如果返回的是一個(gè)對(duì)象,那么就保留原意. 如果返回的是非對(duì)象,比如數(shù)字、布爾和字符串,那么就返回this,如果沒(méi)有return語(yǔ)句,那么也返回this. 看下面代碼:
// 返回一個(gè)對(duì)象的 return
var ctr = function() {
this.name = "趙曉虎";
return {
name:"牛亮亮"
};
};
// 創(chuàng)建對(duì)象
var p = new ctr();
// 訪問(wèn)name屬性
alert(p.name);
//執(zhí)行代碼,這里打印的結(jié)果是"牛亮亮". 因?yàn)闃?gòu)造方法中返回的是一個(gè)對(duì)象,那么保留return的意義,返回內(nèi)容為return后面的對(duì)象. 再看下面代碼:
// 定義返回非對(duì)象數(shù)據(jù)的構(gòu)造器
var ctr = function() {
this.name = "趙曉虎";
return "牛亮亮";
};
// 創(chuàng)建對(duì)象
var p = new ctr();
// 使用
alert(p);
alert(p.name);
代碼運(yùn)行結(jié)果是,先彈窗打印[object Object],然后打印”趙曉虎”. 因?yàn)檫@里 return 的是一個(gè)字符串,屬于基本類(lèi)型,那么這里的return語(yǔ)句無(wú)效,返回的是this對(duì)象. 因此第一個(gè)打印的是[object Object]而第二個(gè)不會(huì)打印undefined.
function User(name, passwordHash) {
this.name = name;
this.passwordHash = passwordHash;
}
var u = new User("sfalken",
"0ef33ae791068ec64b502d6cb0191387");
u.name; // "sfalken"
使用new關(guān)鍵將function作為constructor進(jìn)行調(diào)用。和function以及method調(diào)用不一樣的是,constructor會(huì)傳入一個(gè)新的對(duì)象并將它綁定到this,然后返回該對(duì)象作為constructor的返回值。而constructor function本身的作用就是為了初始化該對(duì)象。
構(gòu)造函數(shù)調(diào)用常犯的一個(gè)錯(cuò)誤
興致勃勃地定義了下面這么個(gè)構(gòu)造函數(shù):
var Coder = function( nick ){
this.nick = nick;
};
定義構(gòu)造函數(shù)結(jié)束后呢?沒(méi)錯(cuò),趕緊實(shí)例化:
var coder = Coder( 'casper' );
這個(gè)coder兄弟叫什么名字?趕緊打印下:
console.log( coder.nick ); //undefined = =b 竟然是undefined??!再回過(guò)頭看看實(shí)例化的那個(gè)語(yǔ)句,不難發(fā)現(xiàn)問(wèn)題出在哪里:少了個(gè)new var coder = Coder( 'casper' ); //當(dāng)作普通的函數(shù)來(lái)調(diào)用,故內(nèi)部的this指針其實(shí)指向window對(duì)象 console.log( window.nick); //輸出:casper var coder = new Coder( 'casper' ); //加上new,一切皆不同,this正確地指向了當(dāng)前創(chuàng)建的實(shí)例 console.log( coder.nick ); //輸出:casper
這樣的錯(cuò)誤貌似挺低級(jí)的,但出現(xiàn)的概率挺高的,腫么去避免或減少這種情況的發(fā)生呢?
可以在內(nèi)部實(shí)現(xiàn)里面動(dòng)下手腳:
var Coder = function( nick ){
if( !(this instanceof Coder) ){
return new Coder( nick );
}
this.nick = nick;
};
其實(shí)很簡(jiǎn)單,實(shí)例化的時(shí)候,內(nèi)部判斷下,當(dāng)前this指向的對(duì)象的類(lèi)型即可,如果非當(dāng)前構(gòu)造函數(shù)的類(lèi)型,強(qiáng)制重新調(diào)用一遍構(gòu)造函數(shù)。
突然覺(jué)得Coder這名字不夠洋氣?想用Hacker,好吧,我改。。。數(shù)了下,一共有三處要改,這不科學(xué),有沒(méi)有辦法只把構(gòu)造函數(shù)的名字改了就行?
當(dāng)然有:
var Coder = function( nick ){
if( !(this instanceof arguments.callee) ){
return new arguments.callee( nick );
}
this.nick = nick;
};
tips:據(jù)說(shuō)在ES 5的嚴(yán)格模式下面arguments.callee會(huì)被禁用,不過(guò)僅當(dāng)ES 5普及同時(shí)你指定了要使用嚴(yán)格模式,否則還是可以用的發(fā)散下思維。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家學(xué)習(xí)函數(shù)調(diào)用、方法調(diào)用和構(gòu)造函數(shù)調(diào)用有所幫助。
- JavaScript實(shí)現(xiàn)顯示函數(shù)調(diào)用堆棧的方法
- JS中獲取函數(shù)調(diào)用鏈所有參數(shù)的方法
- js中函數(shù)調(diào)用的兩種常用方法使用介紹
- js函數(shù)調(diào)用的方式
- JS嵌套函數(shù)調(diào)用上下文的問(wèn)題解決
- js this函數(shù)調(diào)用無(wú)需再次抓獲id,name或標(biāo)簽名
- js函數(shù)調(diào)用常用方法詳解
- js 函數(shù)調(diào)用模式小結(jié)
- javascript 函數(shù)調(diào)用的對(duì)象和方法
- JavaScript 函數(shù)調(diào)用規(guī)則
- javascript 函數(shù)調(diào)用規(guī)則
- javascript iframe內(nèi)的函數(shù)調(diào)用實(shí)現(xiàn)方法
- Javascript 函數(shù)的四種調(diào)用模式
相關(guān)文章
JavaScript冒泡算法原理與實(shí)現(xiàn)方法深入理解
這篇文章主要介紹了JavaScript冒泡算法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript冒泡算法基本原理、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-06-06
javascript使用for循環(huán)批量注冊(cè)的事件不能正確獲取索引值的解決方法
這篇文章主要介紹了javascript使用for循環(huán)批量注冊(cè)的事件不能正確獲取索引值的解決方法,對(duì)比分析了出現(xiàn)問(wèn)題的代碼與修改后的代碼,并給出了采用閉包實(shí)現(xiàn)的方法,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2014-12-12
JS執(zhí)行控制之節(jié)流模式實(shí)例分析
這篇文章主要介紹了JS執(zhí)行控制之節(jié)流模式,結(jié)合實(shí)例形式分析了節(jié)流模式的功能、原理及相關(guān)使用方法,需要的朋友可以參考下2018-12-12
JS實(shí)現(xiàn)彩色圖片轉(zhuǎn)換為黑白圖片的3種方法
本文主要介紹了JS實(shí)現(xiàn)彩色圖片轉(zhuǎn)換為黑白圖片的3種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09
BootstrapTable refresh 方法使用實(shí)例簡(jiǎn)單介紹
本文就bootstrapTable refresh 方法如何傳遞參數(shù)做簡(jiǎn)單舉例說(shuō)明,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-02-02
關(guān)于Javascript中值得學(xué)習(xí)的特性總結(jié)
本文主要介紹了一些Javascript中值得學(xué)習(xí)的特性,可選鏈操作符,空值合并運(yùn)算符,Promise.allSettled(),BigInt類(lèi)型等特性,文中有詳細(xì)的代碼示例介紹這些特性,感興趣的可以參考下2023-05-05
淺談JavaScript中你可能不知道URL構(gòu)造函數(shù)的屬性
這篇文章主要介紹了淺談JavaScript中你可能不知道URL構(gòu)造函數(shù)的屬性,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
一文詳解如何用原型鏈的方式實(shí)現(xiàn)JS繼承
JavaScript中,每當(dāng)創(chuàng)建一個(gè)對(duì)象,都會(huì)給這個(gè)對(duì)象提供一個(gè)內(nèi)置對(duì)象 [[Prototype]] 。這個(gè)對(duì)象就是原型對(duì)象,[[Prototype]] 的層層嵌套就形成了原型鏈。本文將詳細(xì)講解如何用原型鏈的方式實(shí)現(xiàn)一個(gè) JS 繼承,感興趣的可以了解下2022-04-04

