function作為建構函式和非構造函式呼叫的區別

2021-09-16 22:16:32 字數 2802 閱讀 7095

var currenttime = date()能生成乙個當前時間的日期物件,var currenttime = new date()也能生成乙個同樣的物件。如果你看過一些框架,那麼你會發現有的框架生成物件寫法是 new classname(),有的框架是 classname()。 那麼兩種方式有什麼區別呢?

假設我們定義了乙個函式:

function normalfunc() 

// 第一種調法

normalfunc();

// 第二種調法

normalfunc.call( null );

// 第三種調法

var obj =

obj.method();

我們把乙個函式被當作乙個普通函式或者方法呼叫歸為一類,其被呼叫時發生的主要步驟:

把當前函式和這個新的執行上下文和作用域關聯起來。

2.1. 如果當前函式是箭頭函式,那麼把作用域中的 environment record 物件的內部屬性[[thisbindingstatus]]設定成 lexical。

把這個執行上下文壓入呼叫棧的頂部,即設定成執行執行上下文(running execution context)。

接下來處理當前函式的屬性 this 的取值:

4.1. 如果當前函式是箭頭函式,那麼這步就不做任何處理(因為已經在步驟2.1中做了標誌位)。

4.2. 如果不是箭頭函式,那麼先檢視當前函式是否處在嚴格模式下。

4.2.1. 嚴格模式:this 的取值取決於如何呼叫當前函式,譬如上例**中第一種調法,取值為 undefined,第二種調法取值為 `normalfunc.call(` 的第乙個引數,第三種調法取值為 obj。

4.2.2. 非嚴格模式:先按4.2.1的分類獲得 this 的取值,如果是 null 或者 undefined,用全域性物件代替 null 或者 undefined。如果 this 的取值是非空值那麼把 this 指向這個非空值(注1)。

4.3. 把 this 的取值儲存在作用域中的 environment record 物件的內部屬性[[thisvalue]]中(步驟4中並非把 this 直接指向這些取值,而是把值儲存在作用域特定內部屬性中,this 的尋值過程還有額外一步,下面會說明)。

執行函式體。

把當前執行上下文彈出呼叫棧。

如果步驟5有返回,則返回這個結果。如果步驟5沒有返回,則返回 undefined。

注1:這裡非空值還要判斷是原始型別(primitive value),還是物件型別。如果是原始型別,取值還要再把原始型別包裝成物件才能作為 this 的取值。步驟中避免太繁瑣,省略了細節顧特地加上注釋。

結合上面描述的步驟,我們來看看當你在函式中使用 this 時(上面的步驟5中 this 已經可用),程式時如何尋找 this 的:

根據當前執行上下文查詢到對應的 enviroment record(execution context -> scope -> environment record)。

判斷當前這個 record 是否儲存過[[thisvalue]],如果沒有的就沿著作用域鏈向上查詢,以全域性作用域為終點。

如果找到了,則返回。

如上所述,箭頭函式本身的作用域並沒有儲存[[thisvalue]],所以其內部使用 this 會去定義箭頭函式的地方(函式)去取 this,如果取不到繼續向上查詢。

// 沒有繼承關係

function normalfuncascontructor()

// or not

// [return]

}var o = new normalfuncascontructor();

// 有繼承關係

function parent(){}

function child(){}

child.prototype = new parent();

var c = new child();

我們把乙個函式被當作建構函式,使用 new 操作符呼叫時發生的主要步驟:

新建乙個普通物件,把其原型[[prototype]]指向建構函式的 prototype 屬性的值。

如普通函式呼叫的步驟1一樣,生成乙個新的執行上下文和對應的作用域,並把當前建構函式和兩者關聯起來。

把這個執行上下文壓入呼叫棧的頂部。

把第一步生成的物件當作 this 的取值儲存到作用域中的 environment record 物件的內部屬性[[thisvalue]]中。

執行函式體。

把當前執行上下文彈出呼叫棧。

處理函式執行的結果,即 new 了之後返回啥:

7.1 如果步驟5返回乙個物件,那麼就把這個物件作為此次 new 操作的返回值。

7.2 如果返回的不是物件,而且這個函式不是 generator 函式,那麼返回第一步生成的物件(generator 就先不在這裡討論了)。

知道了兩者的區別,我們就能在函式體裡面搞文章了,你可以通過如下**檢測使用者怎麼呼叫你的函式。如果你知道了使用者怎麼呼叫,你自然可以根據你想要的結果限制使用者的使用方法。

function myfunc()  else 

}myfunc(); // commonly invoked

new myfunc(); // called by new operator

var obj =

obj.method(); // commonly invoked

函式作為建構函式執行 和 作為普通函式執行的區別

看下面js function dwn s function double value var d1 new double 1243.34 var d2 double 34.32 dwn d1 dwn d2 b 執行結果 b function double value function double ...

建構函式和拷貝建構函式

建構函式 簡單地說建構函式是類函式,函式名與類名完全相同,無返回值 建構函式屬於類的成員函式,除了具有一般成員函式的特點外,還具有自己的特點 1 是類的乙個特殊的成員函式,函式名與類名相同 2 訪問屬性應該是public 3 功能是初始化物件,在建構函式中一般不作初始化以外的事情 4 可以在類內定義...

函式和建構函式

函式使用function關鍵字來定義,可以用在函式定義表示式或函式宣告語句中。函式呼叫的4種方法 1 作為函式 1 這是乙個普通函式 2function range 3 函式表示式 4var range function 56 呼叫7 range 2 作為建構函式 看建構函式部分 3 作為方法 1 ...