首頁 > web前端 > js教程 > 主體

跟我學習javascript的函式呼叫與建構函式呼叫_javascript技巧

WBOY
發布: 2016-05-16 15:32:17
原創
1229 人瀏覽過

一、函數呼叫
Function絕對是JavaScript中的重中之重。在JavaScript中,Function承擔了procedures, methods, constructors甚至是classes以及modules的功能。

在物件導向程式設計中,functions,methods以及class constructor往往是三件不同的事情,由不同的語法來實現。但是在JavaScript中,這三個概念都由function來實現,透過三種不同的模式。

最簡單的使用模式就是function 呼叫:

function hello(username) { 
  return "hello, " + username; 
} 
hello("Keyser Söze"); // "hello, Keyser Söze" 
登入後複製

二、方法的呼叫

而methods這個概念​​在JavaScript中的表現就是,一個物件的屬性是一個function:同樣的是函數,將其賦值給一個物件的成員以後,就不一樣了。將函數賦值給物件的成員後,那麼這個就不在稱為函數,而應該叫做方法。

var obj = { 
  hello: function() { 
    return "hello, " + this.username; 
  }, 
  username: "Hans Gruber" 
}; 
obj.hello(); // "hello, Hans Gruber" 
登入後複製

真正的行為是,呼叫本身才會決定this會綁定到哪個對象,即:
obj1.hello()會將this綁定到obj1,obj2.hello()則會將this綁定到obj2。記住一句話,誰調用,this就指向誰

正因為this綁定的這種規則,在下面的用法也是可行的:

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" 

登入後複製

但是,在一個普通的函數中,如上面的hello函數,使用this關鍵字是不太好的方式,當它被直接呼叫的時候,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。
區別普通函數調用和方法調用,直接看這個例子就明確了。

var func = function() {
  alert(this);
};
var o = {};
o.fn = func;
// 比较
alert(o.fn === func);//true
// 调用
func();//[object Window]
o.fn();//[object Object]
登入後複製

這裡的運行結果是,兩個函數是相同的,因此列印結果是 true。但由於兩個函數的調用是不一樣的,func 的調用,打印的是 [object Window],而o.fn 的打印結果是 [object Object]。

這裡便是函數呼叫與方法呼叫的區別,函數呼叫中,this 專指全域物件 window,而在方法中 this 專指目前對象,即 o.fn 中的 this 指的就是物件o。

三、建構子的呼叫

function的第三種使用模式就是講它作為constructor:

構造器中的this

我們需要分析建立物件的過程,方能知道this的意義. 如下面程式碼:

 var Person = function() {
  this.name = "小平果";
 };
 var p = new Person();
登入後複製

這裡先定義了函數Person,下面分析一下整個執行:

  • 程式執行到這句話的時候,不會執行函數體,因此 JavaScript的解釋器並不知道這個函數的內容.
  • 接下來執行new關鍵字,創建對象,解釋器開闢內存,得到對象的引用,將新對象的引用交給函數.
  • 緊接著執行函數,將傳過來的物件參考交給this. 也就是說,在建構方法中,this就是剛剛被new創建出來的物件.
  • 然後為this 新增成員,也就是為物件加上成員.
  • 最後函數結束,回傳this,將this交給左邊的變數.

分析過建構子的執行以後,可以得到,建構子中的this就是當前物件.

構造器中的return

在構造函數中return的意義發生了變化,首先如果在構造函數中,如果返回的是一個對象,那麼就保留原意. 如果返回的是非對象,比如數字、布爾和字符串,那麼就返回this,如果沒有return語句,那麼也回傳this. 看下面程式碼:

 // 返回一个对象的 return
 var ctr = function() {
  this.name = "赵晓虎";
  return {
  name:"牛亮亮"
  };
 };
 // 创建对象
 var p = new ctr();
 // 访问name属性
 alert(p.name);

 //执行代码,这里打印的结果是"牛亮亮". 因为构造方法中返回的是一个对象,那么保留return的意义,返回内容为return后面的对象. 再看下面代码:

 // 定义返回非对象数据的构造器
 var ctr = function() {
  this.name = "赵晓虎";
  return "牛亮亮";
 };
 // 创建对象
 var p = new ctr();
 // 使用
 alert(p);
 alert(p.name);
登入後複製

程式碼運行結果是,先彈窗打印[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關鍵將function作為constructor進行呼叫。和function以及method呼叫不一樣的是,constructor會傳入一個新的物件並將它綁定到this,然後傳回該物件作為constructor的回傳值。而constructor function本身的作用就是為了初始化這個物件。

建構子呼叫常犯的一個錯誤

興致勃勃地定義了下面這麼個建構子:

var Coder = function( nick ){ 
this.nick = nick; 
}; 
登入後複製

定義建構函式結束後呢?沒錯,趕快實例化:

var coder = Coder( 'casper' ); 
登入後複製

這個coder兄弟叫什麼名字?趕快列印下:

console.log( coder.nick ); //undefined 
= =b 竟然是undefined!!再回过头看看实例化的那个语句,不难发现问题出在哪里:少了个new 
var coder = Coder( 'casper' ); //当作普通的函数来调用,故内部的this指针其实指向window对象 
console.log( window.nick); //输出:casper 
var coder = new Coder( 'casper' ); //加上new,一切皆不同,this正确地指向了当前创建的实例 
console.log( coder.nick ); //输出:casper 
登入後複製

这样的错误貌似挺低级的,但出现的概率挺高的,肿么去避免或减少这种情况的发生呢?
可以在内部实现里面动下手脚:

var Coder = function( nick ){ 
  if( !(this instanceof Coder) ){ 
    return new Coder( nick ); 
  } 
    this.nick = nick; 
}; 
登入後複製

其实很简单,实例化的时候,内部判断下,当前this指向的对象的类型即可,如果非当前构造函数的类型,强制重新调用一遍构造函数。
突然觉得Coder这名字不够洋气?想用Hacker,好吧,我改。。。数了下,一共有三处要改,这不科学,有没有办法只把构造函数的名字改了就行?
当然有:

var Coder = function( nick ){ 
  if( !(this instanceof arguments.callee) ){ 
    return new arguments.callee( nick ); 
  } 
  this.nick = nick; 
}; 
登入後複製

tips:据说在ES 5的严格模式下面arguments.callee会被禁用,不过仅当ES 5普及同时你指定了要使用严格模式,否则还是可以用的发散下思维。

以上就是本文的全部内容,希望对大家学习函数调用、方法调用和构造函数调用有所帮助。

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!