前端网老姚浅谈:怎么学JavaScript?

  鉴于时不时,有同学私信问我(老姚,下同)怎么学前端的问题。这里统一回复一下,如下次再遇到问我此问题同学,就直接把本文链接地址发给你了。

  首先说句题外话。关于有人管我叫大神的事情。个人感觉这跟你买东西时,人家管你叫帅哥一样,你答应与否都无妨。

  正题开始,“前端怎么学”应该因人而异,别人的方法未必适合自己。就说说我的学习方法吧:我把大部分时间放在学习js上了。因为这个js的学习曲线,先平后陡。项目实践和练习啥的,我不说了,主要说下工作之外的时间利用问题。我是怎么学的呢,看书,分析源码。个人这几天统计了一下,前端书籍目前看了50多本吧,大部分都是js的。市面上的书基本,差不多都看过。

第一个问题是,看书有啥好处?

  好处应该是不言而明的,书看多了,基础会逐渐夯实起来。看多了,自己的判断力,自然就上来了。看别人的文章,就能很快判断出,对方每块儿讲得对不对,哪块儿又是自己不清楚的,模棱两可的。当然也为看源码,分析源码提供了基础。

  10本书读2遍的好处,应该大于一本书读20遍。10本书的交集,那就是基础知识的核心,而并集那就是所有的知识。好书当然要多读,反复读。但是只读一本是不行的。因为每本书的侧重点都不一样。从不同的侧面,去理解一个知识点,是很有意义的。

  所以特别佩服印度人,他跟你讲英文,你一个词语没听懂,他会蹦出n个同一意思的单词,你听懂一个,就ok了。看书也是这样的,某一块讲得不透彻,不用担心,其他书籍可以帮助你来了解。

第二个问题是,书籍推荐。

  个人觉得不错的,没事可以翻翻的。书籍如下:

   >《javascript面向对象编程指南》,风格轻松易懂,比较适合初学者,原型那块儿讲得透彻,12种继承方式呢。

   >《js权威指南》、《js高级程序设计》,这两本书经典是经典,但是太厚,适合把其中任意一章都当成一本书来读。洋洋洒洒,很难一口气看完。比较适合当做参考书。

   >《你不知道的javascript》狙击js核心细节,闭包、原型、this讲得都还清楚。目前《中册》也出了,还在看。

   >《js设计模式与开发实践》js设计模式也是要学的,此书把js的设计模式讲得非常清晰,一点不晦涩,看起来没多少难度。

   >《正则指引》,分析源码时,如果正则表达式不懂,没法进行下去的。此书相对来说讲得比较清晰。

   >《基于MVC的JavaScript Web富应用开发》,看完后,基本能写出自己的mvc框架了。是本好书。

   >《javascript函数式编程》,js是一门函数式语言,此书是函数式编程一个入门,函数是一等公民那是非常重要的。

   >《js忍者秘籍》,jq作者写的,没有传说中的那么难读,话说就算你看完并理解所有知识点,也不会达到世界高手级别的。因为你还没有做到随心所欲。

   >《javascript框架设计》,如果初看此书,会觉得此书有罗列代码之嫌。在我看来,此书讲究的是框架的全局观。以上书籍是我认为是成就高手之路上必须看的,也需要反复看。

   css相关的书籍,说实话我看得比较少,总共有六七本吧。有两本必须推荐一下:

   >《css权威指南》,css基础知识点那是讲得非常清楚的。什么层叠优先级、line-height啥的。不是随便一本书都敢叫“权威指南”的。

   >《css揭秘》,此书我也是不断的看,此书才不屑于全面讲css3各属性呢。css规范文档能讲的,它只会讲你最不在意的。此书解决的47问题,解决思路和解决方案同等重要,很有启发性。以上各书你都可以不买,至少买本此书吧。

第三个问题,怎么看。

  想必很多同学,都想看书,但是很难看下去。文字部分相对来说还能看看,一遇到代码,头皮就发麻了。此问题一开始时我也遇到的。

  说一个学习理论。比如说学英语,有个开水理论。词汇量必须达到6000才行,如果没达到,英文水平不会上去的,这跟烧开水一样,没事烧烧,放着凉凉,从来没烧到100度,那么此水是永远不能喝的。一旦煮沸过,就可以随时喝了。

  20本书你看不下去,说明什么呢?任何一本书,你都没看完过。熟悉的,永远只是前三章。别笑,我原先也是这样的。

  那么现在的问题是,怎么把一本书看完呢?很简单,敲。《基于MVC的JavaScript Web富应用开发》这本书我看时,就是这样,终于有一天,我下定决心要把此书从头到尾敲一遍。文字加代码都敲,然后就一章一章得看完了。代码敲一遍后,你会发现,没之前看起来的那么难。

  如果你属于一看书就犯困那种同学。强烈建议你把《javascript面向对象编程指南》此书从头到尾敲一遍。坚持看完一本书后,信心就上来了。先保证看完一本再说,看完3本后,基本应该能做到几天就能看一本了。万事开头难,加油吧。

第四个问题,看书的层次问题。

  书看完后,要自己总结,要与其他书籍对比看。有同学同时对比着看《权威指南》和《高设》来的。随便拿出个知识点,你都能闭着眼睛说得头头是道,说明水平够了。

  下一块就是源码的学习了。看框架源码之前,想说一件事情:dom的api不懂,没问题,你可以百度。

  但是正则一定要先研究研究,不然大多数人去尝试分析源码时,遇到的挫折都在于此。

怎么去阅读源码呢?敲,照着敲。

  有哪些代码值得去敲呢?优秀框架或者库的源码都值得你去敲。但是拿jq来敲,来入门,那不行的。原因:太他么长了。八九千行呢!!

  个人觉得underscore.js库是不错的第一个选择。原因都是工具方法,敲完以后自己的水平应该略有小成吧。其实有一些api的实现,你要把它当成getElementById一样,深深的印在脑海里。比如extend方法,必须张口就来。敲完underscore库后,可以考虑去看看《javascript函数式编程》这本书了。

  jq的源码不好敲。那么zepto的源码比较少1800多行,敲一天应该敲完了。敲几遍后,把所有不懂的地方,都百度清楚,然后就可以写自己的类jq的库了。然后就可以作为一项技能写进自己的简历里。比如“创建过自己的jquery库”。当然敲的过程,还能帮助自己对jq的api认识。

  然后是backbone.js,因为此框架是以类jq和underscore为基础的mvc框架。代码也没多少行。敲吧。spine.js与backbone类似。可以在敲其之前,先看看那本《基于MVC的JavaScript Web富应用开发》。希望你的简历可以添加这么一笔,“创建过自己的mvc框架”。

  其他的,我也敲过一些。包括jq.validate.js,包括一些插件。如果你愿意的话,bootstrap你可以去敲敲啊。源码挺多的,可以按插件逐个来敲。分析明白了,轮播、分页、下拉框等等的插件那还不是分分钟随手就写一个了。最起码看看人家api接口是怎么设计的也是极好的。话说个人在阅读其css代码中,也学到了不少东西。说到插件,有两个必须提提,一个是表格插件,一个是树。都敲完,简历里可以这么写上,“创建过自己的UI框架”。

  当然了,你也可以敲你喜欢的框架代码,重要的是明白其实现原理,最好理解其为啥那么设计,如果对设计模式比较熟悉的话,会经常发现原来是这么回事。

  照着敲只是分析源码的入门,用途也是为了学习,最后能用在自己的项目中,那是才是正道。就算没啥用,也是打发时间的好方式,比看电视剧强多了。我闲着无聊时,就背着敲underscore源码。最后说句,如果你简历上能如期写上那几句话后,必须是大神。加油吧。

