initProxy
- In addition to preparing for building a responsive system, the idea of data interception can also filter data. Let's look down at the initialization code. After merging options, vue will set a layer of agent for vm instances, which can filter data for vue during template rendering
Vue.prototype._init = function(options) { // Option merge ... { // A layer of proxy for vm instances initProxy(vm); } ... }
initProxy
// Surrogate function var initProxy = function initProxy (vm) { //Does Proxy support if (hasProxy) { var options = vm.$options; //When you use a packaging tool like webpack, you usually use the Vue loader plug-in to compile the template. At this time, options Render exists, and_ The withstriped property will also be set to true (for the difference between the compiled version and the runtime version, please refer to the following chapters), so the agent option is hasHandler at this time //In other scenarios, the proxy option is getHandler var handlers = options.render && options.render._withStripped ? getHandler : hasHandler; // Proxy vm instance to vm attribute_ renderProxy vm._renderProxy = new Proxy(vm, handlers); } else { vm._renderProxy = vm; } };
hasProxy
var hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy);
hasHandler
var hasHandler = { // The hook of has will be triggered when the key is in obj or with scope has: function has (target, key) { ··· } };
Trigger agent
- VM_ The use of renderproxy appears in the of Vue instances_ In the render method, Vue prototype._ Render is a method to convert rendering functions into Virtual DOM. This part is about instance mounting and template engine parsing
- When we call the render function, the VM_ The renderproxy object will access
- The render function is an execution statement packaged as with. During the execution of the with statement, the access of variables under the scope will trigger the has hook, which is also the reason why proxy interception will be triggered during template rendering
- Data proxy interception is triggered because variables are used in the template, such as < div > {message}
Vue.prototype._render = function () { ··· // Call VM_ renderProxy vnode = render.call(vm._renderProxy, vm.$createElement); } ========================================= var vm = new Vue({ el: '#app' }) console.log(vm.$options.render) //Output, template rendering using with statement ƒ anonymous() { with(this){return _c('div',{attrs:{"id":"app"}},[_v(_s(message)+_s(_test))])} }
Data filtering
- Use the data option to set instance data. Can these data be named arbitrarily according to personal habits? Obviously not. If you use js keywords (such as Object,Array,NaN) to name, this is not allowed. On the other hand, Vue source code uses $_ As an internal variable starting with $_ Variable names at the beginning are also not allowed, which constitutes the premise of data filtering and monitoring.
var hasHandler = { has: function has (target, key) { var has = key in target; // isAllowed is used to determine whether the variables appearing on the template are legal. var isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); // _ Variables starting with and $are not allowed to appear in the defined data because they are the beginning of vue internal reserved attributes. // 1. warnReservedPrefix: warning cannot be in $_ Variable at the beginning // 2. warnNonPresent: the variables appearing in the warning template are not defined in the vue instance //has determines whether it is a variable in the target object if (!has && !isAllowed) { if (key in target.$data) { warnReservedPrefix(target, key); } else { warnNonPresent(target, key); } } return has || !isAllowed } }; // Non vue instance defined variables allowed in the template var allowedGlobals = makeMap( 'Infinity,undefined,NaN,isFinite,isNaN,' + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + 'require' // for Webpack/Browserify );
Data filtering when the browser does not support proxy
- Without an agent, use_ The initial variable will still report an error, but it has become an error at the js language level. However, the details of the error cannot be known at the Vue layer, which is the advantage of using Proxy.
- In the data initialization phase, Vue has a layer of filtering agent for the data. See initData proxy for data
function initData(vm) { vm._data = typeof data === 'function' ? getData(data, vm) : data || {} if (!isReserved(key)) { // Data broker, users can directly return data through vm instances proxy(vm, "_data", key); } } function isReserved (str) { var c = (str + '').charCodeAt(0); // The first character is $_ String of return c === 0x24 || c === 0x5F }