//为count扩展策略
Vue.config.optionMergeStrategies.count = function (parent, child, vm) {
return child + 1
}
//合并结束后count的值就会变成2,不再是1
回到主题,那么到这里可以知道strats[key],就是去暴露的接口上查有没有自定义方法,如果有,那么将其对应的方法给到start;
然后再看一下defaultStrat
var defaultStrat = function(parentVal, childVal) {
return childVal === undefined ? parentVal : childVal;
};
根据前面的strats[key]可以猜到,既然前面的是合并的自定义策略,那这个肯定就是默认策略了,这是一个函数表达式,就是判断在传入的参数childVal有没有,如果有,返回childVal,如果没有就返回parentVal;
到这里可以明白
var start = strats[key] || defaultStrat;
这一行代码就是做了个判断,判断自定义的属性有没有对于的合并策略,如果有,那么按用户定义的合并策略进行,如果没有,那么就按默认的策略进行,并且不管哪种策略,都是一个函数;
接着就是执行合并了
//合并,并且将值赋值给了options[key]
options[key] = start(parentVal[key], childVal[key], vm, key)
options是一开始定义的空对象,并且该函数最终也是将options作为返回值返回出去的;
到这里函数基本弄清楚了,**mergeOptions()**这个函数就是在检测判断当前属性是内置的,还是自定义的,如果是自定义的,那么判断有没有自定义的合并策略,如果有,那么就按自定义的合并策略进行合并,如果没有,那么按默认的合并策略进行合并;
接着就是理解参数了,调用的时候一共传了3个参数(其中第一个参数Vue.options,实际上Vue不是这么写的,实际上远复杂的多,这里只是简化了)
vm.$options = mergeOptions(Vue.options, params || {}, vm);
其中params和vm都好理解,params就是实例化时传入的参数,vm指的是this,第一个参数Vue.options则是一个跨作用域的属性
Vue.options = Object.create(null); //等同于Vue.options = {}
通过查询知道,其实Vue.options默认的状态也是一个空对象,之后
//定义属性名,也就是vue上的component等
var ASSET_TYPES = [
‘component’,
‘directive’,
‘filter’
];
ASSET_TYPES.forEach(el=>{
Vue.options[el+“s”] = Object.create(null);
})
通过内置的ASSET_TYPES对其进行进行循环,将每个属性值添加到空对象上,这里就又有一个疑问,为什么要这么写,直接加s不好吗,为什么要通过遍历再加s,最好发现其实这个是为了保证属性的统一,因为component等这些有的上面是components,有的则是component,因此宁可多写几行代码,也要保证属性的高度统一;
因此,Vue.options就是一个内置属性的集合;
通过mergeOptions()这个函数将内置属性和传入的参数进行合并,并且合并的时候通过hasOwn()函数判断指定对象上是否有指定属性,假如有就跳过,从而达到相同属性只执行一次的效果,优化了合并速度;
之后判断传入对象上是否有自定义属性和自定义合并策略,如果有自定义合并策略,那么合并按自定义的规定合并,如果没有就按默认策略合并;
=================================================================
在合并策略中叙述到了一个自定义策略的问题,既然自定义策略是暴露给外界用户的接口,那么如果被篡改了怎么办,比如
//传入的参数多了一个count,这个属性不是官方提供的
var vm = new Vue({
el:“#app” ,
data:{
name:“Oliver尹”
},
beforeCreate() {},
count:1
})
//为count扩展策略
//Vue.config.optionMergeStrategies.count = function (parent, child, vm) {
// return child + 1
//}
//不对config.optionMergeStrategies进行扩展,而进程篡改,比如
Vue.config.optionMergeStrategies = 1;
直接将暴露的对象给修改掉怎么办,在Vue中的处理是这样的
//还是对自定义策略做一个监听,监听暴露的接口是不是有被修改,如果是被修改,那么报错,如果是访问直接将config返回出去
function initGlobalAPI(Vue){
var configDef = Object.create(null);
configDef.get = function () {
return config
}
configDef.set = function (params) {
console.error(“请不要尝试修改Vue.config”);
return;
}
Object.defineProperty(Vue, “config”, configDef)
}
Vue并没有直接去给对象扩展属性,而是采用监听属性的方式,如果你是访问的方式去获得属性,那么访问哪个,就直接通过get返回哪个,但如果是对其进set行设置,则不行,直接报错,不允许进行修改(新技能获得);
因此,Vue中是通过get和set属性对其进行监听的,而没有直接对一个对象进行修改;
================================================================
在2.5.1的版本中,Vue一共设置了11个生命周期函数,其原理是相同的,就是在不同的阶段执行函数callHook(),具体请看下例
//执行合并参数的初始化
function initMixin(Vue){
//给函数Vue的原型添加一个_init的方法
Vue.prototype._init = function(params) {
console.log(this);
//存储this
var vm = this;
/**
-
初始化前,对vue这个构造函数再扩展一个$options属性,
-
mergeOptions用于合并传入的参数和需要添加的默认参数
-
*/
vm.$options = mergeOptions(Vue.options, params || {}, vm);
/**
-
执行beforeCreate钩子函数,
-
也就是为什么执行beforeCreate的时候,data中以及有值了,因为已经进行了参数合并
-
*/
callHook(vm, ‘beforeCreate’);
}
}
这是之前的初始化函数initMin,当执行合并参数结束以后,就开始执行beforeCreate这个生命周期,当然在这之前,还需要定义钩子函数;
//2.5.1版本的钩子函数
var LIFECYCLE_HOOKS = [
‘beforeCreate’,
‘created’,
‘beforeMount’,
‘mounted’,
‘beforeUpdate’,
‘updated’,
‘beforeDestroy’,
‘destroyed’,
‘activated’,
‘deactivated’,
‘errorCaptured’
];
之后会对这11个钩子函数进行一次批量处理,处理的方法就是forEach
/**
- 钩子函数的批量处理
*/
LIFECYCLE_HOOKS.forEach((el)=>{
strats[el] = mergeHook;
})
上面已经知道了,这个strats其实就是暴露给外界的接口config.optionMergeStrategies,这里将每一个钩子函数都作为对象添加到这个接口上;
到这里就解释了,每一个生命周期函数其实都会被添加到这个config.optionMergeStrategies对象上并且作为自定义策略生效了;
接着给每一个生命周期函数赋值了mergeHook
/**
-
所有钩子函数的自定义的策略
-
同样钩子函数也是定义在传入的参数内,因此所有的钩子函数也会经历过mergeOptions这个函数的处理
-
最终将钩子函数合并到vm.$options上,
-
@param {*} parentVal parentVal === undefined ,因为Vue.options上没有这些钩子函数的属性名
-
@param {*} childVal 传入包含el,data的参数
-
最终它会将所有钩子函数包装成一个数组,比如beforeCreate会被包装成[function(){},function(){}]
-
因此所有的钩子函数都可以写出数组的形式,不必局限于函数的形式,因为在vue的内部,所有的钩子函数最终都会被转成数组
*/
function mergeHook(parentVal,childVal){
return childVal? parentVal ? parentVal.concat(childVal) : Array.isArray(childVal) ? childVal : [childVal] : parentVal;
}
请重点看注释,通过这个mergeHook函数,Vue会将所有钩子函数包装成数组,所以实际上钩子函数还有别的写法不仅仅局限于一个函数,也可以是一个数组,数组中的每一项是一个函数
var vm = new Vue({
el:“#app” ,
data:{
name:“Oliver尹”
},
//通过源码知道,这么写其实也没有问题的
beforeCreate:[function(){}, function(){}],
})
console.log(vm.$options)
先看代码
//vm:当前的this
//beforeCreate:需要执行的函数的名字
callHook(vm, ‘beforeCreate’);
//执行钩子函数的函数
function callHook(vm, hook){
//这里的时候 o p t i o n s 已经合并完了,因此钩子函数等也已经合并到 options已经合并完了,因此钩子函数等也已经合并到 options已经合并完了,因此钩子函数等也已经合并到options上了,并且肯定是数组,因为不是数组也已经转成数组了
var handle = vm.$options[hook];
//如果有handle,依次执行
/**
- 因为使用call将vm传进去了,因此钩子函数里的this指向的是vue的根实例
*/
if(handle){
for(var i = 0 , j = handle.length ; i < j ; i++){
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
最后
总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
**
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-b0kYiyfb-1712785407636)]
最后
总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
[外链图片转存中…(img-0eAE14HR-1712785407636)]
[外链图片转存中…(img-zZdzfycc-1712785407637)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-nocmQYep-1712785407637)]