后记

  写本文的最初目的,正如文章开头说的那样,方便自己回复大家的提问。本站的任何一篇分享学习经验的文章,基本都会引起共鸣,这确实是一个值得讨论的话题。这里再说说几个事情。

  >有人问我前端工作经验事情。

  没几年。三年多。

  >初学者或新手(beginner)怎么办?

  看书和分析源码是重要的提高方式,但不适合新手。新手需要的是能快速的入门和入行,能快速的上手工作。一种快捷的学习方式就是看视频。正如有的同学说得那样,知道有哪些东西,怎么用就可以了。

  看视频是有好处的,首先它是一种被动学习方式。我最开始的入门也是看视频来的,只需要看就行了。一遍没懂,再放一遍,我基本上是1.5倍数去看的。

  而读书是一种主动方式,需要自己一页一页翻。需要自己主动的去理解。而很多东西,也许只是视频老师一句话,就能突出的重点,需要我们自己去解读。还有另一件事情是,比如发现自己某个知识点不太清楚,可以单独去百度。比如this,文章很多的。这种学习方式也是快速掌握知识点的好办法。

  书籍需要技术评审,那么看文章一定要看看评论。不过视频就不好说了,视频一般都不会讲得太深入,偶尔也有讲错的。当年我也曾被一些视频误导过,建议找不错的视频看看。各大网站培训机构的免费视频挺多的。

  >看书和分析源码的时机。

  但已经工作一年半载时,正是提高的好时候,此时可以去看书了。全面系统的梳理知识点,扫清自己的盲区。如果只是靠项目经验是不够的,通过项目来学习,那肯定是必须的,工作本身就是一个学习的过程。

  但是工作三年不看书的话,学又能学到多少呢?更何况每个项目都很类似,一直处在舒适区,那真就是5年经验重复第一年的了。所以我不认同这句话:面试时强调自己的学习能力是工作能力不强的表现。3年经验的水平,完全有可能超过5年的。

  >没有时间去学习?

  如果你还没毕业,就已经天天在本站混了,其实你领先了一大步。都是混过大学的,天天充斥着lol和电视剧的陪伴,我只想说进入社会是要还的。最可怕的是什么呢?该还、还不还(这几个字别念错了)。时间是有的,就看你愿意付出不。下班后学习,周末学习,节假日别人玩的时候,在家敲代码,这样才能领先别人。

  >兴趣问题?

  兴趣和擅长是一个良性迭代循环。你擅长某件事情,就会越喜欢它,越喜欢,就越愿意花时间,进而越擅长。此道理都懂,只是缺乏一个trigger。

  如果你喜欢玩游戏的话,其实你可能非常适合做前端。玩游戏就是一个反馈机制,前端工作的反馈,相对其他工作来说也是非常及时的。代码一改,网页一刷,就看到效果了。擅长、优越感、成就感通常都是连在一起的。每看完一本书,我都觉得很有成就感。每敲完一个库,也有成就感。

  以上纯属一家之言,每个人的学习习惯、方式、态度都不一样。先端正态度、找到自己的学习方法,进而养成坚持下去的习惯。最后说一句,你我共勉:只要你走在正确的道路上,不管、走得多慢,都是前进!

  本文完。

技术人员的发展之路

译注:本文作者酷壳/陈皓

  2012年的时候写过一篇叫《程序算法与人生选择》的文章,我用算法来类比如何做选择,说白了就是怎么去计算,但是并没有讲程序员可以发展的方向有哪些。 所以,就算是有这些所谓的方法论,我们可能对自己的发展还是会很纠结和无所事从,尤其是人到了30岁,这种彷徨和迷惑越来越重。虽然我之前也写过一篇《编程年龄和编程技能》的文章,但是还是有很多做技术的人对于自己能否在年纪大时还能去做技术感到没有信心。我猜测,这其中,最大的问题的是,目前从事技术工作的种种负面的经历(比如经常性的加班,被当成棋子或劳动力等等),让人完全看不到希望和前途,尤其是随着年纪越来越大,对未来的越来越没有信心。
  同时,也是因为在GIAC的大会被问到,程序员老了怎么办?而在年底这段时间,也和几个朋友在交流中不断地重复谈到个人发展的这个话题。我的人生过半,活到“不惑”的年纪,自然经常性的对什么事都会回头看看总结归纳,所以,在交谈过程中和交谈过后,自己也有一些思考想记录下来。因为我本人也是在这条路上的人,所以,谈不上给他人指导,我同样也是在瞎乱折腾同样每天在思考自己要去哪儿的“一尘世间迷途老生”。况且,我的经历和眼界非常有限,因此,下面的这些关于个人发展的文字和思考必然是受我的眼界和经历所局限的。也欢迎大家补充和指正。
  这些东西不一定对,也不一定就是全部,期许可以让你在年底的时候有所思考,在明年的时候有所计划。

一个重要阶段和标志

  在讲个人发展之前,我需要先说一下人生中的一个非常重要的阶段——20到30岁!
  这个阶段的首要任务,就是提升自己学习能力和解决难题的能力。这是一个非常非常关键的时间段!这个时间段几乎决定着你的未来。
  30岁以前,这个时间段,应该是人学习和积累的时间段,这个时间段,就是努力学习的时间段。这个时间段,你一定要把时间花在解决问题的技能上。就是说,你一定要练就成的技能是——你能解决大多数人不能解决的问题。使蛮力埋头加班苦干,当一个搬砖老黄牛的是肯定没有前途的。如果你不幸呆在了一个搬砖的地方,天天被业务压得喘不过气来,我建议你宁可让你的项目延期被老板骂,也要把时间挤出来努力学习基础知识,多掌握一些技术(很多技术在思路上是相通的),然后才能有机会改变自己目前的状况。因为,比起你的个人未来,项目延期被老板骂、绩效不好拿不到奖金,都不是什么事儿。
  总结一下,你在30岁前,工作5-7年,你需要拥有:

  ♥ 高效的学习能力。这意味着——基础知识扎实、触类旁通、读英文文档不费劲、有寻找前沿知识的能力、能够看到问题和技术的本质、善于思辩、能独立思考。
  ♥ 解决问题的能力。这意味着——你要高效的学习能力、见过很多的场景、犯过或是处理很多错误、能够防火而不是救火。

  如果你拥有这两个能力的现象是—— 在团队或身边的人群中的显现出Leadership。
  Leadership并不是当领导和经理,而是一种特征,这种特征有如下两个简单的表象:

  ♥ 帮人解问题。团队或身边中大多数人都在问:“这问题怎么办?”,而总是你能站出来告诉大家这事该怎么办?
  ♥ 被人所依赖。团队或身边中大多数人在做比较关键的决定时,都会来找你咨询你的意见和想法。

  一但你在在30岁之间出现了Leadership这样的特征,那么,你会进入一个正循环的阶段:

  ♥ 因为你学习能力强,所以,你会有更多的机会解决难题。
  ♥ 你有更多的机会解决难题,你就会学更多的东西,于是你就会更强。
  ♥ 上面这个循环,只要循环上几年,就会让你人生的各种可能性大大的增加。

  【 注意 】
  ♥ 要达到这样的特质,需要找到自己的长处、以及适合自己的环境。就像鱼的特长是呆在水里,让鱼儿去追求陆上动物的刺激生活并不靠谱。
  ♥ 一般说来,有这样的潜质的人,在学校中就应该要出现。如果你在大学中还没有出现这样的潜质,那么,你在工作当中要加倍努力了(注:所谓的加倍努力,不是让你使蛮力加班,而是让你多学习成长,使蛮力拼命是弥补不了能力、思维、眼界上的缺陷的)。
  ♥ Leadership也有范围的,比如,身边的朋友,工作中的团队/部分,圈内,整个行业。Leadership的范围越大,你的个人发展的选择性就越高。反之则越小。
  ♥ 如果已到了30岁左右,还是没有出现这样的特征。那么,可能未来你也很难有这样的Leadership了。而你的个人发展的可能性可能也就不多了(sigh…)

  读到这里,我必需要说一下,如果你已开始显现出你的Leadership,那么你才谈得上个人发展,这篇文章后续的内容也可能才会对你有意义。

个人发展的三个方向

  以我个人短浅的经历和视野,目前只看到的人的发展有如下三个大方向(他们之间可能会有重叠):

  1)在职场中打拼
  2)去经历有意义有价值的事
  3)追求一种自由的生活

  这三个方向,我个人或多或少都体验过,我也见过身边的很多人走这三个方向走的比较成功。也许还有别的方向,没办法,现在,我的视野就这么大,所以,我在这里,我主要就是谈谈这三个方向。Again,人有资格去走这三个方向的前提是——已有了上面我说的Leadership那种特质!

