fn.apply(this,arguments); // arguments 是发布消息时附送的参数
}
}
//小红的要求 (订阅)
houseObj.listen(function(size){
console.log(‘小红:我要的房子是’+size+‘平米’);
})
//小绿的要求 (订阅)
houseObj.listen(function(size){
console.log(‘小绿:我要的房子是’+size+‘平米’);
})
//执行
houseObj.trigger(100);
houseObj.trigger(150);
存在的问题
-
写完这段代码之后,运行一下,会发现它打印了四次,而我们理想结果是2次,因为houseObj把所有的消息都发给某一个订阅者了。
-
这样对于用户来说是十分不友好的,他只想看他订阅的那条消息。那我们优化一下。
let houseObj = {}; //发布者
houseObj.list = {}; //缓存列表 (花名册) 存放订阅者回调函数
//增加订阅者
houseObj.listen = function(key,fn){ //增加一个唯一标识key
//如果没有订阅过此消息 给该消息创建一个缓存列表
(this.list[key] || (this.list[key] = [])).push(fn)
}
//发布消息 遍历列表
houseObj.trigger = function(){
//取出消息类型名称
let key = Array.prototype.shift.call(arguments);
// 取出该消息对应的回调函数的集合
let fns = this.list[key];
if(!fns || fns.length === 0){
return;
}
for(let i = 0,fn; fn = fns[i++]😉{
fn.apply(this,arguments); // arguments 是发布消息时附送的参数
}
}
//小红的要求 (订阅)
houseObj.listen(‘big’,function(size){
console.log(‘小红:我要的房子是’+size+‘平米’);
})
//小绿的要求 (订阅)
houseObj.listen(‘small’,function(size){
console.log(‘小绿:我要的房子是’+size+‘平米’);
})
//执行
houseObj.trigger(‘big’,100);
houseObj.trigger(‘small’,150);
-
这样我们就会看到控制台只打印了两次,传了一个唯一的key。
-
我们知道,对于上面的代码,对于不同的用户去买房子这么一个对象houseObj 进行订阅,但是如果以后我们需要对买水果子买鞋子或者其他的对象进行订阅呢,我们如果每次都这么去写是不是会很麻烦?
-
我们需要复制上面的代码,再重新改下里面的对象代码;这样是很麻烦的。为此我们需要进行代码封装 :
// 定义一个对象
let event = {
list:{},
listen: function(key,fn){ //增加一个唯一标识key
//如果没有订阅过此消息 给该消息创建一个缓存列表
(this.list[key] || (this.list[key] = [])).push(fn)
},
trigger: function(){
//取出消息类型名称
let key = Array.prototype.shift.call(arguments);
let fns = this.list[key];
if(!fns || fns.length === 0){
return;
}
for(let i = 0,fn; fn = fns[i++]😉{
fn.apply(this,arguments); // arguments 是发布消息时附送的参数
}
}
}
//定义一个initEvent函数,这个函数使所有的普通对象都具有发布订阅功能
let initEvent = function(obj){
for(let i in event){
obj[i] = event[i];
}
};
let houseObj = {}; //发布者对象
initEvent(houseObj); //为对象添加发布-订阅功能
//小明订阅的消息
houseObj.listen(‘big’,function(size){
console.log(‘小明:我要的房子是’+size+‘平米’);
})
//小绿订阅的消息
houseObj.listen(‘small’,function(size){
console.log(‘小绿:我要的房子是’+size+‘平米’);
})
houseObj.trigger(‘big’,100);
houseObj.trigger(‘small’,150);
如上,我们只需要调用initEvent,便可以使所有对象都拥有发布订阅模式。
那么,接下来,如果某用户不想订阅了
如何取消订阅?
//删除订阅
event.remove = function(key,fn){
let fns = this.list[key];
//如果没有定阅过 直接返回false
if(!fns){
return false;
}
// 如果没有传入具体的回调函数,表示需要取消key对应消息的所有订阅
if(!fn){
fn && (fns.length = 0);
}else{
for(let i = fns.length - 1;i >= 0; i-- ){
let _fn = fns[i];
_fn === fn && (fns.splice(i,1)); //删除订阅者对应的回调函数
}
}
}
//其余保持不变
//小明订阅的第一条消息
houseObj.listen(‘big’,fn1 = function(size){
console.log(‘小明:我要的第一套房子是’+size+‘平米’);
})
//小明订阅的第二条消息
总结一下
面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。
还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。
万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。
为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。
前端面试题汇总
JavaScript
性能
linux
前端资料汇总
前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。