摘要:函數的調用有以下幾種方式作為對象方法調用,作為函數調用,作為構造函數調用,和使用或調用。并且規范中說明,只有對象實現了方法。使用了回到上面作為構造函數調用第一步創建一個空的對象,。第二步鏈接該對象即設置該對象的構造函數到另一個對象,即。
在src/core/instance/index.js中
if (process.env.NODE_ENV !== "production" && !(this instanceof Vue) ) { warn("Vue is a constructor and should be called with the `new` keyword") }
這里通過this instanceof Vue來判斷有沒有用new關鍵詞調用,為什么可以這么判斷?我們分別了解一下this和instanceof的用法
this在 JavaScript 中,this 是動態綁定,或稱為運行期綁定的,它可以是全局對象、當前對象或者任意對象,這取決于函數的調用方式。函數的調用有以下幾種方式:作為對象方法調用,作為函數調用,作為構造函數調用,和使用 apply 或 call 調用。
1、作為對象方法調用
var point = { x : 0, y : 0, moveTo : function(x, y) { this.x = this.x + x; this.y = this.y + y; } };
point.moveTo(1, 1)//this 綁定到當前對象,即 point 對象
2、作為函數調用
function makeNoSense(y) { this.x = y; } makeNoSense(5); x;// 調用函數的對象是window,所以x 已經成為一個值為 5 的全局變量
下面,我們看另一種情況
var point = { x : 0, y : 0, moveTo : function(x, y) { // 內部函數 var moveX = function(x) { this.x = x;//this 綁定到了哪里? }; // 內部函數 var moveY = function(y) { this.y = y;//this 綁定到了哪里? }; moveX(x); moveY(y); } }; point.moveTo(1, 1); point.x; //==>0 point.y; //==>0 x; //==>1 y; //==>1
this除了指向它的直接調用者外,還有一種情況就是如果沒有明確的調用對象的時候,將對函數的this使用默認綁定:綁定到全局的window對象。
3、作為構造函數調用
function Point(x, y){ this.x = x; this.y = y; } var test = new Point(1, 2)
我們需要理解的是,new運算符做了什么:
第一步: 創建一個空的對象,{}。 第二步: 鏈接該對象(即設置該對象的構造函數)到另一個對象,即o.\__proto__ == Point.prototype。 第三步: 將步驟1新創建的對象作為this的上下文 第四步: 如果該函數沒有返回對象,則返回this
4、使用 apply 或 call 調用
apply和call可以切換函數執行的上下文環境(context)
function add(x, y) { console.log(x + y) } function del(x, y) { console.log(x - y) } add.call(del, 3, 1) // 4instanceof
1、通常來講,使用 instanceof 就是判斷一個實例是否屬于某種類型,比如:
// 判斷 foo 是否是 Foo 類的實例 function Foo(){} var foo = new Foo(); console.log(foo instanceof Foo)//true
2、另外,更重要的一點是 instanceof 可以在繼承關系中用來判斷一個實例是否屬于它的父類型。例如:
// 判斷 foo 是否是 Foo 類的實例 , 并且是否是其父類型的實例 function Aoo(){} function Foo(){} Foo.prototype = new Aoo();//JavaScript 原型繼承 var foo = new Foo(); console.log(foo instanceof Foo)//true console.log(foo instanceof Aoo)//true
上面的代碼中是判斷了一層繼承關系中的父類,在多層繼承關系中,instanceof 運算符同樣適用。
3、ECMAScript中instanceof的定義
11.8.6 The instanceof operator
The production RelationalExpression:
RelationalExpression instanceof ShiftExpression is evaluated as follows: 1. Evaluate RelationalExpression. 2. Call GetValue(Result(1)).// 調用 GetValue 方法得到 Result(1) 的值,設為 Result(2) 3. Evaluate ShiftExpression. 4. Call GetValue(Result(3)).// 同理,這里設為 Result(4) 5. If Result(4) is not an object, throw a TypeError exception.// 如果 Result(4) 不是 object, //拋出異常 /* 如果 Result(4) 沒有 [[HasInstance]] 方法,拋出異常。規范中的所有 [[...]] 方法或者屬性都是內部的, 在 JavaScript 中不能直接使用。并且規范中說明,只有 Function 對象實現了 [[HasInstance]] 方法。 所以這里可以簡單的理解為:如果 Result(4) 不是 Function 對象,拋出異常 */ 6. If Result(4) does not have a [[HasInstance]] method, throw a TypeError exception. // 相當于這樣調用:Result(4).[[HasInstance]](Result(2)) 7. Call the [[HasInstance]] method of Result(4) with parameter Result(2). 8. Return Result(7). // 相關的 HasInstance 方法定義 15.3.5.3 [[HasInstance]] (V) Assume F is a Function object.// 這里 F 就是上面的 Result(4),V 是 Result(2) When the [[HasInstance]] method of F is called with value V, the following steps are taken: 1. If V is not an object, return false.// 如果 V 不是 object,直接返回 false 2. Call the [[Get]] method of F with property name "prototype".// 用 [[Get]] 方法取 // F 的 prototype 屬性 3. Let O be Result(2).//O = F.[[Get]]("prototype") 4. If O is not an object, throw a TypeError exception. 5. Let V be the value of the [[Prototype]] property of V.//V = V.[[Prototype]] 6. If V is null, return false. // 這里是關鍵,如果 O 和 V 引用的是同一個對象,則返回 true;否則,到 Step 8 返回 Step 5 繼續循環 7. If O and V refer to the same object or if they refer to objects joined to each other (section 13.1.2), return true. 8. Go to step 5.
翻譯成 JavaScript 代碼如下所示:
function instance_of(L, R) {//L 表示左表達式,R 表示右表達式 var O = R.prototype;// 取 R 的顯示原型 L = L.__proto__;// 取 L 的隱式原型 while (true) { if (L === null) return false; if (O === L)// 這里重點:當 O 嚴格等于 L 時,返回 true return true; L = L.__proto__; } }
從代碼中我們可以看到,instanceof是比較左側的__proto__(隱式原型)和右側的prototype(顯示原型)是否相等,如果不相等,取左側__proto__的__proto__,依次循環比較,直到取到Object.prototype.__proto__即null為止。有關__proto__和prototype請查看我這篇博客
回到主題,this instanceof Vue我們可以這么分解:this.__proto__和Vue.prototype
沒有使用new
this指向window,結果為false。
使用了new
回到上面作為構造函數調用:
第一步: 創建一個空的對象,vat o = {}。 第二步: 鏈接該對象(即設置該對象的構造函數)到另一個對象,即o.\__proto__ == Vue.prototype。 第三步: 將步驟1新創建的對象作為this的上下文 第四步: 如果該函數沒有返回對象,則返回this
所以,結果可以看做這樣:
o.\__proto__ == this.\__proto__ == Vue.prototype
所以如果用new操作符的話,this instanceof Vue結果為true。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103962.html
摘要:學習源碼時,我們首先需要看的是文件,該文件里配置了的依賴以及開發環境和生產環境的編譯的啟動腳本等其他信息。一個是完整版,一個是運行時。運行時用來創建實例渲染并處理虛擬等的代碼。基本上就是除去編譯器的其它一切。 學習vue源碼時,我們首先需要看的是package.json文件,該文件里配置了vue的依賴以及開發環境和生產環境的編譯的啟動腳本等其他信息。首先我們需要關注的是script。我...
摘要:源碼解讀閱讀請關注下代碼注釋打個廣告哪位大佬教我下怎么排版啊,不會弄菜單二級導航撲通是什么首先,你會從源碼里面引入,然后再傳入參數實例化一個路由對象源碼基礎類源碼不選擇模式會默認使用模式非瀏覽器環境默認環境根據參數選擇三種模式的一種根據版 router源碼解讀 閱讀請關注下代碼注釋 打個廣告:哪位大佬教我下sf怎么排版啊,不會弄菜單二級導航(撲通.gif) showImg(https:...
摘要:源碼解讀閱讀請關注下代碼注釋打個廣告哪位大佬教我下怎么排版啊,不會弄菜單二級導航撲通是什么首先,你會從源碼里面引入,然后再傳入參數實例化一個路由對象源碼基礎類源碼不選擇模式會默認使用模式非瀏覽器環境默認環境根據參數選擇三種模式的一種根據版 router源碼解讀 閱讀請關注下代碼注釋 打個廣告:哪位大佬教我下sf怎么排版啊,不會弄菜單二級導航(撲通.gif) showImg(https:...
摘要:最后判斷有無根節點,無則表示首次掛載,添加鉤子函數,返回總結實例初始化掛載方法屬性初始化掛載過程在版本,生成函數對作處理,執行中定義了通過實例化的回調執行執行,即調用了真實渲染成對象。 vue 入口 從vue的構建過程可以知道,web環境下,入口文件在 src/platforms/web/entry-runtime-with-compiler.js(以Runtime + Compile...
閱讀 1565·2021-11-02 14:42
閱讀 2308·2021-10-11 10:58
閱讀 656·2021-09-26 09:46
閱讀 2908·2021-09-08 09:35
閱讀 1403·2021-08-24 10:01
閱讀 1228·2019-08-30 15:54
閱讀 3597·2019-08-30 15:44
閱讀 1792·2019-08-30 10:49