一、在职场中发展

  在职场中发展应该是绝大多数人的选择。通过加入公司来达到人生的发展。

  我们经常可以看到很多所谓的“职业规划”,但是大多数职业规划只不过人力资源搞出来的东西,和实际其实是有很大出入的。我的人生经历中,有18年左右是在公司中度过的,在过银行,小公司,大公司,民营公司,外国公司,传统IT公司,互联网公司,不同的公司完全有不同的玩法和文化,我的经历还算丰富,但也不算特别成功,这里只分享一些我在职场中的心得(不一定对,仅供参考)。

  1、去顶尖公司

  去顶尖公司的一个目的就是让你的Leadership的范围的可能性扩大。
  因为公司和公司的差距也不小,所以,就算你在低端公司里是骨干份子,但在高端公司里可能只是一个普通员工(就像中国足球队的主力到了英超可能都无法入选)。所以,在职场中,如果你要让你的个人价值最大化的话,你一定要去顶尖的公司。因为顶尖公司里有非常不错的工作方法和场景,这并不是能看书或是交流得来的,这是必需要去亲身体验的。所以说,在顶尖公司掌握的技能,开阔的眼界,通常来说都会比低端公司的要多得多。
  另外,每个公司的工作级别都是有相互对标的,比如:阿里的P几对应于百度的T几。国内的一线公司职位还相当,但是如果和国外一线公司的比,那就有差距了,而且差距还很大。比如,Google或Facebook的某个高级工程师,可能就对应于阿里的P8/P9甚至更高。
  是的,对于职场来说,如果你在顶尖公司是骨干,那么,你去低端公司,则有很大机会会成为他们高管和核心。就好像你在Facebook里干三五年成为他们的技术骨干,那么你到BAT去成成为高管概率是非常大的。反过来,如果你毕业主去了BAT成为了一个螺丝钉,在天天加班中度过你的青春,你干个十年能成为BAT的高管的概率可能会非常的低。

  2、去真正的创业公司

  去顶尖公司和去创业公司在某些时候并不冲突。不过,这里我想讲的是,一个技术能力强的人在大公司可能会被埋没掉。因为大公司业务成功后,

  ♥ 成功的公司在招聘各种高级技术人才都不会成为问题,于是少你一个不少,多你一个不多。
  ♥ 成功的公司其整个技术体系已经完成,Legacy的问题也比较多,所以,可以供你发挥的余地不大。
  ♥ 成功的公司更多的可能会想要稳定的系统,稳定必然会产生保守,而保守则产生不思进取。

  所以,对于中高级人才来说,在大公司里的能产生的个人价值,可能远远不如那些求贤若渴、没有包袱、可以尽情施展、相对更为灵活和自由的创业型公司。
  不过,去创业公司需要小心仔细的挑选和评估,创业公司的不确定因素很多,也和创始人的因素太大了,所以,你需要小心了解创始人和他们的业务情况,想法和理念差不多才能更好的共事。
  好多创业公司其实并不是真正的创业公司,他们创业有很大的侥幸和驱利心理,要小心甄别。因为那不是真正的创业公司。

  3、职业生涯的发展阶段

  首先,有一个不争事实——整个社会是会把最重要的工作交给30岁左右的这群人的。也就是说,30岁左右这群人是这个社会的做事的中坚力量。
  所以,这是一个机遇!如果你有了Leadership,你就一定能在这个时间段内赶得上这个机遇——公司和领导对你寄于信任和厚望,并把重要的团队和工作交给你。
  于是,你的30岁到40岁就成了一个职业生涯的发展期,也就是你的事业上升期。如果你到40岁都没有赶上,那么你的职业生涯也就这样了,老有所成的人是少数。
  在你事业的上升期,你需要更多的软技能,比如:

  ♥ 带领产品和业务的发展的能力
  ♥ 推行自己喜欢的文化的能力
  ♥ 项目管理的能力——在任务重、时间紧中求全
  ♥ 沟通和说服别人的能力
  ♥ 解决冲突的能力
  ♥ 管理和发展团队的能力
  ♥ 解决突发事件的应急能力
  ♥ …… ……

  另外,你还要明白在职场里的几个冷酷的事实:

  ♥ 你开始要关心并处理复杂的人事。尤其在大公司,大量的人都是屁股决定脑袋,利益关系复杂,目标不一致,每个人心里都有不一样的想法。这个时候再也不是 talk is cheap, show me the code!而是,code is cheap,talk is the matter。你需要花大量的时间去思考和观察形形色色的人。需要耗费大量的精力在不同的人之间周旋,而不是花时间去创造些什么有价值的东西。
  ♥ 你要开始学会使用各种政治手段。办公室政治不可避免,越大的公司越重,自从你开始成为一线的leader的那一天起,你就开始成为“里外不是人”的角色,需要在下属和领导,员工和公司之间周旋。随而你的级别越来越高,你需要使用更多的政治手段,你会学会审时度世的站队,学会迎合员工和领导,学会用官员的语言说话,学会此一时彼一时,学会妥协和交换,学会忍气吞声,学会在在适当的时机表现自己,学会波澜不惊,学会把自己隐藏起来,甚至你还会迷失自我,开始学会一些厚黑学,比如不得不在适当的时机在背后捅人刀子……你可能会成为一个你自己都讨厌的人。

  听上去真的好无聊,所以,你现在也明白为什么高层们都看上去很忙很累,而且抽不出时间来关心细节问题,因为,他们更多的是要协调整个组织和系统来运转,甚至还要四处周旋,各种博弈,没办法,这是职场的必需的东西!听起来是不是感觉人类很愚蠢?这真是没办法的事。如果你不想或是也没有能力玩这些东西,那么你需要去那些可以让技术人员安安心心做技术的公司。这类的公司,我见过Microsoft、Google、Amazon或是一些创业公司里都有。国内的大公司中也有让技术人员成长的职业成长线,但老实说,表面上看似是一个让人专心做技术的升职成长线,但其实还是管理岗位。
  所以,技术人员在职场中的归宿有两条路 —— 到真正的技术公司成为一个专心做技术的人,或是在成为一个职业的经理人。

一个重要阶段和标志

  先说三个故事,

  ♥ 第一个,是在阿里的时候,有一天在内网里看到一个贴子,一个做产品的女孩说自己准备离职要去法国学烘培厨艺,引得大家热评。
  ♥ 第二个,是在亚马逊的美国老板,他每年都要去报个培训班学一个技能,比如:厨艺、开双翼飞机、夜总会里的DJ……、甚至去华盛顿去学当一个政客。
  ♥ 第三个,是在汤森路透工作时,一个英国的同事,有一天他说他离职了,和自己的老婆准备用余生去周游世界,我问他是不是有足够多的钱了?他和我说,钱不够,他俩口子的计划是,边旅游边打工,打工打够到下一站的钱就走。他还说,那种用假期去另一个城市的旅游太没意思了,如果你不在那个地方生活上一段时间 ,你怎么能算是好的旅游体验呢?好吧,无法反驳。

  我是觉得他们把自己的人生过得如此有意思,令我很佩服。虽然跨界跨得有点猛,但是 Why Not?
  在这里,我想说,去追求一种和众人不一样的人生经历也是一件挺好的事,我个人感觉,比起在职场里有趣地多多了。如果你厌倦了职场,其实为什么不去追求一下不同的人生经历呢。就算你不想去追求跨度比较大的人生经历,那么,在技术圈里,也有很多有价值有意思的经历也可以去的。追求刺激有意义的与众不同的经历的人,其实也能算是一种人生的成功,不是吗?
  如果只说技术方面,我个人看到的去追求经历的人,有两种追求的人其实也很成功的:

  ♥ 到技术创新的发源地去经历创新。计算机互联网各种技术的创新引擎,基本上来说,就是在美国了。我们赶上了这个时代,也选对了这个时代最火热的行业,那么,有什么理由不去这个时代的技术发动机那里去经历呢?在美国硅谷湾区,无论是大公司,还是创业公司,都在迸发着各式各样的创新,如果有能力有机会,为什么不努力去经历一下呢?不经历一下,老了不会觉得错过了是一种后悔吗?
  ♥ 去经历下一个热点技术的发展。从IT,到互联网、再到移动互联网、云计算、大数据,再到未来的AI,VR,IoT……,技术创新的浪潮一波接一波的过来,你是想在那继续搬砖搬下去,是想迎浪而上去经历浪潮,还是想成为一个随波逐流的人?

  打工也好,创业也好,在国内也好,在国外也好,这些都是形式,不是内容。内容则是你有没有和有想法的人去经历有意义有价值事?人生苦短,白驹过隙,我们技术人员最大的幸运就是生在这样一个刺激的时代,那么,你还有什么理由不去追逐这些前沿刺激的经历呢?

