跟我學習javascript的函數(shù)調(diào)用和構(gòu)造函數(shù)調(diào)用
一、函數(shù)調(diào)用
Function絕對是JavaScript中的重中之重。在JavaScript中,F(xiàn)unction承擔了procedures, methods, constructors甚至是classes以及modules的功能。
在面向?qū)ο蟪绦蛟O計中,functions,methods以及class constructor往往是三件不同的事情,由不同的語法來實現(xiàn)。但是在JavaScript中,這三個概念都由function來實現(xiàn),通過三種不同的模式。
最簡單的使用模式就是function 調(diào)用:
function hello(username) { return "hello, " + username; } hello("Keyser Söze"); // "hello, Keyser Söze"
二、方法的調(diào)用
而methods這一概念在JavaScript中的表現(xiàn)就是,一個對象的屬性是一個function:同樣的是函數(shù),將其賦值給一個對象的成員以后,就不一樣了。將函數(shù)賦值給對象的成員后,那么這個就不在稱為函數(shù),而應該叫做方法。
var obj = { hello: function() { return "hello, " + this.username; }, username: "Hans Gruber" }; obj.hello(); // "hello, Hans Gruber"
真正的行為是,調(diào)用本身才會決定this會綁定到哪個對象,即:
obj1.hello()會將this綁定到obj1,obj2.hello()則會將this綁定到obj2。記住一句話,誰調(diào)用,this就指向誰
正因為this綁定的這種規(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"
但是,在一個普通的函數(shù)中,如上面的hello函數(shù),使用this關(guān)鍵字是不太好的方式,當它被直接調(diào)用的時候,this的指向就成了問題。在這種情況下,this往往被指向全局對象(GlobalObject),在瀏覽器上一般就是window對象。
而這種行為是不確定和沒有意義的。
所以在ES5標準中,如果使用了strict mode,那么this會被設置為undefined:
function hello() { "use strict"; return "hello, " + this.username; } hello(); // error: cannot read property "username" of undefined
以上這種做法是為了讓潛在的錯誤更快的暴露出來,避免了誤操作和難以找到的bug。
區(qū)別普通函數(shù)調(diào)用和方法調(diào)用,直接看這個例子就明確了。
var func = function() { alert(this); }; var o = {}; o.fn = func; // 比較 alert(o.fn === func);//true // 調(diào)用 func();//[object Window] o.fn();//[object Object]
這里的運行結(jié)果是,兩個函數(shù)是相同的,因此打印結(jié)果是 true。但是由于兩個函數(shù)的調(diào)用是不一樣的,func 的調(diào)用,打印的是 [object Window],而o.fn 的打印結(jié)果是 [object Object]。
這里便是函數(shù)調(diào)用與方法調(diào)用的區(qū)別,函數(shù)調(diào)用中,this 專指全局對象 window,而在方法中 this 專指當前對象,即 o.fn 中的 this 指的就是對象o。
三、構(gòu)造函數(shù)的調(diào)用
function的第三種使用模式就是講它作為constructor:
構(gòu)造器中的this
我們需要分析創(chuàng)建對象的過程,方能知道this的意義. 如下面代碼:
var Person = function() { this.name = "小平果"; }; var p = new Person();
這里首先定義了函數(shù)Person,下面分析一下整個執(zhí)行:
- 程序在執(zhí)行到這一句的時候,不會執(zhí)行函數(shù)體,因此 JavaScript的解釋器并不知道這個函數(shù)的內(nèi)容.
- 接下來執(zhí)行new關(guān)鍵字,創(chuàng)建對象,解釋器開辟內(nèi)存,得到對象的引用,將新對象的引用交給函數(shù).
- 緊接著執(zhí)行函數(shù),將傳過來的對象引用交給this. 也就是說,在構(gòu)造方法中,this就是剛剛被new創(chuàng)建出來的對象.
- 然后為this 添加成員,也就是為對象添加成員.
- 最后函數(shù)結(jié)束,返回this,將this交給左邊的變量.
分析過構(gòu)造函數(shù)的執(zhí)行以后,可以得到,構(gòu)造函數(shù)中的this就是當前對象.
構(gòu)造器中的return
在構(gòu)造函數(shù)中return的意義發(fā)生了變化,首先如果在構(gòu)造函數(shù)中,如果返回的是一個對象,那么就保留原意. 如果返回的是非對象,比如數(shù)字、布爾和字符串,那么就返回this,如果沒有return語句,那么也返回this. 看下面代碼:
// 返回一個對象的 return var ctr = function() { this.name = "趙曉虎"; return { name:"牛亮亮" }; }; // 創(chuàng)建對象 var p = new ctr(); // 訪問name屬性 alert(p.name); //執(zhí)行代碼,這里打印的結(jié)果是"牛亮亮". 因為構(gòu)造方法中返回的是一個對象,那么保留return的意義,返回內(nèi)容為return后面的對象. 再看下面代碼: // 定義返回非對象數(shù)據(jù)的構(gòu)造器 var ctr = function() { this.name = "趙曉虎"; return "牛亮亮"; }; // 創(chuàng)建對象 var p = new ctr(); // 使用 alert(p); alert(p.name);
代碼運行結(jié)果是,先彈窗打印[object Object],然后打印”趙曉虎”. 因為這里 return 的是一個字符串,屬于基本類型,那么這里的return語句無效,返回的是this對象. 因此第一個打印的是[object Object]而第二個不會打印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進行調(diào)用。和function以及method調(diào)用不一樣的是,constructor會傳入一個新的對象并將它綁定到this,然后返回該對象作為constructor的返回值。而constructor function本身的作用就是為了初始化該對象。
構(gòu)造函數(shù)調(diào)用常犯的一個錯誤
興致勃勃地定義了下面這么個構(gòu)造函數(shù):
var Coder = function( nick ){ this.nick = nick; };
定義構(gòu)造函數(shù)結(jié)束后呢?沒錯,趕緊實例化:
var coder = Coder( 'casper' );
這個coder兄弟叫什么名字?趕緊打印下:
console.log( coder.nick ); //undefined = =b 竟然是undefined!!再回過頭看看實例化的那個語句,不難發(fā)現(xiàn)問題出在哪里:少了個new var coder = Coder( 'casper' ); //當作普通的函數(shù)來調(diào)用,故內(nèi)部的this指針其實指向window對象 console.log( window.nick); //輸出:casper var coder = new Coder( 'casper' ); //加上new,一切皆不同,this正確地指向了當前創(chuàng)建的實例 console.log( coder.nick ); //輸出:casper
這樣的錯誤貌似挺低級的,但出現(xiàn)的概率挺高的,腫么去避免或減少這種情況的發(fā)生呢?
可以在內(nèi)部實現(xiàn)里面動下手腳:
var Coder = function( nick ){ if( !(this instanceof Coder) ){ return new Coder( nick ); } this.nick = nick; };
其實很簡單,實例化的時候,內(nèi)部判斷下,當前this指向的對象的類型即可,如果非當前構(gòu)造函數(shù)的類型,強制重新調(diào)用一遍構(gòu)造函數(shù)。
突然覺得Coder這名字不夠洋氣?想用Hacker,好吧,我改。。。數(shù)了下,一共有三處要改,這不科學,有沒有辦法只把構(gòu)造函數(shù)的名字改了就行?
當然有:
var Coder = function( nick ){ if( !(this instanceof arguments.callee) ){ return new arguments.callee( nick ); } this.nick = nick; };
tips:據(jù)說在ES 5的嚴格模式下面arguments.callee會被禁用,不過僅當ES 5普及同時你指定了要使用嚴格模式,否則還是可以用的發(fā)散下思維。
以上就是本文的全部內(nèi)容,希望對大家學習函數(shù)調(diào)用、方法調(diào)用和構(gòu)造函數(shù)調(diào)用有所幫助。
- JavaScript實現(xiàn)顯示函數(shù)調(diào)用堆棧的方法
- JS中獲取函數(shù)調(diào)用鏈所有參數(shù)的方法
- js中函數(shù)調(diào)用的兩種常用方法使用介紹
- js函數(shù)調(diào)用的方式
- JS嵌套函數(shù)調(diào)用上下文的問題解決
- js this函數(shù)調(diào)用無需再次抓獲id,name或標簽名
- js函數(shù)調(diào)用常用方法詳解
- js 函數(shù)調(diào)用模式小結(jié)
- javascript 函數(shù)調(diào)用的對象和方法
- JavaScript 函數(shù)調(diào)用規(guī)則
- javascript 函數(shù)調(diào)用規(guī)則
- javascript iframe內(nèi)的函數(shù)調(diào)用實現(xiàn)方法
- Javascript 函數(shù)的四種調(diào)用模式
相關(guān)文章
JS+CSS實現(xiàn)超漂亮的動態(tài)翻書效果(思路詳解)
我們平常沖浪時是不是看過一些學校高級的錄取通知書,翻開通知書就能看見里面的內(nèi)容,呈現(xiàn)出逼真的3D效果,本文帶領大家基于JS+CSS實現(xiàn)超漂亮的動態(tài)翻書效果,需要的朋友可以參考下2023-05-05動態(tài)加載外部javascript文件的函數(shù)代碼分享
動態(tài)加載外部javascript文件的函數(shù)代碼分享,做個記錄備忘,方便查找。2011-07-07javascript顯示倒計時控制按鈕的簡單實現(xiàn)
下面小編就為大家?guī)硪黄猨avascript顯示倒計時控制按鈕的簡單實現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06Bootstrap 填充Json數(shù)據(jù)的實例代碼
本篇文章主要介紹了Bootstrap 填充Json數(shù)據(jù)的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01