第一题:链式调用
题目: 实现一个如下的效果
People("神轻易").sayHello() // output: 大家好我是神轻易 People("神轻易").sayHello().movement("我要宣布个事").wait(3).movement("我是伞兵"); // output: // 大家好我是神轻易 // 我要宣布个事 // 休息3秒 // 我是伞兵 People("神轻易").sayHello().movement("我要宣布个事").wait(3).waitFirst(1).movement("我是伞兵"); // output: // 休息1秒 // 大家好我是神轻易 // 我要宣布个事 // 休息3秒 // 我是伞兵
这题的考察重点在于js的事件循环、构造函数、原型链。
难点:
waitFirst()要实现后调用先执行,剩余函数按顺序执行,支持延时调用
思路:
要实现一个链式调用,有两种方法,构造函数或者Class,原理都一样,因为Class也可以看作是构造函数的语法糖。
说一下要点:
- 建立一个事件队列
- 每个方法都可以往事件队列推入一个事件,每个方法最终返回指向Function/Class本身,即
this - waitFirst将插入队列头部
- 顺序执行事件队列
可以看到,执行将放到最后进行。
解题代码:
构造函数:
function People(name) {
this.tasks = []
this.name = name
setTimeout(()=>{
this.then()
})
}
People.prototype.sayHello=function(){
this.tasks.push(()=>{
console.log(`大家好,我是${this.name}`)
this.then()
})
return this
}
People.prototype.wait=function(time){
this.tasks.push(()=>{
console.log(`休息${time}秒`)
setTimeout(()=>{
this.then()
},time*1000)
})
return this
}
People.prototype.waitFirst=function(time){
this.tasks.unshift(()=>{
console.log(`休息${time}秒`)
setTimeout(()=>{
this.then()
},time*1000)
})
return this
}
People.prototype.movement=function(event){
this.tasks.push(()=>{
console.log(event)
this.then()
})
return this
}
People.prototype.then=function(){
const task = this.tasks.shift()
task && task()
return this
}
new People("神轻易").sayHello().movement("我要宣布个事").wait(3).waitFirst(1).movement("我是伞兵");
Class:
class People {
constructor(name){
this.tasks = []
this.name = name
setTimeout(()=>{
this.then()
})
}
sayHello(){
this.tasks.push(()=>{
console.log(`大家好,我是${this.name}`)
this.then()
})
return this
}
wait(time){
this.tasks.push(()=>{
console.log(`休息${time*1000}秒`)
setTimeout(()=>{
this.then()
},time*1000)
})
return this
}
waitFirst(time){
this.tasks.unshift(()=>{
console.log(`休息${time*1000}秒`)
setTimeout(()=>{
this.then()
},time*1000)
})
return this
}
movement(event){
this.tasks.push(()=>{
console.log(event)
this.then()
})
return this
}
then(){
const task = this.tasks.shift()
task && task()
return this
}
}
new People("神轻易").sayHello().movement("我要宣布个事").wait(3).waitFirst(1).movement("我是伞兵");
分析:
为了分析得更细致,我改写一下,让大家看得更明白,实际上这段代码
new People("神轻易").sayHello().movement("我要宣布个事").wait(3).waitFirst(1).movement("我是伞兵");
等同于:
new People("神轻易");
People.sayHello();
People.movement("我要宣布个事");
People.wait(3);
People.waitFirst(1);
People.movement("我是伞兵");
在初始化该构造函数的时候,我们在这个函数上下文中依次添加了tasks数组,then方法,以及执行一个setTimeout()函数即:
constructor(name){
this.tasks = []
this.name = name
setTimeout(()=>{
this.then()
})
}
我们知道,在js的事件循环中,有执行栈,同步任务会优先顺序执行,异步任务会被推入事件队列,分为微任务宏任务,待同步任务执行完成之后依次取出执行。所以在constructor中只有初始化tasks数组,以及name属性定义,setTimeout函数作为异步宏任务被挂起。
全部用同步方法表达,在这段构造函数内部,这句链式调用将是这样执行的:
// new People("神轻易").sayHello().movement("我要宣布个事").wait(3).waitFirst(1).movement("我是伞兵");
// 即:
this.tasks = []
this.name = '神轻易'
// 此时People:{name:'神轻易',tasks:[],then:...},setTimeout函数是宏任务,被挂起并继续执行后面的函数,即People.sayHello()
this.tasks.push(()=>{
console.log(`大家好,我是${this.name}`)
this.then()
})
// 此时People:{
// name:'神轻易',
// tasks:[()=>{
// console.log(`大家好,我是${this.name}`)
// this.then()
// },],
// then:...
// }
// 随后执行People.movement('我要宣布个事')
this.tasks.push(()=>{
console.log(`大家好,我是${this.name}`)
this.then()
})
//...将所有事件依次在队尾插入tasks中,注意waitFirst是插入队头
// 最后执行那个被挂起的宏任务setTimeout,而此时我们的tasks队列已经按照正确的顺序组合好了,只需要等待事件依次执行即可
第二题:股票问题
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/be… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
具体啥题忘了,反正原题是这个,一开始看错题了以为只能一次交易,后来面试官提醒我才反应过来原来是可以多次交易的但时间过了,就说了一下解题思路。
这个应该比较简单,直接贴代码吧,不限交易次数的话,今天比昨天价高就是利润。
function maxProfit(prices) {
let profit = 0;
for (let i = 1; i < prices.length; i++) {
if (prices[i] - prices[i - 1] > 0) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
下期预告:UC笔试题