三、追求自由的生活

  我相信“自由”这个事,是所有人的心中都会想去追求的。“生命诚可贵,爱情价更高,…… ”(哈哈)
  但一说起自由,绝大多数人都想到的是“财富自由”或是“财务自由”,其实,并不完全是这样的,在自由的通路上,我个人的经历告诉我,其实,你会有很多的不同类型的自由。下面,是我对几个层次的“自由”的理解。
  第一层自由——工作自由。人的第一层自由的境界是——“工作自由”,我到不是说你在工作单位上可以很自由,虽然有特例,但并不普遍。我想说的“工作自由”是——你不会有失业危机感了。也就是说,你成了各个公司的抢手货,你不但不愁找不到工作,而且你是完全不愁找不到好工作。试想一下,如果是工作来找你,一方面,你就有真正意义上的工作选择权了,另一方面,你都不愁工作了,你完全就可以随时离职去干你想干的事了。此时,你就达到了“工作自由”。
  第一层自由——技能自由。工作自由已是不错,不过前提是你还是需要依赖于别人提供的工作机会。而技能自由则是你可以用自己的技能养活自己,而不需要去公司里工作。也就是所谓的自由职业者了,社会上,这样的人也不少,比如,一些健身体育教练、设计师、翻译者、作者……这些都可以算是自由职业者,程序员这个职业中只要不是搬砖的,有想法的,就有可以成为自由积业者的潜质,想一想,你拥有的编程能力,其实是一种创造的能力,也就是创造力,只要你Make Something People Want(YC创业公司的slogan),你是完全可以通过自己的技能来养活自己的。如果你通过某些自动化的东西,或是你在App上做了一个软件个体户,让自己的收入不断,甚至你做了一个开源软件,社区每个月都给你捐款捐到比你打工挣的还多,那么你就真正的有了技能自由了。
  第一层自由——物质自由。我把财务自由换了一种说法。我个人觉得,除了有个好爸爸之外这种特例的情况,如果你想有物质自由的话,本质上来说,你一定要学会投资,投资不一定是你的钱,时间也是一种财富,年轻更是,你怎么投资你的时间还有你的青春?你要把你的投资投到什么样的事,什么样的人?对于投资这个事,风险也比较大。但是,人生不敢冒险可能才是最大的冒险。这个世界有很多技术不是你能看书学来的,而要只能在实战中学会的,比如:游泳。投资可能也是一种。只有真正懂投资的人,或是运气非常好的人,才可能实现物质自由。

  追求自由的生活,其实也是个人发展道路上的一个不错的选择。通常来说,自由的人,能力都不差,钱也不会少。因为,他们懂得投资。
  也就是说,拥有追求自由能力的的人,

  ♥ 不但有领导力和创造力(也可指导大多数人并走在大多数人前面)
  ♥ 同时他还懂得怎么投资(知道时间和精力和金钱应该投在什么地方)

  注:这里我没有提精神自由,老实说,精神上的自由我也不清楚是什么东西,因为我还没有见过,眼界有限,所以先按不表了,不然真成鸡汤文了)

总结

  无论是在职场中打拼,还是追求精彩的经历,还是去实现自由,我觉得都是不错的个人发展的方向。
  他们都有重叠,比如:

  ♥ 你可以在职场中去追求那些刺激的经历的公司。
  ♥ 同样也可以通过加入有潜力高速发展的公司来达到自由。
  ♥ 你也可以通过追寻不一样的经历来达到人生的自由。
  ♥ ……

  总之,这里的逻辑是——

  ♥ 能够去规划自己的个人发展的人,通常都是有很多机会和可能性的人。
  ♥ 有很多机会和可能性的人,通常都是有Leadership,喜欢冒险的人。
  ♥ 有Leadership喜欢冒险的人,通常都是学习能力强,思维活跃,喜欢折腾,懂得“投资”的人。
  ♥ 学习能力强思维活跃的人,通常来说,都是喜欢看书,喜欢实践和新鲜事物,不怕艰难和挑战,用智力而不是使蛮力的人。
  ♥ 懂得“投资”的人,通常来说,他们更多的关注的是未来和长远的成长,而不是当下的KPI、奖金和晋升。

前端常用学习网站

@(welcome)[前端菜鸟|掘金中]

###技术网站

###资源整合

###美工集锦

###全栈修炼

###官方文档

###前端工具

###JS库

###JS规范

###jQuery插件及特效

###插件库

###H5 和 CSS3

###代码优化

###快速搭建项目

###深度好文

###前端搭建工具

###前端服务器

###待学习

###关于工具

###关于mac

###编辑软件

###前后端通道

###company

###微信小程序

###兼职orwork

###后端步步为营

开源许可证license选择

什么是license

  开源许可

常用的license有哪些

   世界上的开源许可证,大概有上百种。很少有人搞得清楚它们的区别。最流行的六种是—-GPL、BSD、MIT、Mozilla、Apache和LGPL;

如何选择

  对于以上6种开源软件许可,乌克兰程序员Paul Bagwell清楚地描述了它们的一些重要的约束:

  国内阮一峰翻译如下:

node导出Excel表格方式

如果雷同,纯属巧合

  解析excel文件,并导出为json格式,可使用SheetJS js-xlsx

  解析json语句 【可以来自于前端页面,也可以后台直接调用】可使用可使用Excel-Export

使用demo:

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "node-excel-export",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./index.js"
},
"dependencies": {
"excel-export": "^0.5.1",
"express": "~4.13.1"
}
}

  express搭建服务器,excel-export到处文件,入口文件为index.js

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
var express = require('express');
var nodeExcel = require('excel-export'); //excel到处插件
var app = express();
app.get('/excel', function(req, res){
//基本excel规则
var conf = {};
conf.stylesXmlFile = "styles.xml";
conf.cols = [{
caption: '编号', //行名称
type:'number', //类型
width: 15, //宽度
beforeCellWrite:function(row, cellData){ //处理数据
return cellData; //数据大写
}
},{
caption: '姓名',
type:'string',
width: 20,
beforeCellWrite:function(row, cellData,eOpt){ //处理数据
if(cellData == ""){
return "查无此人";
}
return cellData;
}
},{
caption: '日期',
type:'string',
width: 25
}];
conf.rows = [
[1, "华晨宇","2014-04-15 00:00:00"],
[2, "","2014-04-15 00:00:00"],
[3, "汪苏泷","2014-04-17 00:00:00"],
[4, "罗一笑","2014-04-18 00:00:00"]
];
var result = nodeExcel.execute(conf);
res.setHeader('Content-Type', 'application/vnd.openxmlformats');
res.setHeader("Content-Disposition", "attachment; filename=" + "userDate.xlsx"); //会保存userDate为文件名的excel文件
res.end(result, 'binary');
});
app.listen(8888);
console.log('Listening on port 8888');

   conf是配置项,config.cols中定义了表格行的规则,conf.rows是我们模拟的假数据,对应依次打印在excel表中

   conf.cols中有beforeCellWrite方法,可做数据处理

   我们看到,excel表格的样式规则是一个名叫styles.xml的文件,你可直接复制到自己的项目中

   styles.xml文件地址

   服务器端口号为8888.启动服务器后,访问localhost:8888/excel

   打开页面后,会自动下载userDate.excel文件,文件名可根据自己情况做更改

   这个demo项目地址

   很简单的小demo,希望对你有用

判断单、多张图片加载完成

  在实际的运用中有这样一种场景,某资源加载完成后再执行某个操作,例如在做导出时,后端通过打开模板页生成PDF,并返回下载地址。这时前后端通常需要约定一个flag,用以标识模板准备就绪,可以生成PDF了。

  试想,如果模板中有图片,此时如何判断图片是否加载完成?

  在此之前来了解一下jquery的ready与window.onload的区别,ready只是dom结构加载完毕,便视为加载完成。(此时图片没有加载完毕),onload是指dom的生成和资源完全加载(比如flash、图片)出来后才执行。接下来回到正题,先从单张图片说起。

  (1)单张图片(图片在文档中)

1
<img id='xiu' src="http://www.daqianduan.com/wp-content/uploads/2014/11/hs-xiu.jpg">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(document).ready(function(){
//jquery
$('#xiu').load(function(){
// 加载完成
});
//原生 onload
var xiu = document.getElementById('xiu')
xiu.onload = xiu.onreadystatechange = function(){
if(!this.readyState||this.readyState=='loaded'||this.readyState=='complete'){
// 加载完成
}
};
})

  注:
  1、IE8及以下版本不支持onload事件,但支持onreadystatechange事件;
  2、readyState是onreadystatechange事件的一个状态,值为loaded或complete的时候,表示已经加载完毕。
  3、以下内容省略兼容

  (2)单张图片(图片动态生成)

1
2
3
4
5
var xiu = new Image()
xiu.src = 'http://www.daqianduan.com/wp-content/uploads/2014/11/hs-xiu.jpg'
xiu.onload = function(){
// 加载完成
}

  (3)单张图片(结合ES6 Promise)

1
2
3
4
5
6
7
8
9
10
new Promise((resolve, reject)=>{
let xiu = new Image()
xiu.src = 'http://www.daqianduan.com/wp-content/uploads/2014/11/hs-xiu.jpg'
xiu.onload = function(){
// 加载完成
resolve(xiu)
}
}).then((xiu)=>{
//code
})

  (4)多张图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var img = [],
