摘要:函數(shù)的調(diào)用有以下幾種方式作為對(duì)象方法調(diào)用,作為函數(shù)調(diào)用,作為構(gòu)造函數(shù)調(diào)用,和使用或調(diào)用。并且規(guī)范中說(shuō)明,只有對(duì)象實(shí)現(xiàn)了方法。使用了回到上面作為構(gòu)造函數(shù)調(diào)用第一步創(chuàng)建一個(gè)空的對(duì)象,。第二步鏈接該對(duì)象即設(shè)置該對(duì)象的構(gòu)造函數(shù)到另一個(gè)對(duì)象,即。
在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") }
這里通過(guò)this instanceof Vue來(lái)判斷有沒(méi)有用new關(guān)鍵詞調(diào)用,為什么可以這么判斷?我們分別了解一下this和instanceof的用法
this在 JavaScript 中,this 是動(dòng)態(tài)綁定,或稱(chēng)為運(yùn)行期綁定的,它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象,這取決于函數(shù)的調(diào)用方式。函數(shù)的調(diào)用有以下幾種方式:作為對(duì)象方法調(diào)用,作為函數(shù)調(diào)用,作為構(gòu)造函數(shù)調(diào)用,和使用 apply 或 call 調(diào)用。
1、作為對(duì)象方法調(diào)用
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 綁定到當(dāng)前對(duì)象,即 point 對(duì)象
2、作為函數(shù)調(diào)用
function makeNoSense(y) { this.x = y; } makeNoSense(5); x;// 調(diào)用函數(shù)的對(duì)象是window,所以x 已經(jīng)成為一個(gè)值為 5 的全局變量
下面,我們看另一種情況
var point = { x : 0, y : 0, moveTo : function(x, y) { // 內(nèi)部函數(shù) var moveX = function(x) { this.x = x;//this 綁定到了哪里? }; // 內(nèi)部函數(shù) 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除了指向它的直接調(diào)用者外,還有一種情況就是如果沒(méi)有明確的調(diào)用對(duì)象的時(shí)候,將對(duì)函數(shù)的this使用默認(rèn)綁定:綁定到全局的window對(duì)象。
3、作為構(gòu)造函數(shù)調(diào)用
function Point(x, y){ this.x = x; this.y = y; } var test = new Point(1, 2)
我們需要理解的是,new運(yùn)算符做了什么:
第一步: 創(chuàng)建一個(gè)空的對(duì)象,{}。 第二步: 鏈接該對(duì)象(即設(shè)置該對(duì)象的構(gòu)造函數(shù))到另一個(gè)對(duì)象,即o.\__proto__ == Point.prototype。 第三步: 將步驟1新創(chuàng)建的對(duì)象作為this的上下文 第四步: 如果該函數(shù)沒(méi)有返回對(duì)象,則返回this
4、使用 apply 或 call 調(diào)用
apply和call可以切換函數(shù)執(zhí)行的上下文環(huán)境(context)
function add(x, y) { console.log(x + y) } function del(x, y) { console.log(x - y) } add.call(del, 3, 1) // 4instanceof
1、通常來(lái)講,使用 instanceof 就是判斷一個(gè)實(shí)例是否屬于某種類(lèi)型,比如:
// 判斷 foo 是否是 Foo 類(lèi)的實(shí)例 function Foo(){} var foo = new Foo(); console.log(foo instanceof Foo)//true
2、另外,更重要的一點(diǎn)是 instanceof 可以在繼承關(guān)系中用來(lái)判斷一個(gè)實(shí)例是否屬于它的父類(lèi)型。例如:
// 判斷 foo 是否是 Foo 類(lèi)的實(shí)例 , 并且是否是其父類(lèi)型的實(shí)例 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
上面的代碼中是判斷了一層繼承關(guān)系中的父類(lèi),在多層繼承關(guān)系中,instanceof 運(yùn)算符同樣適用。
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)).// 調(diào)用 GetValue 方法得到 Result(1) 的值,設(shè)為 Result(2) 3. Evaluate ShiftExpression. 4. Call GetValue(Result(3)).// 同理,這里設(shè)為 Result(4) 5. If Result(4) is not an object, throw a TypeError exception.// 如果 Result(4) 不是 object, //拋出異常 /* 如果 Result(4) 沒(méi)有 [[HasInstance]] 方法,拋出異常。規(guī)范中的所有 [[...]] 方法或者屬性都是內(nèi)部的, 在 JavaScript 中不能直接使用。并且規(guī)范中說(shuō)明,只有 Function 對(duì)象實(shí)現(xiàn)了 [[HasInstance]] 方法。 所以這里可以簡(jiǎn)單的理解為:如果 Result(4) 不是 Function 對(duì)象,拋出異常 */ 6. If Result(4) does not have a [[HasInstance]] method, throw a TypeError exception. // 相當(dāng)于這樣調(diào)用:Result(4).[[HasInstance]](Result(2)) 7. Call the [[HasInstance]] method of Result(4) with parameter Result(2). 8. Return Result(7). // 相關(guān)的 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. // 這里是關(guān)鍵,如果 O 和 V 引用的是同一個(gè)對(duì)象,則返回 true;否則,到 Step 8 返回 Step 5 繼續(xù)循環(huán) 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 表示左表達(dá)式,R 表示右表達(dá)式 var O = R.prototype;// 取 R 的顯示原型 L = L.__proto__;// 取 L 的隱式原型 while (true) { if (L === null) return false; if (O === L)// 這里重點(diǎn):當(dāng) O 嚴(yán)格等于 L 時(shí),返回 true return true; L = L.__proto__; } }
從代碼中我們可以看到,instanceof是比較左側(cè)的__proto__(隱式原型)和右側(cè)的prototype(顯示原型)是否相等,如果不相等,取左側(cè)__proto__的__proto__,依次循環(huán)比較,直到取到Object.prototype.__proto__即null為止。有關(guān)__proto__和prototype請(qǐng)查看我這篇博客
回到主題,this instanceof Vue我們可以這么分解:this.__proto__和Vue.prototype
沒(méi)有使用new
this指向window,結(jié)果為false。
使用了new
回到上面作為構(gòu)造函數(shù)調(diào)用:
第一步: 創(chuàng)建一個(gè)空的對(duì)象,vat o = {}。 第二步: 鏈接該對(duì)象(即設(shè)置該對(duì)象的構(gòu)造函數(shù))到另一個(gè)對(duì)象,即o.\__proto__ == Vue.prototype。 第三步: 將步驟1新創(chuàng)建的對(duì)象作為this的上下文 第四步: 如果該函數(shù)沒(méi)有返回對(duì)象,則返回this
所以,結(jié)果可以看做這樣:
o.\__proto__ == this.\__proto__ == Vue.prototype
所以如果用new操作符的話(huà),this instanceof Vue結(jié)果為true。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103962.html
摘要:學(xué)習(xí)源碼時(shí),我們首先需要看的是文件,該文件里配置了的依賴(lài)以及開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境的編譯的啟動(dòng)腳本等其他信息。一個(gè)是完整版,一個(gè)是運(yùn)行時(shí)。運(yùn)行時(shí)用來(lái)創(chuàng)建實(shí)例渲染并處理虛擬等的代碼。基本上就是除去編譯器的其它一切。 學(xué)習(xí)vue源碼時(shí),我們首先需要看的是package.json文件,該文件里配置了vue的依賴(lài)以及開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境的編譯的啟動(dòng)腳本等其他信息。首先我們需要關(guān)注的是script。我...
摘要:源碼解讀閱讀請(qǐng)關(guān)注下代碼注釋打個(gè)廣告哪位大佬教我下怎么排版啊,不會(huì)弄菜單二級(jí)導(dǎo)航撲通是什么首先,你會(huì)從源碼里面引入,然后再傳入?yún)?shù)實(shí)例化一個(gè)路由對(duì)象源碼基礎(chǔ)類(lèi)源碼不選擇模式會(huì)默認(rèn)使用模式非瀏覽器環(huán)境默認(rèn)環(huán)境根據(jù)參數(shù)選擇三種模式的一種根據(jù)版 router源碼解讀 閱讀請(qǐng)關(guān)注下代碼注釋 打個(gè)廣告:哪位大佬教我下sf怎么排版啊,不會(huì)弄菜單二級(jí)導(dǎo)航(撲通.gif) showImg(https:...
摘要:源碼解讀閱讀請(qǐng)關(guān)注下代碼注釋打個(gè)廣告哪位大佬教我下怎么排版啊,不會(huì)弄菜單二級(jí)導(dǎo)航撲通是什么首先,你會(huì)從源碼里面引入,然后再傳入?yún)?shù)實(shí)例化一個(gè)路由對(duì)象源碼基礎(chǔ)類(lèi)源碼不選擇模式會(huì)默認(rèn)使用模式非瀏覽器環(huán)境默認(rèn)環(huán)境根據(jù)參數(shù)選擇三種模式的一種根據(jù)版 router源碼解讀 閱讀請(qǐng)關(guān)注下代碼注釋 打個(gè)廣告:哪位大佬教我下sf怎么排版啊,不會(huì)弄菜單二級(jí)導(dǎo)航(撲通.gif) showImg(https:...
摘要:最后判斷有無(wú)根節(jié)點(diǎn),無(wú)則表示首次掛載,添加鉤子函數(shù),返回總結(jié)實(shí)例初始化掛載方法屬性初始化掛載過(guò)程在版本,生成函數(shù)對(duì)作處理,執(zhí)行中定義了通過(guò)實(shí)例化的回調(diào)執(zhí)行執(zhí)行,即調(diào)用了真實(shí)渲染成對(duì)象。 vue 入口 從vue的構(gòu)建過(guò)程可以知道,web環(huán)境下,入口文件在 src/platforms/web/entry-runtime-with-compiler.js(以Runtime + Compile...
閱讀 1582·2021-11-02 14:42
閱讀 2321·2021-10-11 10:58
閱讀 670·2021-09-26 09:46
閱讀 2920·2021-09-08 09:35
閱讀 1418·2021-08-24 10:01
閱讀 1241·2019-08-30 15:54
閱讀 3613·2019-08-30 15:44
閱讀 1804·2019-08-30 10:49