做完两道题,WechatLazyMan笔试题的通透到底解析和
分类:前端技术

怎么样落到实处五个 LazyMan?

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

本文小编: 伯乐在线 - Natumsol 。未经小编许可,禁绝转发!
招待加入伯乐在线 专栏审核人。

7月份找实习的时候,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 "!"); 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); }

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   

解题以前提议我们先看看promise的文书档案[https://segmentfault.com/a/1190000002452115]

打赏扶持笔者写出更加多好文章,感谢!

任选生龙活虎种支付办法

图片 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

就那样推算。

第风流倜傥题:promise应用的面试题

红灯三秒亮二遍,绿灯黄金时代秒亮叁遍,黄灯2秒亮一回;怎么着让八个灯依据这么些原理不断更动重复亮灯?(用Promse实现卡塔 尔(阿拉伯语:قطر‎四个亮灯函数已经存在:
function red(){
console.log('red');
}
function green(){
console.log('green');
}
function yellow(){
console.log('yellow');
}*

//已知函数
function red(){
    console.log('red');
}
function green(){
    console.log('green');
}
function yellow(){
    console.log('yellow');
}*
//亮灯一次 函数
var lightUp = function(timmer, cl){
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            cl();
            resolve();
        }, timmer);
    });
};

//promise 
var myPromise = new Promise(function(resolve, reject){resolve();});
var step = function(pro) {
    pro.then(function(){
        return lightUp(3000, red);
    }).then(function(){
        return lightUp(1000, green);
    }).then(function(){
        return lightUp(2000, yellow);
    }).then(function(){
        //递归
        step(pro);
    });
}

step(myPromise);

有关小编:Natumsol

图片 3

Alibaba 前端程序猿 个人主页 · 笔者的稿子 · 5 ·    

图片 4

二、标题考查的点

先评释:小编不是Wechat职员和工人,考察的点是本身想见的,大概不是,哈哈!

1.主意链式调用
2.类的应用和面向对象编制程序的思路
3.设计格局的运用
4.代码的解耦
5.起码知识标准化,也即 迪米特别准予则(Law of 德姆eter卡塔 尔(英语:State of Qatar)
6.代码的书写结会谈命名

第二题:

贯彻三个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
由此及彼。

//等待函数
function wait(second) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve('Wake up after '   second);
        }, second * 1000);
    });
}

//链式 promise
var  LazyMan = function(name) {
    var p = new Promise(function (resolve, reject) {
        resolve('Hi! This is '   name   '!');
    });

    return {
        sleep: function (second) {
            p = p.then(function (msg) {
                console.log(msg);
                return wait(second);
            });
            return this;
        },
        sleepFirst: function (second) {
            var op = p;
            p = wait(second).then(function (msg) {
                console.log(msg);
                return op;
            });
            return this;
        },
        eat: function (part) {
            var pn = new Promise(function (resolve) {
                resolve('Eat '   part   '~');
            });
            p = p.then(function (msg) {
                console.log(msg);
                return pn;
            });
            return this;
        },
        print: function () {
            return p.then(function (msg) {
                console.log(msg);
            });
        }
    };
}
exports.LazyMan = LazyMan;

核心有八种方案,感兴趣的能够品尝面向对象等任何方式来促成。

三、题目思路解析

1.看难题输出示例,能够规定这是拟人化的出口,约等于说:应该编写一个类来定义生龙活虎类人,叫做LazyMan。能够输著名字、吃饭、睡觉等表现。
2.从输出的句子能够看看,sleepFrist的事前级是参天的,其余行为的预先级意气风发致。
3.从多少个例证来看,都得先调用LazyMan来开端化一人,本事持续一连行为,所以LazyMan是三个接口。
4.句子是按调用方法的次第实行依次实行的,是多少个行列。

四、选取观察者情势实今世码

4.1 接纳模块格局来编排代码

JavaScript

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

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

4.2 声多美滋(Dumex卡塔 尔(英语:State of Qatar)个变量taskList,用来囤积供给队列音信

JavaScript

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

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

队列中,单个项的仓库储存设计为叁个json,存款和储蓄要求接触的音讯,以致艺术实行时索要的参数列表。比方LazyMan(‘汉克’),须要的积攒消息如下。

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(){ 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);

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()); } } })(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){ 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){ // 超多代码... // 揭穿接口 window.LazyMan = function(str){ 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

本文由pc28.am发布于前端技术,转载请注明出处:做完两道题,WechatLazyMan笔试题的通透到底解析和

上一篇:HTML也可以静态编译,损害了复用性 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • HTML也可以静态编译,损害了复用性
    HTML也可以静态编译,损害了复用性
    React.Component 损害了复用性? 2016/09/07 · 底蕴技能 ·binding.scala,data-binding,React,scala.js 本文笔者: 伯乐在线 -ThoughtWorks。未经笔者许可,防止转发! 接待插足
  • 品质的法门
    品质的法门
    9 种改革 AngularJS 品质的艺术 2017/07/20 · JavaScript· AngularJS 初藳出处: JustinSpencer   译文出处:oschina    AngularJS 是当下利用非常遍布的 web app应用框架,随
  • 高质量滚动,实例解析防抖动和节流阀
    高质量滚动,实例解析防抖动和节流阀
    实例解析防抖动和节流阀 2016/04/26 · JavaScript· DOM 本文由 伯乐在线 -涂鸦码龙翻译。未经许可,幸免转发! 立陶宛共和国(Republic of Lithuania卡塔尔语出处:
  • 安插最棒执行,营造打包优化_javascript技术_脚本
    安插最棒执行,营造打包优化_javascript技术_脚本
    Webpack 4 配置最佳实践 2018/06/22 · JavaScript· webpack 原文出处:Zindex    Webpack 4 发布已经有一段时间了。Webpack 的版本号已经来到了4.12.x。但因为 Webpack官方还
  • 前端安全
    前端安全
    Web 安全之 XSS 2018/05/25 · JavaScript· 1 评论 ·XSS 原文出处:今日头条技术博客    1.CSRF 2.XSS 基本概念 攻击原理 防御措施 什么是XSS 跨站脚本攻击(Cross Site