flag = 0,
mulitImg = [
'http://www.daqianduan.com/wp-content/uploads/2017/03/IMG_0119.jpg',
'http://www.daqianduan.com/wp-content/uploads/2017/01/1.jpg',
'http://www.daqianduan.com/wp-content/uploads/2015/11/jquery.jpg',
'http://www.daqianduan.com/wp-content/uploads/2015/10/maid.jpg'
];
var imgTotal = mulitImg.length;
for(var i = 0 ; i < imgTotal ; i++){
img[i] = new Image()
img[i].src = mulitImg[i]
img[i].onload = function(){
//第i张图片加载完成
flag++
if( flag == imgTotal ){
//全部加载完成
}
}
}

  (5)多张图片(结合ES6 Promise.all())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let mulitImg = [
'http://www.daqianduan.com/wp-content/uploads/2017/03/IMG_0119.jpg',
'http://www.daqianduan.com/wp-content/uploads/2017/01/1.jpg',
'http://www.daqianduan.com/wp-content/uploads/2015/11/jquery.jpg',
'http://www.daqianduan.com/wp-content/uploads/2015/10/maid.jpg'
];
let promiseAll = [], img = [], imgTotal = mulitImg.length;
for(let i = 0 ; i < imgTotal ; i++){
promiseAll[i] = new Promise((resolve, reject)=>{
img[i] = new Image()
img[i].src = mulitImg[i]
img[i].onload = function(){
//第i张加载完成
resolve(img[i])
}
})
}
Promise.all(promiseAll).then((img)=>{
//全部加载完成
})

看完就懂的HTTPS

译注:本文作者酷壳/陈皓

  我们先不了聊HTTP,HTTPS,我们先从一个聊天软件说起,我们要实现A能发一个hello消息给B:

  如果我们要实现这个聊天软件,本文只考虑安全性问题,要实现

A发给B的hello消息包,即使被中间人拦截到了,也无法得知消息的内容

如何做到真正的安全?

  这个问题,很多人马上就想到了各种加密算法,什么对称加密、非对称加密、DES、RSA、XX、噼里啪啦~
  而我想说,加密算法只是解决方案,我们首先要做的是理解我们的问题域——什么是安全?
  我个人的理解是:

A与B通信的内容,有且只有A和B有能力看到通信的真正内容

  好,问题域已经定义好了(现实中当然不止这一种定义)。对于解决方案,很容易就想到了对消息进行加密。
  题外话,但是只有这一种方法吗?我看未必,说不定在将来会出现一种物质打破当前世界的通信假设,实现真正意义上的保密。
  对于A与B这样的简单通信模型,我们很容易做出选择:

  这就是对称加密算法,其中图中的密钥S同时扮演加密和解密的角色。具体细节不是本文范畴。
  只要这个密钥S不公开给第三者,同时密钥S足够安全,我们就解决了我们一开始所定问题域了。因为世界上有且只有A与B知道如何加密和解密他们之间的消息。
  但是,在WWW环境下,我们的Web服务器的通信模型没有这么简单:

  如果服务器端对所有的客户端通信都使用同样的对称加密算法,无异于没有加密。那怎么办呢?即能使用对称加密算法,又不公开密钥?请读者思考21秒钟。

  答案是:Web服务器与每个客户端使用不同的对称加密算法:

如何确定对称加密算法

  慢着,另一个问题来了,我们的服务器端怎么告诉客户端该使用哪种对称加密算法?
  当然是通过协商。

  但是,你协商的过程是没有加密的,还是会被中间人拦截。那我们再对这个协商过程进行对称加密就好了,那你对协商过程加密的加密还是没有加密,怎么办?再加密不就好了……好吧,进行鸡生蛋蛋生鸡的问题了。

如何对协商过程进行加密

  新问题来了,如何对协商过程进行加密?密码学领域中,有一种称为“非对称加密”的加密算法,特点是私钥加密后的密文,只要是公钥,都可以解密,但是公钥加密后的密文,只有私钥可以解密。私钥只有一个人有,而公钥可以发给所有的人。

  虽然服务器端向A、B……的方向还是不安全的,但是至少A、B向服务器端方向是安全的。
  好了,如何协商加密算法的问题,我们解决了:使用非对称加密算法进行对称加密算法协商过程。
  这下,你明白为什么HTTPS同时需要对称加密算法和非对称加密算法了吧?

协商什么加密算法

  要达到Web服务器针对每个客户端使用不同的对称加密算法,同时,我们也不能让第三者知道这个对称加密算法是什么,怎么办?
  使用随机数,就是使用随机数来生成对称加密算法。这样就可以做到服务器和客户端每次交互都是新的加密算法、只有在交互的那一该才确定加密算法。
  这下,你明白为什么HTTPS协议握手阶段会有这么多的随机数了吧。

如何得到公钥?

  细心的人可能已经注意到了如果使用非对称加密算法,我们的客户端A,B需要一开始就持有公钥,要不没法开展加密行为啊。
  这下,我们又遇到新问题了,如何让A、B客户端安全地得到公钥?
  我能想到的方案只有这些:

  • 方案1. 服务器端将公钥发送给每一个客户端
  • 方案2. 服务器端将公钥放到一个远程服务器,客户端可以请求得到

  我们选择方案1,因为方案2又多了一次请求,还要另外处理公钥的放置问题。
  公钥被调包了怎么办?又是一个鸡生蛋蛋生鸡问题?
  但是方案1有个问题:如果服务器端发送公钥给客户端时,被中间人调包了,怎么办?

  我画了张图方便理解:

  显然,让每个客户端的每个浏览器默认保存所有网站的公钥是不现实的。

使用第三方机构的公钥解决鸡生蛋蛋生鸡问题

  公钥被调包的问题出现,是因为我们的客户端无法分辨返回公钥的人到底是中间人,还是真的服务器。这其实就是密码学中提的身份验证问题。
  如果让你来解决,你怎么解决?如果你了解过HTTPS,会知道使用数字证书来解决。但是你想过证书的本质是什么么?请放下你对HTTPS已有的知识,自己尝试找到解决方案。
  我是这样解决的。既然服务器需要将公钥传给客户端,这个过程本身是不安全,那么我们为什么不对这个过程本身再加密一次?可是,你是使用对称加密,还是非对称加密?这下好了,我感觉又进了鸡生蛋蛋生鸡问题了。
  问题的难点是如果我们选择直接将公钥传递给客户端的方案,我们始终无法解决公钥传递被中间人调包的问题。
  所以,我们不能直接将服务器的公钥传递给客户端,而是第三方机构使用它的私钥对我们的公钥进行加密后,再传给客户端。客户端再使用第三方机构的公钥进行解密。
  下图就是我们设计的第一版“数字证书”,证书中只有服务器交给第三方机构的公钥,而且这个公钥被第三方机构的私钥加密了:

  如果能解密,就说明这个公钥没有被中间人调包。因为如果中间人使用自己的私钥加密后的东西传给客户端,客户端是无法使用第三方的公钥进行解密的。

  话到此,我以为解决问题了。但是现实中HTTPS,还有一个数字签名的概念,我没法理解它的设计理由。
  原来,我漏掉了一个场景:第三方机构不可能只给你一家公司制作证书,它也可能会给中间人这样有坏心思的公司发放证书。这样的,中间人就有机会对你的证书进行调包,客户端在这种情况下是无法分辨出是接收的是你的证书,还是中间人的。因为不论中间人,还是你的证书,都能使用第三方机构的公钥进行解密。像下面这样:
  第三方机构向多家公司颁发证书的情况:

  客户端能解密同一家第三机构颁发的所有证书:

  最终导致其它持有同一家第三方机构证书的中间人可以进行调包:

数字签名,解决同一机构颁发的不同证书被篡改问题

  要解决这个问题,我们首先要想清楚一个问题,辨别同一机构下不同证书的这个职责,我们应该放在哪?
  只能放到客户端了。意思是,客户端在拿到证书后,自己就有能力分辨证书是否被篡改了。如何才能有这个能力呢?
  我们从现实中找灵感。比如你是HR,你手上拿到候选人的学历证书,证书上写了持证人,颁发机构,颁发时间等等,同时证书上,还写有一个最重要的:证书编号!我们怎么鉴别这张证书是的真伪呢?只要拿着这个证书编号上相关机构去查,如果证书上的持证人与现实的这个候选人一致,同时证书编号也能对应上,那么就说明这个证书是真实的。
  我们的客户端能不能采用这个机制呢?像这样:

  可是,这个“第三方机构”到底是在哪呢?是一个远端服务?不可能吧?如果是个远端服务,整个交互都会慢了。所以,这个第三方机构的验证功能只能放在客户端的本地了。

