“最难不过坚持”
本人承接扒站仿站,php网站维护,病毒查杀,网站编辑,网站改版,html制作
有需要网站维护,改版,病毒查杀,网站编辑,网站备案,html制作等相关的工作可以联系我。
本人有多年相关工作经验,也可提供免费咨询,交个朋友。
有需要探讨问题的朋友,也可以加我微信,共同探讨!
微信:15011482830 QQ:408917339
- https://jueru.net/
-
- :weixiao:
-
- :shuijiao: :weiqu: :zhenbang: :leng:
-
- :yiwen: :yiwen: :yiwen: :yiwen:
-
- 这个业务逻辑多少都有点奇怪了,阅读浏览次数增值在新闻详情页的控制器方法里setInc,这怎么还写进模型事件里了。如果非要用onAfterRead也可以,把新闻文章的内容单独分出来一个news_content表,然后把它和news做关联,然后给news_content表的onAfterRead事件做增值处理,这样点进新闻页内查询到文章内容时才会触发它。
-
春节过后,感觉过年吃的油腻的食品转化的脂肪都长到 脑子去了。 根本转不动啊
上班第一天 实在是写不动代码了, 顺手打开多天为看的 收件箱,查看查看邮件,看看春节期间 风云变幻的前端圈又有哪些大事发生。(在这里先为 GitLab 的那位运维同学 默哀一分钟)
在 sg 的邮件中 看到了一道有意思的题目。
原生JS 实现一个 lazyMan 效果
what ? lazyman 是什么鬼,顺其自然的百度了一下
-------------------------------------------------------------假装有分割线------------------------------------------------------------------
把题目转换成 代码就是如下的 一个意思。
题目:
-------------------------------------------------------------假装有分割线------------------------------------------------------------------
答案:
-------------------------------------------------------------假装有分割线------------------------------------------------------------------
思考: 这个题目主要考察哪些内容呢?(我们一步步往下看)
1、首先,看到这个 链式操作 我们能想到的就是 我们原来在使用 JQ 的时候 经常会去 操作DOM 的时候会用到的 $.addClass('xxx').removeClass('xxx') 这样的操作对吧
那么我们仔细思考一下,为什么 这种写法 是能够执行,且不会报错呢?
因为 $.addClass('xxx') 这是一个已经执行过的方法了,就是相当于 上面这种链式写法是 在一个方法后面又去 执行一个方法, 如果原生直接这么去写,肯定是会报错
说 前面这个方法 不包含后面的这个方法。(报这个错误是正常的,为什么呢? 因为本身确实没有啊,因为 func 其本身就是一个 obj,但是这个 obj 中不包含第二个方法)
-------------------------------------------------------------假装有分割线------------------------------------------------------------------
2、那我们首先想到的就是 构造函数, 然后 给这个构造函数的 原型上去添加链式操作需要的方法。
好,那我们先码上 初级 的代码。
// 构造函数 function _lazyMan(name) { console.log(name); }
然后我们简单的封装一下
// 构造函数 function _lazyMan(name) { console.log(name); } /* 封装 */ function lazyMan(name) { return new _lazyMan(name); } lazyMan('zz'); // zz
3、我们再给我们的构造函数的原型 添加方法
// 构造函数原型上的 sleep fn _lazyMan.prototype.sleep = function() { console.log('i am sleepping'); } // 构造函数原型上的 eat fn _lazyMan.prototype.eat = function() { console.log('i am eatting'); }
然后实例化 构造函数,并给其赋值,看结果
lazyMan('zz').eat() // zz // i am eatting
lazyMan('zz').eat().sleep() // zz // i am eatting // error 报错
思考: 为什么会报错么?
上文已给解答。
4、我们需要如何去操作才能完成我们 真正想要的东西呢?
我们 是不是需要一个 数组 来存储我们的 事件,然后 有一个 next 的 方法 专门去 执行我们数组中的方法呢?
按照这个思路,我们来尝试着 组织 下我们的代码。
// 构造函数 function _lazyMan(name) { this.tasks = []; var that = this; var fn = (function(n) { var name = n; return function() { console.log(name); that.next(); } })(name) this.tasks.push(fn); setTimeout(function() { that.next(); },0) } // 事件调度函数 _lazyMan.prototype.next = function() { var fn = this.tasks.shift(); fn && fn(); } // 构造函数原型上的 sleep fn _lazyMan.prototype.sleep = function() { var that = this; var fn = (function() { return function() { console.log('i am sleepping'); that.next(); } })() this.tasks.push(fn); return this; // 实现链式调用 } // 构造函数原型上的 eat fn _lazyMan.prototype.eat = function() { var that = this; var fn = (function() { return function() { console.log('i am eatting'); that.next(); } })() this.tasks.push(fn); return this; // 实现链式调用 }
其实上面的 代码还可以更加简化一些。
但是在 实际的应用中肯定包含了更多的 变量需要去利用 闭包 去保存、 但是 ES6 的出现 会让代码 一如既往的简洁。
lazyMan('zz').eat().sleep().eat(); lazyMan('zz').sleep().eat();
通过上面的代码,我们发现,我们把 我们链式操作的方法在 构造函数实例化的 时候, 均存入到了 我们定义的 tasks 数组中去了。
在 链式操作调用方法的时候,先去 执行 原型链上的 链式上的 第一个方法,然后再去 执行 next 方法, 去执行 存放在数组中的下一个方法。
继而,我们得到了我们想要的 链式操作 以及 很 明确的 流程控制。
可能有同学会问 流程控制 体现在 哪里。
回过头来,我们再 仔细的看下题目。
为什么会去 执行 两遍这个程序,因为就是为了体现 程序执行过程是 有序的,而不是随便任意执行。 (完)