In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-04 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article will explain in detail why Vue2 this can directly access data and methods, the content of the article is of high quality, so the editor will share it with you for reference. I hope you will have some understanding of the relevant knowledge after reading this article.
1. Example: this can get data and methods directly
For example:
Const vm = new Vue ({data: {name:'I am Ruochuan',}, methods: {sayName () {console.log (this.name);}},},}); console.log (vm.name); / / I am Yoshikawa console.log (vm.sayName ()); / / I am Ruochuan
This can export that I am Ruochuan. Curious people will wonder why this can access it directly.
So why can this.xxx get the data in data and the methods method?
We construct the function written by ourselves, how to achieve the effect similar to Vue.
Function Person (options) {} const p = new Person ({data: {name: 'Ruochuan'}, methods: {sayName () {console.log (this.name);}); console.log (p.name); / / undefinedconsole.log (p.sayName ()); / / Uncaught TypeError: p.sayName is not a function
If it were you, how would you achieve it? With questions, let's debug Vue2 source code learning.
two。 Prepare the environment to debug the source code
You can create a new folder examples and a new file index.html file locally.
Add the following js in.
Const vm = new Vue ({data: {name:'I am Ruochuan',}, methods: {sayName () {console.log (this.name);}},}); console.log (vm.name); console.log (vm.sayName ())
Then install the npm I-g http-server startup service globally.
Npm I-g http-servercd exampleshttp-server. / / if the port is occupied, you can also specify port http-server-p 8081.
In this way, you can open the index.html page you just wrote in http://localhost:8080/.
Debug: open debug in F12, source panel, in the example const vm = new Vue ({hit a breakpoint.
After refreshing the page, press F11 to enter the function, and the breakpoint goes into the Vue constructor.
2.1 Vue constructor function Vue (options) {if (! (this instanceof Vue)) {warn ('Vue is a constructor and should be called with the `new` keyword');} this._init (options);} / / initialize initMixin (Vue); stateMixin (Vue); eventsMixin (Vue); lifecycleMixin (Vue); renderMixin (Vue)
It is worth mentioning that if (! (this instanceof Vue)) {} determines whether the constructor is called with the new keyword.
Generally speaking, we should not consider writing this at ordinary times.
Of course, if you look at the source code library, you can also call new within your own function. But vue generally requires new Vue () only once for a project, so it's not necessary.
The jQuery source code is the internal new, which is the new-free construction for the user.
JQuery = function (selector, context) {/ / returns the object return new jQuery.fn.init (selector, context) after new;}
Because it is often called to use jQuery.
Actually, jQuery can also be new. And not using new is the same effect.
Debug: continue to hit a breakpoint at this._init (options); and press F11 to enter the function.
2.2 _ init initialization function
After entering the _ init function, this function is relatively long and does a lot of things, and we guess that the implementation related to data and methods is in the initState (vm) function.
/ / the code has been deleted function initMixin (Vue) {Vue.prototype._init = function (options) {var vm = this; / / a uid vm._uid = uid$3++; / / a flag to avoid this being observed vm._isVue = true / merge options if (options & & options._isComponent) {/ / optimize internal component instantiation / / since dynamic options merging is pretty slow, and none of the / / internal component options needs special treatment. InitInternalComponent (vm, options);} else {vm.$options = mergeOptions (resolveConstructorOptions (vm.constructor), options | | {}, vm);} / / expose real self vm._self = vm; initLifecycle (vm); initEvents (vm); initRender (vm); callHook (vm, 'beforeCreate'); initInjections (vm) / / resolve injections before data/props / / initialization status initState (vm); initProvide (vm); / / resolve provide after data/props callHook (vm, 'created');};}
Debug: then we prepare the breakpoint here in the initState (vm) function, press F8 to jump to this breakpoint directly, and then press F11 to enter the initState function.
2.3 initState initialization status
From the point of view of the function name, the main functions of this function are:
Initialize props
Initialize methods
Monitoring data
Initialize computed
Initialize watch
Function initState (vm) {vm._watchers = []; var opts = vm.$options; if (opts.props) {initProps (vm, opts.props);} / / incoming methods, initialization method if (opts.methods) {initMethods (vm, opts.methods);} / / incoming data, initialize data if (opts.data) {initData (vm) } else {observe (vm._data = {}, true / * asRootData * /);} if (opts.computed) {initComputed (vm, opts.computed);} if (opts.watch & & opts.watch! = = nativeWatch) {initWatch (vm, opts.watch);}}
Let's focus on initializing methods and then initializing data.
Debug: make a breakpoint in initMethods and a breakpoint in initData (vm). After reading the initMethods function, you can press F8 to return to the initData (vm) function directly. Continue to press F11 and enter the initMethods function first.
2.4 initMethods initialization method function initMethods (vm, methods) {var props = vm.$options.props; for (var key in methods) {{if (typeof methods [key]! = = 'function') {warn ("Method\"+ key +"\ "has type\") + (typeof methods [key]) +"\ "in the component definition. "+" Did you reference the function correctly? ", vm);} if (props & & hasOwn (props, key)) {warn ((" Method\ "" + key + "\" has already been defined as a prop. "), vm) } if ((key in vm) & & isReserved (key)) {warn ("Method\"+ key +"\ "conflicts with an existing Vue instance method. "+" Avoid defining component methods that start with _ or $. ");}} vm [key] = typeof methods [key]! = 'function'? Noop: bind (methods [key], vm);}}
InitMethods function, there are mainly some judgments.
Determine whether each item in the methods is a function, if not a warning.
Determine if each item in the methods conflicts with the props, and if so, warn.
Determine whether each item in the methods already exists on the new Vue instance vm, and that the method name starts with a reserved _ $(which generally refers to the internal variable identity in JS), if it is a warning.
Apart from these judgments, we can see that the initMethods function is actually traversing the incoming methods object and using the this of the bind binding function to point to vm, that is, the instance object of new Vue.
This is why we can access the functions in methods directly through this.
We can move the mouse over the bind variable, press the alt key, you can see the function definition, here is line 218, click to jump here to see the implementation of bind.
2.4.1 bind returns a function that modifies this to point to function polyfillBind (fn, ctx) {function boundFn (a) {var l = arguments.length; return l? L > 1? Fn.apply (ctx, arguments): fn.call (ctx, a): fn.call (ctx)} boundFn._length = fn.length; return boundFn} function nativeBind (fn, ctx) {return fn.bind (ctx)} var bind = Function.prototype.bind? NativeBind: polyfillBind
To put it simply, it is compatible with native bind functions that are not supported in older versions. At the same time compatible with writing, make a judgment on the number of parameters, using call and apply implementation, it is said to be due to performance problems.
If you are not familiar with the usage and implementation of call, apply and bind, can you simulate the call and apply methods of implementing JS
Debugging: after reading the initMethods function, press F8 to return to the breakpoint of the initData (vm) function mentioned above.
2.5 initData initialize data
The initData function is also some judgment. The main things done are as follows:
Assign a value to _ data for later use.
The resulting data is not an object to give a warning.
Iterate through data, each of which:
If there is a conflict with methods, report a warning.
If there is a conflict with props, report a warning.
It is not an internal private reserved attribute, do a layer of proxy, proxy to _ data.
Finally, the data is monitored to make it responsive data.
Function initData (vm) {var data = vm.$options.data; data = vm._data = typeof data = = 'function'? GetData (data, vm): data | {}; if (! isPlainObject (data)) {data = {}; warn ('data functions should return an object:\ n' + 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', vm);} / / proxy data on instance var keys = Object.keys (data); var props = vm.$options.props Var methods = vm.$options.methods; var I = keys.length; while (iMuk -) {var key = keys [I]; {if (methods & & hasOwn (methods, key)) {warn (("Method\"+ key +"\ "has already been defined as a data property."), vm) }} if (props & & hasOwn (props, key)) {warn ("The data property\"+ key +"\ "is already declared as a prop. "+" Use prop default value instead. ", vm);} else if (! isReserved (key)) {proxy (vm," _ data ", key);}} / / observe data observe (data, true / * asRootData * /);} 2.5.1 getData to obtain data
The function is called when it is a function, and the execution gets the object.
Function getData (data, vm) {/ / # 7573 disable dep collection when invoking data getters pushTarget (); try {return data.call (vm, vm)} catch (e) {handleError (e, vm, "data ()"); return {}} finally {popTarget ();} 2.5.2 proxy Agent
In fact, it uses Object.defineProperty to define objects.
The purpose here is: this.xxx is the this._data.xxx that you visit.
/ * Perform no operation. * Stubbing args to make Flow happy without leaving useless transpiled code * with... rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). * / function noop (a, b, c) {} var sharedPropertyDefinition = {enumerable: true, configurable: true, get: noop, set: noop}; function proxy (target, sourceKey, key) {sharedPropertyDefinition.get = function proxyGetter () {return this [sourceKey] [key]}; sharedPropertyDefinition.set = function proxySetter (val) {this [sourceKey] [key] = val;}; Object.defineProperty (target, key, sharedPropertyDefinition) } 2.5.3 Object.defineProperty defines object properties
Object.defineProperty is a very important API. There is also an API:Object.defineProperties (obj, props) (ES5) that defines multiple attributes.
Object.defineProperty involves more important knowledge points, which are often tested in interviews.
The value returned by value-- when it attempts to get the property.
Writable-- whether the property is writable.
Enumerable-- whether this property will be enumerated in the for in loop.
Configurable-- whether the attribute can be deleted.
Set ()-the function called by the update operation for this property.
Get ()-the function that is called when the property value is obtained.
Finally, explain whether 2.6.1 hasOwn is the property debug mode owned by the object itself. Press alt key, move the mouse over the method name, and you can see where the function is defined. Click to jump. / * Check whether an object has the property. * / var hasOwnProperty = Object.prototype.hasOwnProperty;function hasOwn (obj, key) {return hasOwnProperty.call (obj, key)} hasOwn ({a: undefined},'a') / / truehasOwn ({},'a') / / falsehasOwn ({}, 'hasOwnProperty') / / falsehasOwn ({},' toString') / / false// is your own attribute and is not found up through the prototype chain. 2.6.2 whether isReserved is an internally private reserved string of $and _ beginning / * Check if a string starts with $or _ * / function isReserved (str) {var c = (str +') .charCodeAt (0); return c = 0x24 | | c = 0x5F} isReserved ('_ data'); / / trueisReserved ('$options'); / / trueisReserved ('data'); / / falseisReserved (' options'); / / false3. Finally, the simplified version of function noop (a, b, c) {} var sharedPropertyDefinition = {enumerable: true, configurable: true, get: noop, set: noop}; function proxy (target, sourceKey, key) {sharedPropertyDefinition.get = function proxyGetter () {return this [sourceKey] [key]}; sharedPropertyDefinition.set = function proxySetter (val) {this [sourceKey] [key] = val;} is implemented with more than 60 lines of code. Object.defineProperty (target, key, sharedPropertyDefinition);} function initData (vm) {const data = vm._data = vm.$options.data; const keys = Object.keys (data); var I = keys.length; while (iMuk -) {var key = keys [I]; proxy (vm,'_ data', key);} function initMethods (vm, methods) {for (var key in methods) {vm [key] = typeof methods [key]! = 'function'? Noop: methods [key] .bind (vm);} function Person (options) {let vm = this; vm.$options = options; var opts = vm.$options; if (opts.data) {initData (vm) } if (opts.methods) {initMethods (vm, opts.methods)}} const p = new Person ({data: {name: 'Ruochuan'}, methods: {sayName () {console.log (this.name);}); console.log (p.name); / / before implementation: undefined// 'Ruochuan' console.log (p.sayName ()) / / before implementation: Uncaught TypeError: p.sayName is not a function// 'Ruochuan' 4. Summary
The basic knowledge involved in this paper is as follows:
Constructor function
This points to
Call 、 bind 、 apply
Object.defineProperty
This article originates from answering the source code common reading group's questions, through a detailed description of how to debug the Vue source code, to explore the answer.
Answer the questions at the beginning of the article:
The reason for directly accessing the function in methods through this is that the method in methods specifies this as the instance of new Vue (vm) through bind.
The reason for directly accessing the data in data through this is that the attributes in data will eventually be stored in the _ data object on the instance (vm) of new Vue. Accessing this.xxx is the this._data.xxx after accessing the Object.defineProperty proxy.
The advantage of this design of Vue is that it is easy to obtain. There is also an inconvenience, that is, props, methods and data are easy to conflict.
The overall difficulty of the article is not great, but readers are highly recommended to debug it themselves. After debugging, you may find that the original Vue source code is not so difficult as expected, but also can understand part of it.
On why Vue2 this can directly get data and methods to share here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.