Vue.set
Vue.set( target, key, value ),target不能是 Vue 實例,或者 Vue 實例的根數據對象,因為源碼中做了如下判斷:
var ob = (target).__ob__; if (target._isVue || (ob && ob.vmCount)) { "development" !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + 'at runtime - declare it upfront in the data option.' ); return val }
target._isVue阻止了給Vue實例添加屬性,ob && ob.vmCount阻止了給Vue實例的根數據對象添加屬性。
Vue.delete
如果Vue能檢測到delete操作,那么就不會出現這個api。如果一定要用delete來刪除$data的屬性,那就用Vue.delete,否則不會觸發dom的更新。
同Vue.set,Vue.delete( target, key )的target不能是一個 Vue 示例或 Vue 示例的根數據對象。源碼中的阻止方式和Vue.set相同。
在2.2.0+ 版本中target若為數組,key則是數組下標。因為Vue.delete刪除數組實際是用splice來刪除,delete雖然能用於刪除數組,但位置還在,不能算真正的刪除。
var a = [1, 2, 3]; delete a[0]; console.log(a); // [undefined, 2, 3]
Vue.use
Vue.use 源碼比較簡單,可以全部貼出來。
Vue.use = function (plugin) { var installedPlugins = (this._installedPlugins || (this._installedPlugins = [])); if (installedPlugins.indexOf(plugin) > -1) { return this } // additional parameters var args = toArray(arguments, 1); args.unshift(this); if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args); } else if (typeof plugin === 'function') { plugin.apply(null, args); } installedPlugins.push(plugin); return this };
安裝的插件放到了 installedPlugins ,安裝插件前通過installedPlugins.indexOf(plugin)來判斷插件是否被安裝過,進而阻止注冊相同插件多次。
插件類型為 object,必須指定 install 屬性來安裝插件(typeof plugin.install === 'function'),另外插件執行采用plugin.install.apply(plugin, args);,因此 this 訪問 object 的其他屬性。此處的 args 是由 Vue(args.unshift(this);) 和 Vue.use 傳入的除了 plugin 的其他參數(toArray(arguments, 1),1 表示從 arguments[1] 開始截取)。
Vue.use({ a: 1, install: function (Vue) { console.log(this.a) // 1 console.log(arguments) // [function Vue(options),"a", "b", "c"] } }, 'a', 'b', 'c')
插件類型為 function,安裝調用plugin.apply(null, args);,因此在嚴格模式下插件運行時上下文 this 為 null,非嚴格模式為 Window。
'use strict' Vue.use(function plugin() { console.log(this) // null console.log(arguments) // [function Vue(options),"a", "b", "c"] }, 'a', 'b', 'c')
Vue.extend
配置項data必須為function,否則配置無效。data的合並規則源碼如下:
strats.data = function ( parentVal, childVal, vm ) { if (!vm) { if (childVal && typeof childVal !== 'function') { "development" !== 'production' && warn( 'The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm ); return parentVal } return mergeDataOrFn(parentVal, childVal) } return mergeDataOrFn(parentVal, childVal, vm) };
傳入非function類型的data(上圖中data配置為{a:1}),在合並options時,如果data不是function類型,開發版會發出警告,然后直接返回了parentVal,這意味着extend傳入的data選項被無視了。
我們知道實例化Vue的時候,data可以是對象,這里的合並規則不是通用的嗎?注意上面有個if(!vm)的判斷,實例化的時候vm是有值的,因此不同於Vue.extend,其實下面的注釋也做了說明(in a Vue.extend merge, both should be function),這也是官方文檔為何說data是個特例。
另外官方文檔所說的“子類”,是因為Vue.extend返回的是一個“繼承”Vue的函數,源碼結構如下:
Vue.extend = function (extendOptions) { //*** var Super = this; var SuperId = Super.cid; //*** var Sub = function VueComponent(options) { this._init(options); }; Sub.prototype = Object.create(Super.prototype); Sub.prototype.constructor = Sub; //*** return Sub