微信LazyMan笔试题的深入解析和实现,如何实现一个

什么落到实处多个 LazyMan?

2016/12/24 · JavaScript · 9 评论 · Javascript, 异步

本文小编: 伯乐在线 - Natumsol 。未经作者许可,防止转发!
招待加入伯乐在线 专辑审核人。

17月份找实习的时候,Wechat面试官给了本人风度翩翩套笔试题,今日关照时无声无息中翻了出来,个中有生龙活虎道题非常风趣:

落到实处二个LazyMan,能够据守以下措施调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!

LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper

依此类推。

那是高人一头的JavaScript流程序调整制,难点的第一是怎么样促成任务的依次实行。在Express有多个看似的事物叫中间件,这个中间件和大家那边的进食、睡觉等职务很接近,每二个中间件推行到位后会调用next()函数,那一个函数用来调用下几在那之中间件。

对此这一个主题素材,我们也得以使用平时的笔触来化解,首先创立二个使命队列,然后选用next()函数来支配职分的次第实践:

JavaScript

function _LazyMan(name) { this.tasks = []; var self = this; var fn =(function(n){ var name = n; return function(){ console.log("Hi! This is " + name + "!"卡塔尔(英语:State of Qatar); self.next(卡塔尔(قطر‎; } }卡塔尔国(name卡塔尔; this.tasks.push(fn卡塔尔; setTimeout(function(卡塔尔{ self.next(卡塔尔(英语:State of Qatar); }, 0卡塔尔国; // 在下叁个事件循环运维职分 } /* 事件调治函数 */ _LazyMan.prototype.next = function() { var fn = this.tasks.shift(); fn && fn(); } _LazyMan.prototype.eat = function(name) { var self = this; var fn =(function(name){ return function(){ console.log("Eat " + name + "~"卡塔尔(英语:State of Qatar); self.next(卡塔尔(英语:State of Qatar) } }卡塔尔(قطر‎(name卡塔尔(قطر‎; this.tasks.push(fn卡塔尔国; return this; // 完结链式调用 } _LazyMan.prototype.sleep = function(time) { var self = this; var fn = (function(time){ return function() { setTimeout(function(){ console.log("Wake up after " + time + "s!"); self.next(); }, time * 1000); } })(time); this.tasks.push(fn); return this; } _LazyMan.prototype.sleepFirst = function(time) { var self = this; var fn = (function(time) { return function() { setTimeout(function() { console.log("Wake up after " + time + "s!"); self.next(); }, time * 1000); } })(time); this.tasks.unshift(fn); return this; } /* 封装 */ function LazyMan(name){ return new _LazyMan(name); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
function _LazyMan(name) {
    this.tasks = [];  
    var self = this;
    var fn =(function(n){
        var name = n;
        return function(){
            console.log("Hi! This is " + name + "!");
            self.next();
        }
    })(name);
    this.tasks.push(fn);
    setTimeout(function(){
        self.next();
    }, 0); // 在下一个事件循环启动任务
}
/* 事件调度函数 */
_LazyMan.prototype.next = function() {
    var fn = this.tasks.shift();
    fn && fn();
}
_LazyMan.prototype.eat = function(name) {
    var self = this;
    var fn =(function(name){
        return function(){
            console.log("Eat " + name + "~");
            self.next()
        }
    })(name);
    this.tasks.push(fn);
    return this; // 实现链式调用
}
_LazyMan.prototype.sleep = function(time) {
    var self = this;
    var fn = (function(time){
        return function() {
            setTimeout(function(){
                console.log("Wake up after " + time + "s!");
                self.next();
            }, time * 1000);
        }
    })(time);
    this.tasks.push(fn);
   return this;
}
_LazyMan.prototype.sleepFirst = function(time) {
    var self = this;
    var fn = (function(time) {
        return function() {
            setTimeout(function() {
                console.log("Wake up after " + time + "s!");
                self.next();
            }, time * 1000);
        }
    })(time);
    this.tasks.unshift(fn);
    return this;
}
/* 封装 */
function LazyMan(name){
    return new _LazyMan(name);
}

打赏支持小编写出越来越多好文章,多谢!

打赏笔者

<pre>
function _lazyman(name) {
this.tasks = [];
var self = this;
var fn = function() {
console.log("hi this is " + name);
self.next();
}
this.tasks.push(fn);
setTimeout(function() {
self.next();
}, 0);
}
// 实现next
_lazyman.prototype.next = function() {
// body...
var fn = this.tasks.shift();
fn && fn();
};
_lazyman.prototype.eat = function(name) {
// body...
var self = this;
var fn = function() {
console.log("eat " + name + " ~");
self.next();
}
this.tasks.push(fn);
// 链式调用
return this;
};
_lazyman.prototype.sleep = function(time) {
// body...
var self = this;
var fn = function() {
setTimeout(function() {
console.log("sleep " + time + "s ~");
self.next();
}, time * 1000);
}
this.tasks.push(fn);
// 链式调用
return this;
};
_lazyman.prototype.sleepFirst = function(time) {
// body...
var self = this;
var fn = function() {
setTimeout(function() {
console.log("sleepFirst " + time + "s ~");
self.next();
}, time * 1000);
}
// unshift
this.tasks.unshift(fn);
// 链式调用
return this;
};
// 封装
function LazyMan(name) {
return new _lazyman(name);
}
</pre>
调用:
<code>
<pre>
LazyMan('hahah').eat('dinner').sleep(10).eat('lunch').sleepFirst(5);
// sleepFirst 10s
// hi this is hahah
// eat dinner
// sleep 10s
// eat lunch
</pre>
</code>
<p>1.兑现链式调用</p>
<p>2.兑现流程序调节制,相通于express中的中间件概念</p>

微信LazyMan笔试题的中肯剖判和兑现

2017/02/03 · JavaScript · Javascript, 异步

原稿出处: wall_wxk   

打赏扶助本身写出越来越多好文章,多谢!

任选意气风发种支付办法

图片 1 图片 2

2 赞 11 收藏 9 评论

黄金年代、标题介绍

以下是自己copy自网络的面试题原作:

兑现三个LazyMan,能够遵照以下方法调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!

LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper

依此类推。

关于小编:Natumsol

图片 3

阿里Baba(Alibaba卡塔尔国 前端程序员 个人主页 · 小编的稿子 · 5 ·    

图片 4

二、标题调查的点

先表明:笔者不是Wechat工作者,考查的点是本人想来的,恐怕不是,哈哈!

1.情势链式调用
2.类的应用和面向对象编制程序的思绪
3.设计形式的运用
4.代码的解耦
5.起码知识规范化,也即 迪米特法规(Law of 德姆eter)
6.代码的书写结议和命名

三、标题思路拆解解析

1.看标题输出示例,能够明确那是拟人化的输出,也正是说:应该编写几个类来定义大器晚成类人,叫做LazyMan。能够出口名字、吃饭、睡觉等行为。
2.从输出的句子可以见见,sleepFrist的优先级是参天的,别的行为的事前级生龙活虎致。
3.从八个例子来看,都得先调用LazyMan来发轫化一位,技艺一而再持续行为,所以LazyMan是一个接口。
4.句子是按调用方法的次第进行每一个推行的,是叁个行列。

四、选拔观看者格局实今世码

4.1 接收模块情势来编排代码

JavaScript

(function(window, undefined){ })(window);

1
2
3
(function(window, undefined){
 
})(window);

4.2 声澳优(Ausnutria Hyproca卡塔尔个变量taskList,用来储存需求队列音讯

JavaScript

(function(window, undefined){ var taskList = []; })(window);

1
2
3
(function(window, undefined){
    var taskList = [];
})(window);

队列中,单个项的存款和储蓄设计为贰个json,存款和储蓄必要接触的消息,以致艺术推行时须要的参数列表。比方LazyMan(‘Hank’卡塔尔国,需求的囤积音讯如下。

JavaScript

{ 'msg':'LazyMan', 'args':'Hank' }

1
2
3
4
{
    'msg':'LazyMan',
    'args':'Hank'
}

当实施LazyMan方法的时候,调用订阅方法,将索要实行的音讯存入taskList中,缓存起来。
仓储的消息,会先保留着,等宣布办法举办领取,实践和出口。

4.3 订阅方法

订阅方法的调用情势设计:subscribe("lazyMan", "Hank")

JavaScript

(function(window, undefined){ var taskList = []; // 订阅 function subscribe(卡塔尔(英语:State of Qatar){ var param = {}, args = Array.prototype.slice.call(arguments卡塔尔(قطر‎; if(args.length < 1卡塔尔国{ throw new Error("subscribe 参数不可能为空!"); } param.msg = args[0]; // 消息名 param.args = args.slice(1卡塔尔; // 参数列表 if(param.msg == "sleepFirst"卡塔尔{ taskList.unshift(param卡塔尔(英语:State of Qatar); }else{ taskList.push(param卡塔尔国; } } }卡塔尔(قطر‎(window卡塔尔国;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(function(window, undefined){
    var taskList = [];
 
    // 订阅
    function subscribe(){
        var param = {},
            args = Array.prototype.slice.call(arguments);
 
        if(args.length < 1){
            throw new Error("subscribe 参数不能为空!");
        }
 
        param.msg = args[0]; // 消息名
        param.args = args.slice(1); // 参数列表
 
        if(param.msg == "sleepFirst"){
            taskList.unshift(param);
        }else{
            taskList.push(param);
        }
    }
})(window);

用一个param变量来协会好内需仓库储存的音信,然后push进taskList中,缓存起来。
专程的,要是是sleepFirst,则停放在队列底部。

4.4 发表办法

JavaScript

(function(window, undefined){ var taskList = []; // 订阅方法 代码... // 公布 function publish(卡塔尔国{ if(taskList.length > 0卡塔尔{ run(taskList.shift(卡塔尔(英语:State of Qatar)卡塔尔国; } } }卡塔尔国(window卡塔尔(قطر‎;

1
2
3
4
5
6
7
8
9
10
11
12
(function(window, undefined){
    var taskList = [];
 
        // 订阅方法 代码...
 
    // 发布
    function publish(){
        if(taskList.length > 0){
            run(taskList.shift());
        }
    }
})(window);

将队列中的存款和储蓄音信读抽出来,交给run方法(暂定,后续实现)去推行。这里限制每一次发表只举办叁个,以保全队列之中的方法能够挨个实践。
别的,这里运用shift(卡塔尔国方法的由来是,抽取四个,就在队列中删除那二个,制止重复实践。

4.5 实现LazyMan类

JavaScript

// 类 function LazyMan(){}; LazyMan.prototype.eat = function(str){ subscribe("eat", str); return this; }; LazyMan.prototype.sleep = function(num){ subscribe("sleep", num); return this; }; LazyMan.prototype.sleepFirst = function(num){ subscribe("sleepFirst", num); return this; };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 类
function LazyMan(){};
 
LazyMan.prototype.eat = function(str){
    subscribe("eat", str);
    return this;
};
 
LazyMan.prototype.sleep = function(num){
    subscribe("sleep", num);
    return this;
};
 
LazyMan.prototype.sleepFirst = function(num){
    subscribe("sleepFirst", num);
    return this;
};

将LazyMan类实现,具有eat、sleep、sleepFrist等行为。
接触一遍表现,就在taskList中著录二次,并再次来到当前目的,以支撑链式调用。

4.6 完毕出口console.log的卷入方式

JavaScript

// 输出文字 function lazyManLog(str卡塔尔(قطر‎{ console.log(str卡塔尔; }

1
2
3
4
// 输出文字
function lazyManLog(str){
    console.log(str);
}

为啥还要为console.log包装生龙活虎层,是因为在实战项目中,产经平时会校正出口提醒的UI。假使每风流倜傥处都用console.log直接调用,那改起来就劳动相当多。
别的,若是要包容IE等中低等版本浏览器,也足以很有益于的修正。
也就是DRY原则(Don’t Repeat Youself)。

4.7 达成具体实施的章程

JavaScript

// 具体方法 function lazyMan(str卡塔尔(英语:State of Qatar){ lazyManLog("Hi!This is "+ str +"!"); publish(); } function eat(str){ lazyManLog("Eat "+ str +"~"); publish(); } function sleep(num){ setTimeout(function(){ lazyManLog("Wake up after "+ num); publish(); }, num*1000); } function sleepFirst(num){ setTimeout(function(){ lazyManLog("Wake up after "+ num); publish(); }, num*1000); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 具体方法
function lazyMan(str){
    lazyManLog("Hi!This is "+ str +"!");
 
    publish();
}
 
function eat(str){
    lazyManLog("Eat "+ str +"~");
    publish();
}
 
function sleep(num){
    setTimeout(function(){
        lazyManLog("Wake up after "+ num);
 
        publish();
    }, num*1000);
 
}
 
function sleepFirst(num){
    setTimeout(function(){
        lazyManLog("Wake up after "+ num);
 
        publish();
    }, num*1000);
}

那边的至关重假设解决setTimeout推行时会延迟调用,也即线程异步试行的标题。只有该方式推行成功后,再发表一次消息publish(),提醒能够实践下叁个行列音讯。不然,就能够直接等候。

4.8 完结run方法,用于识别要调用哪个具体方法,是二个总的调节台

JavaScript

// 鸭子叫 function run(option){ var msg = option.msg, args = option.args; switch(msg){ case "lazyMan": lazyMan.apply(null, args);break; case "eat": eat.apply(null, args);break; case "sleep": sleep.apply(null,args);break; case "sleepFirst": sleepFirst.apply(null,args);break; default:; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
// 鸭子叫
function run(option){
    var msg = option.msg,
        args = option.args;
 
    switch(msg){
        case "lazyMan": lazyMan.apply(null, args);break;
        case "eat": eat.apply(null, args);break;
        case "sleep": sleep.apply(null,args);break;
        case "sleepFirst": sleepFirst.apply(null,args);break;
        default:;
    }
}

本条点子有一点像鸭式辨型接口,所以注释叫鸭子叫
run方法选择队列中的单个音讯,然后读抽出来,看消息是如何类型的,然后实践相应的方式。

4.9 暴露接口LazyMan,让外界能够调用

JavaScript

(function(window, undefined卡塔尔(英语:State of Qatar){ // 比较多代码... // 暴光接口 window.LazyMan = function(str卡塔尔(英语:State of Qatar){ subscribe("lazyMan", str卡塔尔; setTimeout(function(卡塔尔国{ publish(卡塔尔; }, 0卡塔尔(قطر‎; return new LazyMan(卡塔尔; }; }卡塔尔国(window卡塔尔(قطر‎;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function(window, undefined){
        // 很多代码...
 
    // 暴露接口
    window.LazyMan = function(str){
        subscribe("lazyMan", str);
 
        setTimeout(function(){
            publish();
        }, 0);
 
        return new LazyMan();
    };
})(window);

接口LazyMan里面包车型大巴publish方法必须利用setTimeout实行调用。那样能让publish()进行的线程延后,挂起。等链式方法都进行完结后,线程空闲下来,再实施该publish()
除此以外,那是二个对外接口,所以调用的时候,同不日常候也会new 三个新的LazyMan,并重临,以供调用。

五、总结

1. 好处

选取观看者情势,让代码能够解耦到合理的水平,使中期维护尤其方便。
举个例子自身想改革eat主意,作者只供给关切eat()LazyMan.prototype.eat的兑现。别的地点,笔者都能够不用关爱。那就相符了起码知识标准化

2. 不足
LazyMan.prototype.eat这种情势的参数,其实可以用arguments代替,作者没写出来,怕弄得太复杂,就留个优化点吗。
采取了unshift和shift方法,未有思量到低版本IE浏览器的优质。

六、完整源码和线上demo

完整源码已经坐落于自身的gitHub上

源码入口:

demo访谈地址:

demo须要开垦调控台,在调整新北调理代码。

七、番外

互连网有人也促成了lazyMan,然而落到实处的主意自个儿不是很心爱和认同,可是也是风姿洒脱种思路,这里顺便贴出来给大伙看看。
怎样落实多少个LazyMan:

1 赞 收藏 评论

图片 5

本文由澳门威斯尼人平台登录发布于Web前端,转载请注明出处:微信LazyMan笔试题的深入解析和实现,如何实现一个

相关阅读