目录
经过长时间的进展,几乎没有写过什么博客,就这样迎来了 0.1.0 版本。
新增
- 友情链接
- 链接 hover 动画
- Changelog 页面,以后的所有的 Changelog 都在这个页面下展示
更新
- 更新主题(tranquilpeak)更新至
1.6.2 - 跟随潮流,使用《功夫熊猫3》海报背景
- 在列表页面,更新为全文显示,以前是只显示部分内容
修复
- disqus 无法通过 http 获取到对应的脚本,只能通过 https
遗留
- disqus 的 css 依旧受到上面问题的困扰
在 2016 年 1 月 12 日,Lo-Dash 迎来了半年来第一次大更新,也就是 4.0,这次更新了很多的内容,包括了不兼容更新,方法分离,函数重命名等等操作,下面我们来一一分析一下。
简单的翻译了一下官方的更新日志。
不再支持 Bower & Component,而是使用 npm,到发稿为止,已经无法在 bower 找到相关 Lo-Dash 的内容
移除了对 [IE6-8](https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support) 的支持
使用了 [es5-shim](https://github.com/es-shims/es5-shim) 或者 [es6-shim](https://github.com/es-shims/es6-shim)
移除了大部分的 thisArg 参数
1 | var objects = [{ 'a': 1 }, { 'a': 2 }]; |
node 中引用包的时候去除了类别的二级目录1 | // in 3.10.1 |
移除了 _.support
移除了 _.findWhere ,用 _.find 来替代(with iteratee shorthand)
移除了 _.where ,用 _.filter 来替代(with iteratee shorthand)
移除了 _.pluck ,用 _.map 来替代(with iteratee shorthand)
重命名 _.first 为 _.head
重命名 _.indexBy 为 _.keyBy
重命名 _.invoke 为 _.invokeMap
重命名 _.modArgs 为 _.overArgs
重命名 _.padLeft & _.padRight 为 _.padStart & _.padEnd
重命名 _.pairs 为 _.为Pairs
重命名 _.rest 为 _.tail
重命名 _.restParam 为 _.rest
重命名 _.sortByOrder 为 _.orderBy
重命名 _.trimLeft & _.trimRight 为 _.trimStart & _.trimEnd
重命名 _.trunc 为 _.truncate
也就是说从原来的方法中,将部分功能分离出来,成为一个新的方法。
分离出 _.indexOf & _.lastIndexOf 为 _.sortedIndexOf & _.sortedLastIndexOf
分离出 _.max & _.min 为 _.maxBy & _.minBy
分离出 _.omit & _.pick 为 _.omitBy & _.pickBy
分离出 _.sample 为 _.sampleSize
分离出 _.sortedIndex 为 _.sortedIndexBy
分离出 _.sortedLastIndex 为 _.sortedLastIndexBy
分离出 _.uniq 为 _.sortedUniq, _.sortedUniqBy, & _.uniqBy
将 _.sortByAll 融合到了 _.sortBy
改变这个类别 _.at 为 “Object”
改变这个类别 _.bindAll 为 “Utility”
在 master 分支下,将 ./lodash.js 移动到 ./dist/lodash.js
在 npm 分支下,将 ./index.js 移动到 ./lodash.js
将 _.clone & _.flatten 函数的参数中删除了 isDeep 参数
_.bindAll 将不再支持绑定所有的函数,当没有名字传入的时候
总之这次更新来的挺突然,感觉改动了好多东西,如果你的代码用了较多的话,暂时不建议去更新的。
更多内容呢详情请看官方 changelog
你有没有发现自己保存东西的时候、下载东西的时候弹出来的保存对话框没有以前的收藏(favorites)分类了。
这个时候,自己想点击一个下载或者文档都非常的麻烦。
一开始的时候,以为这只是个别的现象,就没有理会,随着时间的推移,才发现,这是一个普遍现象。开始寻找解决方案。
经过寻找,终于解决了这个问题:
解决方法如下:
Libary -> Perference 文件夹,找打 com.apple.finder.plist 文件,删除之Finder 或者 系统然后就可以惊奇的发现,这个问题已经修复了
我是一名大学牲,你别不相信,在来大学之前,我坚信自己是一个好学生,热爱学习,懂得学习。我之所以没有考到好的学校,不是因为自己能力不行,是因为自己不在意而已。
可事实证明是,虽然高考在某一些方面确实是会扼杀部分的才能,而更多的是能够区分不同的人。
当我作为一个一般的学生进入一般的大学的时候,真正的体会到了那种好大学和坏大学的区别。
好大学,都是一种朴素的情绪,任何事情都是踏踏实实的来做。
或许这篇文章是给我自己的,让自己时刻去警醒。
而在我们的大学,到处都充斥着一种浮躁的情绪。在计算机方面:
在我们社团中,虽然我很尊重我们的技术副站长,可是总是充斥着一种如果你不学会前端,后端,运维,装逼,瞎扯,看B站,几乎都不好意思出现在社团中。而且,不管你懂得深不深,只要你懂,你就可以在社团中瞎扯了。虽然我不反对对全栈技术的支持,但是我反对这种只为了广度,而没有深度的学习。今天看着他们搭建服务器,讲想看看mysql,明天看着他们写api,就想学学node,后天看着前端妹子漂亮,然后就去写HTML,可是最后呢?你知道了很多,但是如果给你一周的时间,你能完成什么东西呢?
是的,你必须要有坚实方向感,如果你是iOS工程师,先干好自己的事情,然后再去学习其他的。如果你是前端开发工程师,你要着眼于前端,而其他内容都是你所需要了解即可。不要因为这一刻我买了苹果手机,坚定了写iOS程序的愿望,然后看着舍友都会写前端,然后就果断跳去前端的阵营。
记住,学精不等于学会
但是,在我们社团中,还充斥这一种学会等于学精的感觉。我很讨厌。
或许这种体现,就是浅尝辄止,无法深入下去。对于我而言,我发现我很多东西都是接触过,但是没有深入研究过。而这种感觉总让我感觉不舒服,难受。我宁愿没有接触过那些东西。
或许这种情绪的来源在于大家对自己地位的在意。比如说,当我自己接触过之后,就可以和他们聊起来,当时自己接触的非常浅,每当有别人来尝试这个东西的时候,就会担心他学的比自己好,自己原本厉害的形象被损毁,然后不得不再去寻找其他的可以装逼的技术。从而在这里产生了一个恶性循环。让自己越来越深的陷入了这个循环中。无法自拔。
留给自己的话,认真,认真,认真对待每一件事情。
你会成功的!加油。
假设自己已经学通了,所有的部分,而且很深刻,还会担心别人超过自己么?自己之所以担心别人超过自己,都是因为对自己的不自信,相信自己,找到你和别人的不足,努力去奋斗。保持一种学习的心态,不要浅尝辄止。而且要学会和别人分享。自己总是觉得别人没有走自己的老路,觉得不舒服。可是,还没有想好如何安慰自己这个心态。。。
Babel相信很多新手没有听说过Babel和ES6,如果你是老手的话,那么请自动忽略~
ES6也就是ECMAScript 6,也就是最新的一代js规范,添加了很多语言的特性,包括模块管理,类,块级作用域等等内容。我最喜欢的就是箭头函数,优雅~
然而虽然ES6很棒,但是现在几乎没有浏览器或者Node(我记得5.0已经全部支持了es6,可是为啥我试着却不行。。。似乎要开启全部的harmony)能够完全支持es6的代码,那么问题来了,如果我想体验一下es6的代码,怎么办??
一个很简单的思路便是:
我写个程序,将es6代码转换成es5代码进行运行不就好了,很棒
而Babel就是干的这个事情。
对于Babel来说,现在有了两个版本,一个是5,一个是6,那么两者有什么区别呢?
5对新手更加友好,因为只需要安装一个babel就可以了,而6需要安装比较多的东西和插件才可以。
相比5来说,6将命令行工具和API分开来了,最直观的感觉就是,当你想在代码中运行es6代码的话,需要安装babel-core,而如果你想在终端编译es6或者是运行es6版本的REPL的话,需要安装babel-cli
也许有人问,原先的babel去哪了?是这样的,这个babel的package到了6版本之后虽然还是能安装,但是已经不具有任何的有效的代码了。取而代之的是一段提示文字,提示你需要安装babel-core或者babel-cli。所以你在babel6的情况下,完全不需要安装babel
6将babel插件化,当你第一次安装babel-core并且按照以前的方式来加载require
hook的话,你会发现代码无法运行:require('babel-core/register');就是因为babel6整体插件化了,如果你想使用es6语法,需要手动加载相关插件。
这里有一篇文章,建议看一下《TheSix Things You Need To Know About Babel 6》
建立空文件夹babel6作为本次的目录,并npm init
Babel61 | npm install babel-core --save |
如果觉得慢,可以使用淘宝镜像cnpm。
此时,基础的babel6就安装完成了,如果你想安装babel5,那么执行如下的代码
1 | npm install babel@5 --save |
即可使用babel5,那么在后文的中,统一使用babel6
安装好之后,问题来了,如何使用呢?
相信使用过coffee的人一定知道register,那么在babel中同样不例外,也可以使用同样的方法。
1 | require('babel-core/register'); |
大家可能以为这样我就可以在app.js中优雅的使用es6了,在babel5中确实是这样的,但是在babel6中,却不一样了。
如果你这样写完,并没有任何作用,因为你缺少一个插件。
如果想使用es6语法,必须安装一个插件
1 | npm install babel-preset-es2015 |
然后在文件夹下面创建一个叫.babelrc的文件,并写入如下代码:
1 | { |
下面你就可以很优雅的书写你的es6代码了。
ES6代码下面我们写一段优雅的代码
1 | let first = (size, ...args) => [...args].slice(0, size); |
直接运行,不说话~~~
什么是.babelrc文件呢?熟悉linux的同学一定知道,rc结尾的文件通常代表运行时自动加载的文件,配置等等的,类似bashrc,zshrc。同样babelrc在这里也是有同样的作用的,而且在babel6中,这个文件必不可少。
里面可以对babel命令进行配置,以后在使用babel的cli的时候,可以少写一些配置
还有一个env字段,可以对BABEL_ENV或者NODE_ENV指定的不同的环境变量,进行不同的编译操作
这个是babel6新加的,就是代表需要启动什么样的预设转码,在babel6中,预设了6种,分别是
es2015
stage-0
stage-1
stage-2
stage-3
react
至于如何安装,请查看balel官网
而且,对.babelrc的设置,你可以存放在package.json中的。如下:
1 | { |
require hook
的作用就是替换原先的require,以便在加载自动对代码进行编译,运行。
其实这个做的便是重写require.extensions中对应的扩展名的加载程序,并且默认会判断这个文件是否是node_modules中的模块,如果是的话,那么将不会进行转换。否则的话,会进行转换。
其实babel也可以当做全局变量来使用的
1 | npm install babel-cli -g |
安装上后,会安装如下四个程序到全局环境中:
babel
babel-node
babel-doctor
babel-external-helpers
这个就是编译js文件的全局变量,具体如何使用,大家请参照官网。使用方法和coffee,style,less了类似,就不多讲了
这里主要说一下这个东西,就是这个的作用就是提供一个node命令相同的REPL环境,不过这个环境会在执行之前讲代码进行编译。
坑1:上文讲到,babel6默认是无法编译es6文件的,需要你手动安装es2015的preset,同样,全局模式下,也需要这个preset。
那么问题来了,我们怎么安装这个preset呢?global?所以这是一个坑,我在babel的issue中找到这样的一条。作者给出这样的回答:我们处理preset和plugin是依据于输入的文件,而你直接运行CLI是没有输入文件的,也就无法定位preset和plugin的位置。言下之意就是不要全局安装,虽然我们给你了你全局安装的方式。然后作者关闭了issue,表示很无奈。。。。
解决方案1:经过寻找,找到一种解决方案,就是创建一个空项目,安装babel-preset-es2015,并写入对应的配置进入.babelrc,然后在这个目录下运行babel-node即可正常运行
不过这种方式太麻烦了,所以,如果大家想体验一下es6的REPL的话,建议安装babel5
1 | npm install babel@5 -g |
就是检查babel状况的,主要检查以下几个内容
是否发现了.babelrc配置文件
是否有重复的babel安装包,比如说安装了5和6
所有的babel安装包是否已经升级到了最新版
并且 npm >= 3.3.0
就是讲一些公共的帮助函数提取成一个文件,其实就做了这一个作用。。。
这是我的第一篇关于es6的教程,如果大家有什么不好的地方,请及时想我反馈
2015-11-15 添加了CLI
events module先说一下网上似乎很多人提供的使用例子来看,都是如下的
1 | var EventEmitter = require('events').EventEmitter; |
然而在源码当中有这样的一句话
1 | module.exports = EventEmitter; |
所以require('events').EventEmitter和require('events')是一样的。所以以后大家可以直接写
1 | var EventEmitter = require('events'); |
在源码中,构造函数极其的简单。
1 | function EventEmitter() { |
思路很简单,就是直接调用EventEmitter上的静态方法init进行构造。之后我们会介绍EventEmitter.init方法
挂在到EventEmitter上的静态属性和方法还是很多的,先说明一下静态属性:
defaultMaxListeners
usingDomains
顾名思义,默认的最大callback数量,就是如果当前对象没有指定_maxListeners,默认使用的就是这个值,默认是10
更多请看_maxListeners
待定
1 | EventEmitter.init = function() { |
先不管domain恨死干什么用的,总之init函数给this挂上了以下四个属性:
domain
获取emitter中指定类型的callback数量
这里有一个比较特殊的地方,就是他对对象是否含有listenerCount方法进行了判断
1 | EventEmitter.listenerCount = function(emitter, type) { |
listenerCount方法呢?这个属性是一个事件的缓存列表,他的key就是事件名称,value就是事件的回调函数,有如下几种取值:
Function
Array
当只有一个回调函数的时候,就直接存储为回调函数本身,否则包装成数组进行存储
顾名思义,就是事件的个数,这里有几个需要注意的就是,这个之有且仅在添加一个没有过的事件的时候才会加一,如果你给一个事件添加了多了callback的话,这个值并不会加一的。
这个就是可以表示一个event的最大callback的个数。如果小于等于这个个数,不会产生任何问题。但是如果大于这个限制,将会弹出警告,说可能会导致内存泄露。
我猜测可能是因为过多的callback会保存过多的context,从而导致内存泄露。
敬请更正
先从最常用的讲起,就是添加事件侦听喽
首先大家一定很熟悉on方法,大家一定想不到的是,竟然还有一个叫addListener方法。那么这两个方法有什么区别呢?
答案就是什么区别都木有~
而且在定义的时候,定义的是addListener而不是on,从源码中便可以看出来
1 | EventEmitter.prototype.addListener = function addListener(type, listener) { |
所以on更多的是一种简化,而正统的却是addListener,但是虽然这个正统,相信也没有几个人来使用吧,毕竟实在是太那啥了,是吧-_-||
好的下面言归正传,整个添加函数的流程可以看做是这样的(大家可以对照的源码看,我就不在这里把源码全部都粘贴过来了,并且我这里可能为了语句的通顺改变部分代码的执行顺序,大家请自行看出来。。。):
接受两个参数,分别是type表示事件,就是event,第二个是listener,侦听器,也就是callback
如果listener不是函数,很明显啊,抛出错误不解释
检测当前对象上是否存在_events属性,如果不存在创建之,并顺手初始化_eventsCount为0.
另events为this._events
如果events中没有type的listener,那么不解释,添加之~即events[type] = listener
如果events里面有的话,不解释,一个就数组包装一下,两个直接push
如果type类型的listener超过两个了,那么就检测一下有没有超过长度限制,具体的检测逻辑我就不在这里详细的说明了,总之就是给将检测结果挂到events[type]的warned属性上了。
如果有对应的newListener事件侦听的话,就直接用type和listener.listener?listener.listener:listener触发之
返回this
至此函数执行完毕
那么下一个就讲一下如果触发事件吧
newListener事件是在事件真正添加之前触发的很早以前我认为emit只能emit一个参数,到现在我猜明白,想几个就几个,没人限制你。
emit有一个很好玩的特性就是,如果你emit一个"error",如果没有事件侦听这个error的话,就会直接throw出一个error来,而其他的事件不会又这种效果,这就意味着我们最好要侦听error事件,万一出了一点错误,那将是崩溃的节奏啊~
检测type是否为"error"
如果是,并且没有监听到error,throw出pass进来的错误或者构建一个未捕捉的错误弹出。
如果没有对应的回调函数的话,返回false
获取构造函数并赋值给handler,这个值有可能是函数,或者是数组。
根据参数个数调用对应的函数,顺序依次运行handler
返回true
handler的执行在handler执行的时候,会先将当前队列复制一份,然后再进行执行。并且根据参数个数用call或者apply执行函数。放置在某一次执行期间突然掺入了其他的callback或者删除了callback,从而引发错误。
我原本以为会使用process.nextTick进行异步的执行,后来一想不对啊,肯定要按照添加的顺序进行执行,所以依次调用。
见
1 | // 没有参数的调用 |
源码对不同的情况进行了加速,因为人们大部分情况都是使用0参数或者1参数的,所以对这几种情况进行处理是非常高效的。
这个最简单了,就是用一个函数封装一下传入的callback,然后将这个函数,addListener进入到事件中。关于这个封装函数的写法,如下
1 | var fired = false; |
具体的就不多说了,总之就是执行后,先删除这个包装过的callback。
我的疑问:这里我有一点不太理解的地方就是为什么还需要
fired进行标记一下呢?
删除指定类型的指定callback的事件 很简单,分为一下几步
如果listener不是函数,抛出错误
如果events不存在或者对应的事件不存在,返回this
另list为events[type]
如果list就是那个callback或者list.listener是那个callback,删除
否则如果这是一个数组,那么找到对应的listener删除,否则返回this
如果上面有任意一个删除之后_eventsCount为0了,直接重新赋值this._events = {}(其实并不知道这个意义何在)
如果有任何一个删除,并且有事件侦听到了removeListener,触发之,传递type和listener
返回this
在事件删除之后才调用
removeListener事件
根据传递的参数来决定是删除全部的还是只删除指定事件的全部
确保存在this._events,否则返回this
如果没有侦听removeListener
如果没有传递type,重新赋值this._events和this._eventsCount
如果传递了type,删除type对应的事件,根据情况重新赋值~~~
如果侦听了removeListener,除了这个本身,依次调用removeAllLiseners()进行删除,最后删除removeListener这个事件
对于每一个callback,依次调用removeListener方法进行删除
返回this
获取指定类型的callback,否则为[]
获取指定类型的callback的数量
请大家自行搜索百度 Or Google
本文章内部的术语,我不进行大篇幅的解释,如果你不了解的话,请自行搜索,不要说自己懒~
如果本文章有问题的话,请及时进行评论,并和我联系
Google的官网通过我的观察,几乎已经全部使用了http2,你可以在开发者工具中的 Network 中查看 Protocol 使用的协议。
这里有一个问题,就是如果你的没有 Protocol ,这个怎么办?你可以在上面单击右键,就会弹出来有哪一些列可以让你选择,然后你选择 Protocol 即可。
对于Chrome浏览器,可以在地址栏上输入
1 | chrome://net-internals |
并在左上角的下拉菜单中寻找 HTTP/2 的字样,如果有的话,说明你的浏览器就支持http2,否则就话可能是另外一种情况
在Chrome地址栏中输入
1 | chrome://flags |
当前页面搜索 http2 ,找到相应的内容,并开启。然后重启浏览器尝试
如果还是前面两种都不可以的话,那么就请自行百度吧。
这个由于我没有firefox的浏览器,就留给读者自行百度了。
同样自行百度吧
浏览器都支持之后,那么就是开始准备我们的工作目录了。创建一个目录,我这里就叫做 try-http2。并安装http2包。
这里不再重复,请尝试百度,并将证书和密钥拷贝到目录下面
准备工作结束
使用http2服务创建服务器和使用https是基本一样的
1 | var http2 = require('http2'); |
此时在terminal中启动服务器即可
记住,这里一定要用sudo来启动,因为在Linux的系统中(Mac也是和Linux相同祖先),普通用户是无法监听到1024端口一下的端口,所以要用sudo来让程序监听443端口,因为https服务就是监听在443端口的
在浏览器中访问上面那个地址,然后在Network中查看Protocol是否为h2
看成功了,已经成功通过http2协议打开了这个网页。
你会发现在地址栏上https证书出现了错误,这是因为证书是你自己发布的,Chrome自然是不认识了
说到服务器推,大家一定第一个想到的是WebSocket,但是相比于WebSocket来说,服务器推的东西不是数据,而是网络请求。
其实他的正规说法是,服务器会推测你需要的东西,在解析HTML前将你需要的文件或者数据给你请求回来。这样,你请求了一次数据,返回了好几个资源
1 |
|
1 | var http2 = require('http2'); |
看成功执行了client.js中的代码。
下面我们来看看Network中的请求
你会发现虽然是请求了两次,但是client.js是服务器推送过来的请求,并不是浏览器去请求的。
虽然服务器推跟我们的心里落差较大,但是这并不影响这个技术的实施。
有了服务器推,可以很好的加快网站的加载速度,完全可以不需要等待整张页面加载完成之后再加载相关的数据。像一些script,CSS之类的可以在渲染页面之前就加载完成。
但是这个服务器推仍然无法替代WebSocket的地位,因为两个东西本质和目的都是不同的。而且服务器推相比来说,我们能控制的能力更少。
但是服务器推也有缺点,就是会无故增加浏览网页的流量,对于移动端来说,这将是致命的!
熟悉过Linux的同学一定知道,在Linux中,文件是区分大小写的。而对于相同祖先的Mac OS来说,应该也是如此。大家想当然的认为是这样的。
可是,事实却不是这样的。
在Mac OS中,默认是不区分大小写的。 这个大家可以进行如下的实验
1 | $ echo a > a |
大家可以看一下结果,是不是
1 | a |
这样的么?
说明Mac OS确实是不区分大小写的。
前面我说过了,默认是不区分,但是我们可以更改文件分区来区分大小写。
我是用的我的一个移动硬盘来看的分区,所以会在window的格式上有对勾,请不要在意😂
如图,默认是日志式,你可以选择区分大小写,日志式就可以了
一个弱弱的码农
杭州电子科技大学学生一枚