客户端本地怎么验证证书呢?

  客户端本地怎么验证证书呢?答案是证书本身就已经告诉客户端怎么验证证书的真伪。
  也就是证书上写着如何根据证书的内容生成证书编号。客户端拿到证书后根据证书上的方法自己生成一个证书编号,如果生成的证书编号与证书上的证书编号相同,那么说明这个证书是真实的。
  同时,为避免证书编号本身又被调包,所以使用第三方的私钥进行加密。
  这地方有些抽象,我们来个图帮助理解:
  证书的制作如图所示。证书中的“编号生成方法MD5”就是告诉客户端:你使用MD5对证书的内容求值就可以得到一个证书编号。

  当客户端拿到证书后,开始对证书中的内容进行验证,如果客户端计算出来的证书编号与证书中的证书编号相同,则验证通过:

  但是第三方机构的公钥怎么跑到了客户端的机器中呢?世界上这么多机器。
  其实呢,现实中,浏览器和操作系统都会维护一个权威的第三方机构列表(包括它们的公钥)。因为客户端接收到的证书中会写有颁发机构,客户端就根据这个颁发机构的值在本地找相应的公钥。

题外话:如果浏览器和操作系统这道防线被破了,就没办法。想想当年自己装过的非常规XP系统,都害怕。

  说到这里,想必大家已经知道上文所说的,证书就是HTTPS中数字证书,证书编号就是数字签名,而第三方机构就是指数字证书签发机构(CA)。

CA如何颁发数字证书给服务器端的?

  当我听到这个问题时,我误以为,我们的SERVER需要发网络请求到CA部门的服务器来拿这个证书。😭 到底是我理解能力问题,还是。。
  其实,问题应该是CA如何颁发给我们的网站管理员,而我们的管理员又如何将这个数字证书放到我们的服务器上。

  我们如何向CA申请呢?每个CA机构都大同小异,我在网上找了一个:

  拿到证书后,我们就可以将证书配置到自己的服务器上了。那么如何配置?这是具体细节了,留给大家google了。

也许我们需要整理一下思路

  我们通过推算的方式尝试还原HTTPS的设计过程。这样,我们也就明白了为什么HTTPS比HTTP多那么多次的交互,为什么HTTPS的性能会差,以及找到HTTPS的性能优化点。
  而上面一大堆工作都是为了让客户端与服务器端安全地协商出一个对称加密算法。这就是HTTPS中的SSL/TLS协议主要干的活。剩下的就是通信时双方使用这个对称加密算法进行加密解密。
  以下是一张HTTPS协议的真实交互图(从网上copy的,忘了从哪了,如果侵权麻烦告知):

能不能用一句话总结HTTPS?

  答案是不能,因为HTTPS本身实在太复杂。但是我还是尝试使用一段话来总结HTTPS:
  HTTPS要使客户端与服务器端的通信过程得到安全保证,必须使用的对称加密算法,但是协商对称加密算法的过程,需要使用非对称加密算法来保证安全,然而直接使用非对称加密的过程本身也不安全,会有中间人篡改公钥的可能性,所以客户端与服务器不直接使用公钥,而是使用数字证书签发机构颁发的证书来保证非对称加密过程本身的安全。这样通过这些机制协商出一个对称加密算法,就此双方使用该算法进行加密解密。从而解决了客户端与服务器端之间的通信安全问题。

如何成为一名卓越的前端工程师

译注:本文翻译自谷歌工程师 Philip Walton 的一篇博客。

  最近我收到一封读者来信让我陷入了思考,信是这么写的:
  Hi Philip,您是否介意我问,您是如何成为一名卓越 (great) 的前端工程师的?对此您有什么建议吗?
  不得不承认,被问这样的问题,我很惊讶,因为我从来不觉得自己是个很卓越的前端工程师。甚至我入行的头几年时并不认为自己可以做好这一行。我只确定自己比自己想象中还才疏学浅,而且大家面试我的时候都不知道从何问起。
  话虽这么说,我到现在做得还算不错,而且成为了团队中有价值的一员。但我最终离开 (去寻求新的挑战——即我还不能够胜任的工作) 的时候,我经常会被要求招聘我的继任者。现在回看这些面试,我不禁感叹当我刚开始的时候自己在这方面的知识是多么的匮乏。我现在或许不会按照我自己的模型进行招聘,即便我个人的这种经历也有可能成功。
  我在 web 领域工作越长时间,我就越意识到区分人才和顶尖人才的并不是他们的知识——而是他们思考问题的方式。很显然,知识在很多情况下是非常重要而且关键的——但是在一个快速发展的领域,你前进和获取知识的方式 (至少在相当长的一段时间里) 会比你已经掌握的知识显得更加重要。更重要的是:你是如何运用这些知识解决每天的问题的。
  这里有许许多多的文章谈论你工作中需要的语言、框架、工具等等。我希望给一些不一样的建议。在这篇文章里,我想谈一谈一个前端工程师的心态,希望可以帮助大家找到通往卓越的道路。

别光解决问题,想想究竟发生了什么

  很多人埋头写 CSS 和 JavaScript 直到程序工作起来了,然后就去做别的事情了。我通过 code review 发现这种事经常发生。我总会问大家:“为什么你会在这里添加 float: left?”或者“这里的 overflow: hidden 是必要的吗?”,他们往往答道:“我也不知道,可是我一删掉它们,页面就乱套了。”
  JavaScript 也是一样,我总会在一个条件竞争的地方看到一个 setTimeout,或者有些人无意中阻止了事件传播,却不知道它会影响到页面中其它的事件处理。我发现很多情况下,当你遇到问题的时候,你只是解决当下的问题罢了。但是如果你永远不花时间理解问题的本源,你将一次又一次的面对相同的问题。花一些时间找出为什么,这看上去费时费力,但是我保证它会节省你未来的时间。在完全理解整个系统之后,你就不需要总去猜测和论证了。

学会预见未来的浏览器发展趋势

  前后端开发的一个主要区别在于后端代码通常都运行在完全由你掌控的环境下。前端相对来说不那么在你的掌控之中。不同用户的平台或设备是前端永恒的话题,你的代码需要优雅掌控这一切。
  我记得自己 2011 年之前曾经阅读某主流 JavaScript 框架的时候看到过下面这样的代码 (简化过的):

1
var isIE6 = !isIE7 && !isIE8 && !isIE9;

  在这个例子中变量 IE6 为了判断 IE 浏览器版本是否是 6 或更低的版本。那么在 IE10 发布时,我们的程序判断还是会出问题。
  我理解在真实世界特性检测并不 100% 工作,而且有的时候你不得不依赖有 bug 的特性或根据浏览器特性检测的错误设计白名单。但你为此做的每一件事都非常关键,因为你预见到了不再有 bug 的未来。对于我们当中的很多人来说,我们今天写的代码都会比我们的工作周期要长。有些我写的代码已经过去 8 年多了还在产品线上运行。这让人很满足又很不安。

阅读规范文档

  浏览器有 bug 是很难免的事,但是当同一份代码在两个浏览器渲染出来的效果不一样,人们总会不假思索的推测,那个“广受好评”的浏览器是对的,而“不起眼”的浏览器是错的。但事实并不一定如此,当你的假设出现错误时,你选取的变通办法都会在未来遭遇问题。
   一个就近的例子是 flex 元素的默认最小尺寸问题。根据规范的描述,flex 元素初始化的 min-width 和 min-height 的值是 auto (而不是 0),也就是说它们默认应该收缩到自己内容的最小尺寸。但是在过去长达 8 个月的时间里,只有 Firefox 的实现是准确的。
   如果你遇到了这个浏览器兼容性的问题并且发现 Chrome、IE、Opera、Safari 的效果相同而 Firefox 和它们不同时,你很可能会认为是 Firefox 搞错了。事实上这种情况我见多了。很多我在自己 Flexbugs 项目上报的问题都是这样的。而且这些解决方案的问题会在两周之后 Chrome 44 修复之后被体现出来。和遵循标准的解决方案相比,这些方案都伤害到了正确的规范行为。当同一份代码在两个或更多浏览器的渲染结果不同时,你应该花些时间确定哪个效果是正确的,并且以此为标准写代码。你的解决方案应该是对未来友好的。额外的,所谓“卓越”的前端工程师是时刻感受变化,在某项技术成为主流之前就去适应它的,甚至在为这样的技术做着贡献。如果你锻炼自己看到规范就能在浏览器支持它之前想象出它如何工作的,那么你将成为谈论并影响其规范开发的那群人。

阅读别人的代码
  出于乐趣阅读别人的代码可能并不是你每周六晚上会想到的娱乐项目,但是这毫无疑问是你成为优秀工程师的最佳途径。自己独立解决问题绝对是个不错的方式,但是这不应该是你唯一的方式,因为它很快就会让你稳定在某个层次。阅读别人的代码会让你开阔思维,并且阅读和理解别人写的代码也是团队协作或开源贡献必须具备的能力。我着实认为很多公司在招聘新员工的时候犯的最大错误是他们只评估应聘者从轮廓开始写新代码的能力。我几乎没有见过一场面试会要求应聘者阅读现有的代码,找出其中的问题,并修复它们。缺少这样的面试流程真的非常不好,因为你作为工程师的很多时间都花费在了在现有的代码的基础上增加或改变上面,而不是搭建新的东西。

