May 31, 2021 Article blog
Recently in-depth study of vue source code, the learning process, see some fun functional methods to collect and share, I hope to help you to learn js in depth. If everyone can understand these functions at a glance, the technology is still good Oh.
Object.prototype.toString.call()
returns a data format of the type object, and then uses
slice
to intercept the 8th to the last bit, resulting in Object
var _toString = Object.prototype.toString;
function toRawType (value) {
return _toString.call(value).slice(8, -1)
}
toRawType({}) // Object
toRawType([]) // Array
toRawType(true) // Boolean
toRawType(undefined) // Undefined
toRawType(null) // Null
toRawType(function(){}) // Function
Vue to determine whether the component name we write is html built-in labels, if you use array class traversal then will have to loop many times to get the results, if the array into an object, the label name is set to the key of the object, then do not have to traverse the lookup in turn, only need to find once to get results, improve the efficiency of the search.
function makeMap (str, expectsLowerCase) {
// 构建闭包集合map
var map = Object.create(null);
var list = str.split(',');
for (var i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expectsLowerCase
? function (val) { return map[val.toLowerCase()]; }
: function (val) { return map[val]; }
}
With closures, you can simply call
isHTMLTag
each time you decide if it's a built-in label
var isHTMLTag = makeMap('html,body,base,head,link,meta,style,title')
console.log('res', isHTMLTag('body')) // true
_createElement
vue_createElement the
simpleNormalizeChildren
function is used to format incoming
children
in order to flatten the array and flatten the two-dimensional array, similar to the
flatten
method in
lodash
// 先看lodash中的flatten
_.flatten([1, [2, [3, [4]], 5]])
// 得到结果为 [1, 2, [3, [4]], 5]
// vue中
function simpleNormalizeChildren (children) {
for (var i = 0; i < children.length; i++) {
if (Array.isArray(children[i])) {
return Array.prototype.concat.apply([], children)
}
}
return children
}
// es6中 等价于
function simpleNormalizeChildren (children) {
return [].concat(...children)
}
Vue uses
Object.defineProperty
to collect dependencies, triggering an updated view, but the array cannot monitor changes in the data, but why can an array trigger page updates when using methods such as
push pop
because vue intercepts these methods internally.
// 重写push等方法,然后再把原型指回原方法
var ARRAY_METHOD = [ 'push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice' ];
var array_methods = Object.create(Array.prototype);
ARRAY_METHOD.forEach(method => {
array_methods[method] = function () {
// 拦截方法
console.log('调用的是拦截的 ' + method + ' 方法,进行依赖收集');
return Array.prototype[method].apply(this, arguments);
}
});
var arr = [1,2,3]
arr.__proto__ = array_methods // 改变arr的原型
arr.unshift(6) // 打印结果: 调用的是拦截的 unshift 方法,进行依赖收集
Vue.extend is called
Vue.extend
instantiation component in
Vue.extend
is
VueComponent
constructor, and
VueComponent
inherits Vue with
Object.create
so Vue and
Vue.extend
not very different in normal development.
This side mainly learns to implement inheritance using es5 native methods, of course, the class class in es6 is inherited directly with extends.
// 继承方法
function inheritPrototype(Son, Father) {
var prototype = Object.create(Father.prototype)
prototype.constructor = Son
// 把Father.prototype赋值给 Son.prototype
Son.prototype = prototype
}
function Father(name) {
this.name = name
this.arr = [1,2,3]
}
Father.prototype.getName = function() {
console.log(this.name)
}
function Son(name, age) {
Father.call(this, name)
this.age = age
}
inheritPrototype(Son, Father)
Son.prototype.getAge = function() {
console.log(this.age)
}
Run the results test
var son1 = new Son("AAA", 23)
son1.getName() //AAA
son1.getAge() //23
son1.arr.push(4)
console.log(son1.arr) //1,2,3,4
var son2 = new Son("BBB", 24)
son2.getName() //BBB
son2.getAge() //24
console.log(son2.arr) //1,2,3
The once method is relatively simple, and it would be nice to implement it directly with a closure
function once (fn) {
var called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
}
}
Simple deep copy we can use
JSON.stringify()
but the
looseEqual
shallow copy in vue source code is also very interesting, first type judgment and then recursive call, overall is not difficult, learn the idea.
function looseEqual (a, b) {
if (a === b) { return true }
var isObjectA = isObject(a);
var isObjectB = isObject(b);
if (isObjectA && isObjectB) {
try {
var isArrayA = Array.isArray(a);
var isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) {
return a.length === b.length && a.every(function (e, i) {
return looseEqual(e, b[i])
})
} else if (!isArrayA && !isArrayB) {
var keysA = Object.keys(a);
var keysB = Object.keys(b);
return keysA.length === keysB.length && keysA.every(function (key) {
return looseEqual(a[key], b[key])
})
} else {
/* istanbul ignore next */
return false
}
} catch (e) {
/* istanbul ignore next */
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
function isObject (obj) {
return obj !== null && typeof obj === 'object'
}
Here's a look at
some of the fun functions I found during a recent study of Vue source code by
W3Cschool编程狮