模仿vue本身動手寫響應式框架(二) - Vue對象建立

上一章節中,咱們用vue實現了簡單的todo應用,若是咱們把vue.js引用去掉,首先是界面顯示原始文本內容javascript

而後console報錯html

index.html:22 Uncaught ReferenceError: Vue is not defined
    at index.html:22

緣由是咱們在代碼中經過代碼var app = new Vue({...})建立了Vue對象,Vue對象是定義在vue.js中,如今沒了vue.js天然報錯。前端

這章的內容就是解決Vue對象找不到問題,讓代碼再也不報錯,爲何要先解決js報錯問題而不是文本顯示問題?由於Vue對象提供了Vue全部的功能,其中就包括值綁定,解決了值綁定的問題,界面天然也會恢復正常,因此先解決Vue對象找不到問題。vue

匿名函數和閉包

先解釋什麼是匿名函數,顧名思義就是沒有定義名稱的函數,好比下面這幾種java

// 函數表達式
var fn = function add(a,b){
    return a+b;
}

var c  = fn(1,2);

// 上面例子的結合
(function(a,b){return a+b;})(1,2);

//事件響應函數

var button = document.getElementById('submitButton');
button.onclick = function(){
    //do something
}

還有其餘狀況,這裏就不列舉,java也有匿名類,跟js的匿名函數相似。jquery

再來聊一下前端面試必問,無數前端學子竟折腰的閉包是什麼東西,這東西確實難理解,我以爲很大一個緣由是翻譯的問題,好比匿名函數,看名稱大概就知道什麼意思,閉包兩個字沒有任何想象的空間,並且還可能引發誤會,閉包實際上跟包並無什麼關係。個人不嚴謹但直觀的理解是閉包就是類,你能夠理解爲閉包就是java裏的類,在java類中,類能夠定義變量和方法,方法能夠引用類的變量,類比js,java類就是js的函數,java類變量就是js函數中定義的變量,java類的方法就是定義在js函數內部的函數。舉個例子:面試

function CircleArea(r){
    var PI=3.14159;
    
    function calculate(){
        return PI*r*r;
    }
    
    return calculate;
}

var circle2=CircleArea(2);
var area=circle2();
console.log(area);

正常當函數執行完變量會進行回收,在函數CircleArea中返回了calculate這個函數,理論上PI已經回收由於函數已經執行完,但在函數外部執行var area=circle2();時,結果依然時正確的,說明PI並無被回收,這個就是閉包的特性,函數和對其周圍狀態(lexical environment,詞法環境)的引用捆綁在一塊兒構成閉包(closure),這個纔是官方對閉包的定義。vuex

那麼在咱們這個應用中,Vue是以什麼形式存在,對象仍是函數?毫無疑問確定是函數,只有在函數中才能實現複雜的邏輯,才能實現生命週期的控制。因此若是想讓var app = new Vue({...})這行代碼不報錯,一個可行的方案以下:api

var Vue = function (options){
    console.log(options);
}

建立一個js文件,名稱就叫作vuex.js,複製上面的代碼到js文件中,將上一章html中引用vue.js的改成引用vuex.js,從新運行,這時候雖然界面仍是原樣輸出,可是console已經不報錯了,並且也正確打印出數據。bash

這一章的目的也就達到了。能不能更優雅點?若是看過jquery源碼和vue源碼,你們都能在代碼的開頭看到這麼一段代碼

(function( global, factory ) {....})(this,function(options){...})

是否有點像上面匿名函數(function(a,b){return a+b;})(1,2);,沒錯,這個就是當即執行的匿名函數,整個框架的邏輯就寫在function中,配置經過options傳入,這樣寫有什麼好處?

  • 更加優雅整潔
  • 擁有獨立的運行環境,多個框架之間不會相互衝突

其中保證擁有獨立運行環境纔是重要緣由,經過匿名函數實現了一個閉包,整個框架的邏輯在閉包中完成,經過function的return給調用者api。但若是經過匿名函數+閉包的方式,如何保證能new Vue({})呢,能夠全局聲明Vue變量,將上面的代碼修改成如下代碼:

(function(global, factory) {
    global.Vue = factory
})(this, function(options) {
    console.log(options);
});

其中global對象在調用時傳入this,this表示window對象,factory就是實現整個邏輯的匿名函數,經過global.Vue = factory將匿名函數定義在window.Vue上,這樣全局均可以使用new Vue實現函數的調用。

參考

相關文章
相關標籤/搜索