与比你聪明的人一起工作

  我印象中的很多前端开发者 (相比于全职工作来说) 都是自由职业者,有同类想法的后端开发者并没有那么多。可能是因为很多前端都是自学成才的而后端则多是学校里学出来的。不论是自我学习还是自我工作,我们都面对一个问题:你并没有机会从比你聪明的家伙那里学到什么。没有人帮你 review 代码,也没有人与你碰撞灵感。我强烈建议,最起码在你职业发展的前期,你要在一个团队里工作,尤其是一个普遍比你聪明而且有经验的团队里工作。如果你最终会在你职业发展的某个阶段选择独立工作,一定要让自己投身在开源社区当中。保持对开源项目的活跃贡献,这会给你团队工作相同甚至更多的益处。

“造轮子”
  造轮子在商业上是非常糟糕的,但是从学习的角度是非常好的。你可能很想把那些库和小工具直接从 npm 里拿下来用,但也可以想象一下你独立建造它们能够学到多少东西。我知道有些人读到这里是特别不赞成的。别误会,我并没有说你不应该使用第三方代码。那些经过充分测试的库具有多年的测试用例积累和已知问题积累,使用它们绝对是非常明智的选择。但在这里我想说的是如何从优秀到卓越。我觉得这个领域很多卓越的人都是我每天在用的非常流行的库的作者或维护者。
  你可能不曾打造过自己的 JavaScript 库也拥有一个成功的职业发展,但是你从不把自己手弄脏是几乎不可能淘到金子的。在这一行大家普遍会问的一个问题是:我接下来应该做点什么?如果你没有试着学一个新的工具创建一个新的应用,那不妨试着重新造一个你喜欢的 JavaScript 库或 CSS 框架。这样做的一个好消息是,在你遇到困难的时候,所有现成的库的源代码都会为你提供帮助。

把你学到的东西都记录下来

  最后,但丝毫不逊色的是,你应该把你学到的东西记录下来。这样做有很多原因,但也许最重要的原因是它强迫你更好的理解这件事。如果你无法讲清楚它的工作原理,在整个过程中它会推动你自己把并不真正理解的东西弄清楚。很多情况下你根本意识不到自己还不理解它们——直到自己动手写的时候。根据我的经验,写作、演讲、做 demo 是强迫自己完全深入理解一件事的最佳方式。就算你写的东西没有人看,整个过程也会让你受益匪浅。

滚动信息条的两种展示方法

  • 无间歇 直接滚动
  • 间歇式滚动

HTML

1
2
3
4
<div id="recoder_con">
<div id="recoder_ul1"></div>
<div id="recoder_ul2"></div>
</div>

CSS

1
2
3
4
5
6
7
8
.recoder-con{
display: inline-block;
width: 584px; //指定宽度
height: 280px; //指定高度
overflow: scroll;
overflow-x: hidden;
overflow-y: hidden;
}

无间歇JS

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 prizeScroll(listNum) {
var speed = 65,
wap = document.getElementById("recoder_con"),
ul1 = document.getElementById("recoder_ul1"),
ul2 = document.getElementById("recoder_ul2");
ul2.innerHTML = ul1.innerHTML;
var leftHeight;
if (listNum > 4) {
leftHeight = 0;
} else if (listNum == 4) {
leftHeight = 33;
}
function Marquee2() {
if (ul2.offsetTop - wap.scrollTop <= leftHeight) {
wap.scrollTop -= ul1.offsetHeight;
} else {
wap.scrollTop++;
}
}
var MyMar2 = setInterval(function () {
Marquee2();
}, speed);
}
prizeScroll(4)

有间歇JS

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
var wap = $('#recoder_con'),
ul1Html = $('#recoder_ul1').html(),
ul2 = $('#recoder_ul2');
var speed = 50,
listNum = 4,
delay = 1000,
liHeight = 21,
time,
scrollTop = 0;
ul2.html(ul1Html);
function startScroll() {
time = setInterval("scrollUp()", speed);
wap.scrollTop(scrollTop++);
}
function scrollUp(){
if(scrollTop % liHeight == 0){
clearInterval(time);
setTimeout(startScroll,delay);
}else{
wap.scrollTop(scrollTop++);
if(scrollTop >= (listNum -1) * liHeight){
scrollTop = 0;
wap.scrollTop(scrollTop);
}
}
}
setTimeout('startScroll()',delay);

vi命令大全

[TOC]
@(welcome)[前端菜鸟|掘金中]

  • [x] 进入vi的命令
    • vi filename :打开或新建文件,并将光标置于第一行首
    • vi +n filename :打开文件,并将光标置于第n行首
    • vi + filename :打开文件,并将光标置于最后一行首
    • vi +/pattern filename:打开文件,并将光标置于第一个与pattern匹配的串处
    • vi -r filename :在上次正用vi编辑时发生系统崩溃,恢复filename
    • vi filename….filename :打开多个文件,依次进行编辑
  • [x] 移动光标类命令

    • h :光标左移一个字符
    • l :光标右移一个字符
    • space:光标右移一个字符
    • Backspace:光标左移一个字符
    • k或Ctrl+p:光标上移一行
    • j或Ctrl+n :光标下移一行
    • Enter :光标下移一行
    • w或W :光标右移一个字至字首
    • b或B :光标左移一个字至字首
    • e或E :光标右移一个字至字尾
    • ) :光标移至句尾
    • ( :光标移至句首
    • }:光标移至段落开头
    • {:光标移至段落结尾
    • nG:光标移至第n行首
    • n+:光标下移n行
    • n-:光标上移n行
    • n$:光标移至第n行尾
    • H :光标移至屏幕顶行
    • M :光标移至屏幕中间行
    • L :光标移至屏幕最后行
    • 0:(注意是数字零)光标移至当前行首
    • $:光标移至当前行尾
  • [x] 屏幕翻滚类命令

    • Ctrl+u:向文件首翻半屏
    • Ctrl+d:向文件尾翻半屏
    • Ctrl+f:向文件尾翻一屏
    • Ctrl+b;向文件首翻一屏
    • nz:将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。
  • [x] 插入文本类命令

    • i :在光标前
    • I :在当前行首
    • a:光标后
    • A:在当前行尾
    • o:在当前行之下新开一行
    • O:在当前行之上新开一行
    • r:替换当前字符
    • R:替换当前字符及其后的字符,直至按ESC键
    • s:从当前光标位置处开始,以输入的文本替代指定数目的字符
    • S:删除指定数目的行,并以所输入文本代替之
    • ncw或nCW:修改指定数目的字
    • nCC:修改指定数目的行
  • [x] 删除命令
    • ndw或ndW:删除光标处开始及其后的n-1个字
    • do:删至行首
    • d$:删至行尾
    • ndd:删除当前行及其后n-1行
    • x或X:删除一个字符,x删除光标后的,而X删除光标前的
    • Ctrl+u:删除输入方式下所输入的文本
  • [x] 搜索及替换命令

    • /pattern:从光标开始处向文件尾搜索pattern
    • ?pattern:从光标开始处向文件首搜索pattern
    • n:在同一方向重复上一次搜索命令
    • N:在反方向上重复上一次搜索命令
    • :s/p1/p2/g:将当前行中所有p1均用p2替代
    • :n1,n2s/p1/p2/g:将第n1至n2行中所有p1均用p2替代
    • :g/p1/s//p2/g:将文件中所有p1均用p2替换
  • [x] 选项设置

    • all:列出所有选项设置情况
    • term:设置终端类型
    • ignorance:在搜索中忽略大小写
    • list:显示制表位(Ctrl+I)和行尾标志($)
    • number:显示行号
    • report:显示由面向行的命令修改过的数目
    • terse:显示简短的警告信息
    • warn:在转到别的文件时若没保存当前文件则显示NO write信息
    • nomagic:允许在搜索模式中,使用前面不带“\”的特殊字符
    • nowrapscan:禁止vi在搜索到达文件两端时,又从另一端开始
    • mesg:允许vi显示其他用户用write写到自己终端上的信息
  • [x] 最后行方式命令(ctrl + c)
    • :n1,n2 co n3:将n1行到n2行之间的内容拷贝到第n3行下
    • :n1,n2 m n3:将n1行到n2行之间的内容移至到第n3行下
    • :n1,n2 d :将n1行到n2行之间的内容删除
    • :w :保存当前文件
    • :e filename:打开文件filename进行编辑
    • :x:保存当前文件并退出
    • :q:退出vi
    • :q!:不保存文件并退出vi
    • :!command:执行shell命令command
    • :n1,n2 w!command:将文件中n1行至n2行的内容作为command的输入并执行之,若不指定n1,n2,则表示将整个文件内容作为command的输入
    • :r!command:将命令command的输出结果放到当前行
  • [x] 寄存器操作
    • “?nyy:将当前行及其下n行的内容保存到寄存器?中,其中?为一个字母,n为一个数字
    • “?nyw:将当前行及其下n个字保存到寄存器?中,其中?为一个字母,n为一个数字
    • “?nyl:将当前行及其下n个字符保存到寄存器?中,其中?为一个字母,n为一个数字
    • “?p:取出寄存器?中的内容并将其放到光标位置处。这里?可以是一个字母,也可以是一个数字
    • ndd:将当前行及其下共n行文本删除,并将所删内容放到1号删除寄存器中。

VI的使用

一、插入文本
┌──┬────────────┐
│命令│描述          │
├──┼────────────┤
│i  │在当前字符前插入文本  │
├──┼────────────┤
│I  │在行首插入文本      │
├──┼────────────┤
│a  │在当前字符后添加文本  │
├──┼────────────┤
│A  │在行末添加文本     │
├──┼────────────┤
│o  │在当前行后面插入一空行 │
├──┼────────────┤
│O  │在当前行前面插入一空行 │
├──┼────────────┤
│R  │以改写方式输入文本   │
└──┴────────────┘
二、移动光标
┌─────┬───────────┐
│命令   │描述         │
├─────┼───────────┤
│j或下箭头 │向下移动一行     │
├─────┼───────────┤
│k或上箭头 │向上移动一行     │
├─────┼───────────┤
│h或左箭头 │左移一个字符     │
├─────┼───────────┤
│l或右箭头 │右移一个字符     │
├─────┼───────────┤
│w     │右移一个词      │
├─────┼───────────┤
│W     │右移一个以空格分隔的词│
├─────┼───────────┤
│b     │左移一个词      │
├─────┼───────────┤
│B     │左移一个以空格分隔的词│
├─────┼───────────┤
│0     │移到行首       │
│Ctrl-F  │向前翻页       │
├─────┼───────────┤
│Ctrl-B  │向后翻页       │
├─────┼───────────┤
│nG    │到第n行        │
├─────┼───────────┤
│G     │到最后一行      │
└─────┴───────────┘
三、替换文本
┌─────┬──────┐
│命令   │描述    │
├─────┼──────┤
│$     │到行尾   │
├─────┼──────┤
│(     │到句子的开头│
├─────┼──────┤
│)     │到句子的末尾│
├─────┼──────┤
│{     │到段落的开头│
├─────┼──────┤
│}     │到段落的末尾│
└─────┴──────┘

四、删除文本
┌───┬───────────┐
│命令 │描述          │
├───┼───────────┤
│r   │替换一个字符      │
├───┼───────────┤
│c   │修改文本直到按下Esc健 │
├───┼───────────┤
│cw  │修改下一个词      │
├───┼───────────┤
│cnw  │修改接下来的n个词   │
└───┴───────────┘
五、文本编辑
┌──┬──────────────────────┐
│命寺│描述                    │
├──┼──────────────────────┤
│yy │将一行文本移到缺省缓冲区中          │
├──┼──────────────────────┤
│yn │将下一个词移到缺省缓冲区中          │
├──┼──────────────────────┤
│ynw │将后面的n个词移到缺省缓冲区中        │
├──┼──────────────────────┤
│p  │如果缺省缓冲区中包含一行文本,则在当前   │
│  │行后面插入一个空行井将缺省缓冲区中的声   │
│  │容粘贴到这一行中;如果缺省缓冲区中包含   │
│  │多个词,把这些词粘贴到光标的右边.     │
├──┼──────────────────────┤
│P  │如果缺省缓冲区中包含一行文本,则正当前    │
│   │行前面插入一个空行井将缺省缓冲区中的内    │
│  │容粘贴到这一行中;如果缺省缓冲区中包含    │
│   │多个词,把这些词粘贴到光标的左边    

  │
└──┴──────────────────────┘
六、保存退出
┌───────────┬───────────────┐
│命令         │描述             │
├───────────┼───────────────┤
│zz          │保存并退出          │
├───────────┼───────────────┤
│:w filename      │写入文件            │
├───────────┼───────────────┤
│:W          │写入文件           │
├───────────┼───────────────┤
│:x          │保存(如果当前文件修改过)并退出│
├───────────┼───────────────┤
│:q!          │不保存文件,直接退出      │
├───────────┼───────────────┤
│:q          │退出vi            │

VI常用技巧

VI命令可以说是Unix/Linux世界里最常用的编辑文件的命令了,但是因为它的命令集众多,很多人都不习惯使用它,其实您只需要掌握基本命令,然后加以灵活运用,就会发现它的优势,并会逐渐喜欢使用这种方法。本文旨在介绍VI的一些最常用命令和高级应用技巧。

一、基本命令介绍

—- 1.光标命令

k、j、h、l——上、下、左、右光标移动命令。虽然您可以在Linux中使用键盘右边的4个光标键,但是记住这4个命令还是非常有用的。这4个键正是右手在键盘上放置的基本位置。
nG——跳转命令。n为行数,该命令立即使光标跳到指定行。
Ctrl+G——光标所在位置的行数和列数报告。
w、b——使光标向前或向后跳过一个单词。
—- 2.编辑命令
i、a、r——在光标的前、后以及所在处插入字符命令(i=insert、a=append、r=replace)。
cw、dw——改变(置换)/删除光标所在处的单词的命令 (c=change、d=delete)。
x、d$、dd——删除一个字符、删除光标所在处到行尾的所有字符以及删除整行的命令。
—- 3.查找命令
—- /string、?string——从光标所在处向后或向前查找相应的字符串的命令。
—- 4.拷贝复制命令
—- yy、p——拷贝一行到剪贴板或取出剪贴板中内容的命令。

二、常见问题及应用技巧

—- 1.在一个新文件中读/etc/passwd中的内容,取出用户名部分。
—- vi file
—- :r /etc/passwd 在打开的文件file中光标所在处读入/etc/passwd
—- :%s/:.*//g 删除/etc/passwd中用户名后面的从冒号开始直到行尾的所有部分。
—- 您也可以在指定的行号后读入文件内容,例如使用命令“:3r /etc/passwd”从新文件的第3行开始读入 /etc/passwd的所有内容。
—- 我们还可以使用以下方法删掉文件中所有的空行及以#开始的注释行。
—- #cat squid.conf.default | grep -v ^$ | grep -v ^#

—- 2.在打开一个文件编辑后才知道登录的用户对该文件没有写的权限,不能存盘,需要将所做修改存入临时文件。
—- vi file
—- :w /tmp/1 保存所做的所有修改,也可以将其中的某一部分修改保存到临时文件,例如仅仅把第20~59行之间的内容存盘成文件/tmp/1,我们可以键入如下命令。
—- vi file
—- :20,59w /tmp/1

—- 3.用VI编辑一个文件,但需要删除大段的内容。
—- 首先利用编辑命令“vi file”打开文件,然后将光标移到需要删除的行处按Ctrl+G显示行号,再到结尾处再按Ctrl+G,显示文件结尾的行号。
—- :23,1045d 假定2次得到的行号为23和1045,则把这期间的内容全删除,也可以在要删除的开始行和结束行中用ma、mb命令标记,然后利用“:a,bd”命令删除。

—- 4.在整个文件的各行或某几行的行首或行尾加一些字符串。
—- vi file
—- :3,$s/^/some string / 在文件的第一行至最后一行的行首插入“some string”。
—- :%s/$/some string/g 在整个文件每一行的行尾添加“some string”。
—- :%s/string1/string2/g 在整个文件中替换“string1”成“string2”。
—- :3,7s/string1/string2/ 仅替换文件中的第3行到第7行中的“string1”成“string2”。
—- 注意: 其中s为substitute,%表示所有行,g表示global。

—- 5.同时编辑2个文件,拷贝一个文件中的文本并粘贴到另一个文件中。
—- vi file1 file2
—- yy 在文件1的光标处拷贝所在行
—- :n 切换到文件2 (n=next)
—- p 在文件2的光标所在处粘贴所拷贝的行
—- :n 切换回文件1

—- 6.替换文件中的路径。
—- 使用命令“:%s#/usr/bin#/bin#g”可以把文件中所有路径/usr/bin换成/bin。也可以使用命令“:%s//usr/bin//bin/g”实现,其中“”是转义字符,表明其后的“/”字符是具有实际意义的字符,不是分隔符。