关于前端工程师:面试官问你工作多久了怎么还不会冒泡排序

前言大家好,我是梁木由,一个有想头的前端,明天温习到了如何排序,那么给大家来分享下,冒泡排序与疾速排序 冒泡排序概念 从第一个元素开始,把以后元素与下一个元素进行比拟,元素大的往后排,小的往前排,顺次比拟到最初一个元素,进行替换地位。 实现步骤 先遍历一共有多少个数须要跟其它数进行比拟再遍历每个数须要跟其它数比拟多少次如果前一个数小于后一个数,就替换地位function bubbleSort(arr){  let len = arr.length;  // 遍历多少个数跟其它数进行比拟  for(let i = 0; i < len; i++){    // 再遍历每个数须要跟其它数比拟多少次    for(let j = 0; j < len - i - 1; j++){      // 如过前一个数小于后一个数      if(arr[j+1] < arr[j]){        // 替换地位       [arr[j+1],arr[j]] = [arr[j],arr[j+1]]     }   } }  return arr}// 验证let arr = [1,44,6,77,3,7,99,12]console.log(bubbleSort(arr))// [1, 3, 6, 7, 12, 44, 77, 99]疾速排序概念 ...

January 11, 2023 · 1 min · jiezi

关于前端工程师:前端工程师2022版某课完结

download:前端工程师2022版某课完结线段树(动静开点)的两种形式题目描述Tag : 「线段树(动静开点)」、「线段树」实现一个 MyCalendar 类来存放你的日程安排。如果要增加的工夫内不会导致三重预订时,则可能存储这个新的日程安排。MyCalendar 有一个 book(int start, int end) 方法。它意味着在 start 到 end 工夫内减少一个日程安排,注意,这里的工夫是半开区间,即 [start,end)[start, end)[start,end), 实数 xxx 的范畴为, start<=x<end start <= x < end start<=x<end。当三个日程安排有一些工夫上的交叉时(例如三个日程安排都在同一时间内),就会产生三重预订。每次调用 MyCalendar.book 方法时,如果可能将日程安排胜利增加到日历中而不会导致三重预订,返回 true。否则,返回 false 并且不要将该日程安排增加到日历中。请按照以下步骤调用 MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)示例:MyCalendar();MyCalendar.book(10, 20); // returns trueMyCalendar.book(50, 60); // returns trueMyCalendar.book(10, 40); // returns trueMyCalendar.book(5, 15); // returns falseMyCalendar.book(5, 10); // returns trueMyCalendar.book(25, 55); // returns true 解释: 前两个日程安排可能增加至日历中。 第三个日程安排会导致双重预订,但可能增加至日历中。第四个日程安排流动(5,15)不能增加至日历中,因为它会导致三重预订。第五个日程安排(5,10)可能增加至日历中,因为它未使用已经双重预订的工夫10。第六个日程安排(25,55)可能增加至日历中,因为工夫 [25,40] 将和第三个日程安排双重预订;工夫 [40,50] 将独自预订,工夫 [50,55)将和第二个日程安排双重预订。复制代码提醒: ...

July 19, 2022 · 6 min · jiezi

关于前端工程师:前端工程师2022版某课完结

download:前端工程师2022版某课完结程序员如何利用技术能力变现 本质上来说,程序员是手艺人,有手艺的人就能做出别人做不进去的货色,而付费也是一件很天然的事了。那么,这个问题就成了,如何让自己的“手艺”更为值钱的问题了。千里之行,积于跬步 任何一件胜利的小事,都是通过一个一个的小胜利达到的。所以,你得确保你有一个一个的小胜利。具体说来,首先,你得让自己身边的人有求于你,或是向别人推荐你。这就需要你能够管制大多数人不能管制的技能或技术,需要你更多地学习,并要有更多的别人没有的经验和经历。一旦你身边的人开始有求于你,或是向别人推荐你,你就会被内部的人留意到,于是其他人就会付费来获取你的帮助。而一旦你的帮忙有成果的话,就会产生效益,无论是经济效益还是社会效益,都会为你开拓更大的空间。你也会因为这样的正向反应而鼓励自己去学习和钻研更多的货色,从而失去一个正向的循环。而且这个正向循环,一旦开始就停不下来了。 关注有价值的货色什么是有价值的货色?价值其实是受供需关系影响的,供大于求,就没什么价值,供不应求,就有价值。这意味着你不只有看到市场,还要看到技术的趋势,能够分辨出什么是支流技术,什么是过渡式的技术。当你比别人有更好的嗅觉时,你就能起动得更快,也就比别人有 先发劣势。对于市场需求。要看清市场,就需要看看各个公司在做什么,他们的难题是什么。简略来说,现在的每家公司无论大小都缺人。是真的缺人吗?中国是人口大国,不缺写代码搬砖的,真正缺的是有能力能够解决技术难题的人,能够提高团队人效的人。所以,从这些方面思考,你会知道哪些技能才是真正的“供不应求”,这样可能让你更有价值。 对于技术趋势。要看清技术趋势,你需要了解历史,就像一个球静止一样,你要知道这个球未来静止的地方,是需要观察球的已经实现静止的轨迹才知道的。因此,了解技术发展轨迹是一件很重要的事。要看一个新的技术是否适应技术发展趋势,你需要将一些老技术的本质吃得很透。因此,在学习技术的过程肯定要多问自己两个问题:“1. 这个技术解决什么问题?为什么别的同类技术做不到?2. 为什么是这样解决的?有没有更好的形式?”另外,还有一个简略的判断方法,如果一个新的技术适应技术发展趋势,那么在这个新的技术出现时,前面肯定会有大型的商业公司反对,这类公司反对得越多,就说明你越需要关注。 找到能体现价值的地方在一家高速发展的公司中,技术人员的价值可能达到最大化。试想,在一家大公司中,技术架构和业务已经定型,基本上没有什么太多的事可能做的。而且对于已经发展起来的大公司来说,经常稳固的重要性超过了翻新。此外,大公司的高级技术人员很多,多你一个不多,少你一个不少,所以你的价值很难被体现进去。而刚起步的公司,业务还没有跑顺,公司的次要精力会放在业务拓展上,这个时候也不太需要高精尖的技术,所以,技术人员的价值也体现不进去。只有那些在高速发展的公司,技术人员的价值才能被最大化地体现进去。比较好的成长路径是,先进入大公司学习大公司的技术和胜利的经验方法,而后找到高速成长的公司,可能实现自己更多的价值。当然,这里并不排除在大公司中找到高速发展的地方。动手能力很重要 成为一个手艺人,动手能力是很重要的,因为在解决任何一个具体问题的时候,有没有动手能力就成为了要害。这也是我一直在写代码的原因,代码里全是细节,细节是魔鬼,只有了解了细节,你才能提出更好或是更靠谱的并可能落地的解决打算。而不是一些抽象和含混的货色。这太重要了。 关注技术付费点技术付费点基本体现在两个地方,一个是,能帮别人“挣钱”的地方;另一个是,能帮别人“省钱”的地方。也就是说,能够帮助别人更流利地挣钱,或是能够帮助别人提高效率,能俭约更多的成本,越间接越好。而且这个技术或解决打算最好还是大多数人做不到的。晋升自己的能力和经历 付费的前提是信赖,只有你晋升自己的能力和经历后,他人才会对你有肯定的信赖,才会感觉你靠谱,才会给你机会。而这个信赖需要用你的能力和经历来填补。比如,你是一个很出名的开源软件的核心开发人员,或是你是某出名公司核心我的项目的核心开发人员,等等。找到有价值的信息源 信息社会,如果你比别人有更好的信息源,那么你就可能比别人成长得更快。对于技术人员来说,咱们知道,几乎所有的技术都源自东方世界,所以,你应该走到信息的源头去。如果你的信息来自朋友圈、微博、知乎、百度或是今日头条,那么你完蛋了。因为这些渠道有价值的信息不多,有养分的可能只有 1%,而为了这 1%,你需要读完 99% 的信息,太不划算了。那么如何找到这些信息源呢?用好 Google 就是一个要害,比如你在 Google 搜索引擎里输出“XXX Best Practice”,或是“Best programming resource”……你就会找到很多。而用好这个更好的信息源需要你的英文能力,因此不断晋升英文能力很要害。 输入观点和价值观真正微小的公司或是产品都是要输入价值观的。只有输入了更先进的价值观,才会获得真正的影响力。然而,你要能输入观点和价值观,并不是一件容易的事,这需要你的积累和经历,而不是一朝之功,需要长期积累。因此,如果想要让你的技能变现,这本质上是一个厚积薄发的过程。

July 13, 2022 · 1 min · jiezi

关于前端工程师:前端工程师2022版完结无密

download:前端工程师2022版-完结无密通过实例深入理解sync.Map的工作原理一. 原生map的“先天不足”对于已经初始化了的原生map,咱们可能尽情地对其进行并发读:// github.com/bigwhite/experiments/inside-syncmap/concurrent_builtin_map_read.go package main import ( "fmt""math/rand""sync") func main() { var wg sync.WaitGroupvar m = make(map[int]int, 100)for i := 0; i < 100; i++ { m[i] = i}wg.Add(10)for i := 0; i < 10; i++ { // 并发读 go func(i int) { for j := 0; j < 100; j++ { n := rand.Intn(100) fmt.Printf("goroutine[%d] read m[%d]: %d\n", i, n, m[n]) } wg.Done() }(i)}wg.Wait()} 复制代码但原生map一个最大的问题就是不反对多goroutine并发写。Go runtime内置对原生map并发写的检测,一旦检测到就会以panic的形式阻止程序持续运行,比如上面这个例子:// github.com/bigwhite/experiments/inside-syncmap/concurrent_builtin_map_write.go package main import ( ...

June 13, 2022 · 3 min · jiezi

关于前端工程师:22岁那年你处在哪个状态现在呢

前言一个人毕生中除了睡觉,占据你最多工夫的就是工作/事业。但,你是否酷爱你的工作?有人说生命的意义在于过程,不在于后果。生存中大多数工夫都是在工作,你享受这个过程吗? 不同阶段的状态刚毕业很多人懵懵懂懂的进入职场,岗位可能跟业余相干,抑或不相干。过后不会去思考太多,感觉能养活本人是第一步,也就是马斯洛需要论的第一层,维持本人在社会中的生存。这时你从大学带出校门会把握一项“技能”,这项技能须要被社会认可的,被社会所须要的(或者说被当下这个社会所须要的)。比方前端开发,后端开发等。这个阶段,可能对于本人是否喜爱本人以后所做的还没有什么概念。重点:这个时候,不能被本人所学的业余所“解放”,你能够从事其它不是本业余的岗位,你要思考的就是2点:1. 本人是否喜爱(前提); 2. 岗位是否有前(钱)途(换句话说就是岗位是否被社会须要,人才供需关系如何)。关键词:喜爱、前(钱)途 毕业后1-2年浸泡退职场这个大染缸1-2年,你会遇到前所未有的职场规定,人际沟通,办公室政治等等。当然更多的对于本人职业“技能”的大幅晋升。这个阶段,可能会钱少,可能会加班。但当你遇到这种状况的时候,如果你恶感,那根本能够阐明你不喜爱本人正在做的事。如果遇到你真正喜爱/酷爱做的工作,你会不分场合的去全情投入。重点:这个阶段倡议拓展各种知识面(广度)为主,提倡用以至学。关键词:广度、“用以至学” 工作4年及以上对于开发来说,如果从事了4年以上了,能力好的根本能造成一套本人的常识体系(结构化思维)以及做事的方法论。对于这个岗位的价值你或者会有本人的见解。如果这个阶段还是一直纯写业务,没有本人的思考和认知的话,那么该停下来问问本人,今后的路要怎么走了。现实中这个阶段会明确,开发对于本人来说是职能岗位(来需要,写业务搬砖),还是什么?如果你意识到这就是一个职能性质的工作,那么你是能够被新生代代替的。可能在不久几年后行将迎来本人的薪资和职业认知天花板,如果迷茫了,就多找比本人厉害的“前辈”交换交换,他们是怎么过去的。在公司内做事要“瞻前(将来)顾后(历史)”。重点:这个阶段倡议将以往碎片(点或线)的常识结构化梳理(线或面),寻找属于本人的业余畛域(深度)为主。构建本人的职业技术壁垒,不可代替的外围竞争力。 关键词:深度、领域专家、方法论 不同阶段的简历简历是你集体展现的出现,每个阶段的简历所涵盖的信息也不一样,简历的内容变动也是你集体和工作的变动。 校招 1 年这个阶段还属于成长期,更须要看重的是你的根底和激情。对于 JS 根底,计算机根底,网络通信,算法等局部的要求会绝对高一些。毕竟这个阶段比拟难考查你的业务我的项目中的积淀,所以只能从根底局部动手考查。 在学校学习,或是利用网络上的各种材料坚固本人的根底,是这个阶段的要害。在简历里用各种形式展现出你对前端的激情,让面试官看到你的后劲。多去理解社区前沿技术,关注国内外的各种技术趋势。尝试本人写一些小我的项目,或者是参加社区开源的我的项目。开始记录本人的技术博客,尝试费曼学习法用输入倒逼你的输出。1 年 - 4 年这个阶段一般来说是向着独当一面的工程师倒退。也是十分要害的一个期间,防止一年的教训用三年。 社区里对于进阶的材料和路线有很多,平时多关注一下,补齐本人的基础知识。平时罕用的框架进阶一步去应用,比方它的一些高级用法是否有所把握,有没有试着去理解它的原理实现。日常的业务开发中不局限于实现性能,是否有去思考我的项目构造如何设计,如何封装根底工具,根底组件如何设计、开发、共享。在日常的业务开发中有没有去思考团队提效的形式,比方:1.接入 eslint、prettier 等代码测验、格调对立的插件。2.工程化的角度思考本地开发的提效,如何去进行 webpack 构建的优化,最近社区 esbuild 很火,尝试去接入一下。vite 和 snowpack 的思路很赞,能不能在新我的项目中使用起来等等……3.平时如果常常有多我的项目开发的需要,整顿出差别和对立的局部,建设团队外部的脚手架防止重复劳动。4.尝试搭建CI / CD 平台,尝试搭建npm 私服保护本人公司外部的通用包。 锤炼你的软技能,沟通合作也是很重要的一项能力。通过思考业务实在需要砍掉多余的需要,协调各个角色一起推动指标,也是高级工程师很重要的技能。4年以上走到这个阶段,可能就往技术专家或者治理的方向后退了。你能够把握某(多)个具体产品或者技术方向的研发工作,独立负责一个复杂度高的我的项目,并冲破其中的关键技术。 你须要具备相当的产品视线和技术深度,须要站在更宏观的角度来看问题,也须要具备肯定的跨团队合作能力;可能制订所负责方向的产品和技术布局,并推动落地,同时在研发效率、品质、资源使用率、产品渗透率等方面有肯定的进步。 如何负责技术调研,是否关注行业前沿趋势,依据不同场景抉择最优的技术计划,能不能有拍板决定的能力和气魄。技术教训是否丰盛,有没有相当的技术储备,参加过的我的项目类型多吗,遇到的艰难都是如何解决,是否有积淀出一套本人的办法?回绝一年的教训重复使用。产品上是否能帮助甚至主导业务指标的制订,并依据业务指标划分工作,指定排期,正当的推动我的项目达到预期成果。是否带过团队,或者是合作过跨团队我的项目,带团队有什么心得,能协调解决团队成员情绪问题吗,成员技能散布不均衡等问题如何解决。如何打造一个有技术气氛的团队,不局限于本人晋升技术,而是帮忙团队独特成长。不同阶段的学习刚毕业校招面试偏重后劲考查。在前端这条路上,学习能力看你是否走得快,学习欲望看你是否走得远。而前端根底是你取得面试机会的资本,而从前端常识掌握情况折射进去的后劲特质,才是你怀才不遇的亮点。这份前端校招面试精编解析文档内容包含了HTML、CSS、前端根底、前端外围、挪动端开发、计算机根底、我的项目、职业倒退及HR面,面试问题和把握的常识都具体写明,没有JS局部,会和另外一份javaScript前端经典面试题一起分享到小伙伴的。 工作1-2年一两年的是要对技术把握更高了,面临的问题也更发的难,这份前端高级工程师面试题精编解析内容包含有HTML、CSS、JS、浏览器、服务端与网络、Vue、算法, 前端校招面试精编解析和前端高级工程师面试题精编解析PDF材料【点击即可获取】,不管你是处于刚毕业或工作了一两年,置信这两份材料会对你有帮忙。 结语全情投入以后所做的事,清晰意识本人在做什么,行将要做什么。每一步都很清晰,如果有一丝含糊,那就停下来,认真思考问问本人。兴许有的人可能感觉本人未来并不会始终从事这个岗位,但请置信这些点滴会连贯你将来的路线。投入以后的酷爱不会对于你未来路线的抉择产生副作用。

July 30, 2021 · 1 min · jiezi

前端知识点总结ES6入门

1.var、let、constES6 推荐在函数中使用 let 定义变量const 用来声明一个常量 (值类似值不能改变,引用类型地址不能改变)let 和 const 只在最近的一个块中(花括号中)有效 //1.let不能重复申明 var n = 10;var n = 100;console.log(n) //100let a=10let a=100console.log(a) // SyntaxError 'a' has already been declared//2.var能改变全局作用域(变量提升) let则不能var b =1{ var b=10}console.log(b) //10let c=1{ let c=10}console.log(c) //1//3.同作用域内不能重申明var d=1let d=2console.log(d) // SyntaxError'd' has already been declaredlet d=1var d=2console.log(d) //SyntaxError 'd' has already been declared//4.var不管作用域对于同个变量赋值则更改var e=1{ let e=2}console.log(e) //1let f=1{ var f=2}console.log(f) //SyntaxError 'f' has already been declared//5.常量不能重新赋值const A = [1,2];A.push = 3;console.log(A); //[1,2,3]A = 10; //Error 这里地址改变了2.箭头函数、thisES6箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。箭头函数背部没有自己的this,this总是指向上一层的this,层层递上,直到找到有自己的this函数为止。ES5函数里的this总是指向函数执行时所在的对象,尤其在非严格模式下,this有时候会指向全局对象。 ...

November 13, 2019 · 3 min · jiezi

关于前端面试每日31

前端面试每日3+1简介有些是聚合平台,大家一起来成就它,而我的使命是要去成就别人,我觉得自己做的事情很伟大,所以我在坚持!就算最后一个人都没有,那我还是要坚持,因为我很固执为自己而活!近些日子,很多人私聊我很多问题,我把这些问题归类整理了下,便形成了“前端面试每日3+1”的介绍。语录整理问:3+1指的是什么? 答:指的是前端的3个必会技能html/css/javascript和一个工作中相关的软技能。问:为什么是3+1? 答:在这千变万化,类库层出不穷的前端,要知道html、css、javascript才是基石!有的时候我们舍近而求远,容易被各种框架所迷惑,要做到不忘初心才能方得始终,+1是加了个技能题,扩展我们的视野(广度)。问:你提到的“每日三问”,指的是哪三问呢? 答:出自于《论语》,曾子曰:“吾日三省吾身”。今天我做计划了吗?今天我学习了吗?今天我思考了吗?问:你为什么要做这个事?你的初衷是什么? 答:好多人都问过我,为什么要做这个事情呢?故事起源于离职同事发来的一道求助面试题,然后在部门企业微信群里炸开了,答题完后大家觉得如果要是每天来一题,是不是会更爽呢?以面代练,突发其想说干就干,所以就有了这个开源仓库,只为利他利己!当时的一股劲,说做就做,没想这么多。现在好好想下,其实不为别的,就算是为了自己吧,坚持去做一件事,哪怕就只有我一个人。问:为什么没有答案? 答:这个问题已经有不下百人问过我,在这我一直都在强调三点: 1.独立思考(勤思考);2.动手去做(多动手);3.坚持学习(能坚持)答案网上一大把,就算是我一下子把上千道题目和答案放在你面前,你未必看得下去,学习是一个思考与积累的过程。我宁愿自己花点时间深入弄懂一个知识点,也不愿意仅仅只是把这几千道题收藏起来!问:有没有人让你提供过答案? 答:有,非常多!有不少朋友上来就是要答案,我都会说没有!问:面试题这么多,网上搜索出来有很多,为何还要一天天发呢? 答:如果我一下子把所有题列出来了,你觉得你还会看吗?就好比一下给你几十G的视频,你觉得会有效果吗?问:你去哪弄的这么多面试题? 答:很多都是工作中遇到的,然后拿出来分享下,当然还有更多是来自广大朋友的力量。所以说开源是大家的,不是我一个人的,取之于民用之于民。问:题目有没有可能出完的一天?出完了怎么办? 答:会,但学习的过程是无止境的。问:你觉得出的题偏难还是简单? 答:我觉得没必要去划分简单和难的界线,只有学与不学。问:看到你的平时提交记录,都是在还没到5点的时候,你究竟是几点起的? 答:4:30问:你不困吗?答:不困问:有没有人质疑过你?答:有啊,有几次我一刚发完题,网友们就在微信上私聊我假装跟我聊天,看我是机器发的还是人工发的,刚开始几次我还好就回复了,但后来我就不回复了,等上班在地铁上时再回复下,因为我不想占用他们的早上的宝贵时间。问:你是如何来得动力? 答:做就要做好,这是一种个性吧。问:你怎么会有这么多时间? 答:早上的时间完完全全属于自己的,那时没有微信、没有电话、没有饭局等的打扰。问:这开源项目未来还要添加什么功能吗? 答:可能会做个网站展示吧,具体怎么做暂时还未考虑这么多。问:你是怎么做推广的? 答:刚开始的时候,我天天在掘金上发,后面被喷了很多次,但我就是这么厚脸皮,既然请不了大v,那就只能天天坚持厚脸皮啰^_^!问:在开源过程中会有反对你的人吗? 答:好多,非常感谢!问:你能自我评价下自己是个什么样的人? 答:非常靠谱问:有和你做类似的事情吗?或者说是竞争对手? 答:这不存在竞争对手一说。但做的过程中发现类似的朋友还是挺多的,都是爱学习的朋友!希望更多的朋友参与进来!像木易杨、刘小夕他们也在为社区贡献,质量都非常高,欢迎大家也关注下(呵呵,我得去收他们的广告费才行,1分也是爱)。问:你这个项目主要针对的是哪些人群呢? 答:web开发的朋友们。问:对于喜欢学习的朋友你有什么建议吗? 答:只要你真的感兴趣,剩下的就只有坚持了。问:听说你非常喜欢打羽毛球 答:这不用听说的,认识我的人都知道这个事情!问:前端里面你觉得公众号做得最好的是哪个? 答:情大的《前端早读课》,他几年前发第一篇的时候我刚好在地铁上,在这几年的时间里,我每天都会看。问:你说你的事业是父亲,怎么说呢? 答:其实生活和工作是息息相通的,作为父亲,是一种责任,对孩子的负责也是对自己的负责。问:对于前端的发展,你怎么看? 答:静下心来学习,以不变应万变。问:你做这个开源项目的目的是什么? 答:没有想过,单纯地想坚持做件事吧。其实这是为了什么呢?挣钱?挣名利?我只觉得别人能做到的,我一定也可以做得到,就是那么要强!问:在开源过程中你学到了什么? 答:学会了包容和取舍。问:在开源过程中,你觉得遇到最印象深刻的是什么? 答:有个网友加我说他通过3+1的深入学习,自己掌握了很多以前不会也没有去想过的知识点,同时也给自己找到了份好工作,最重要的是学会了主动学习。这点令我非常感动,至少有认可的,知足!问:在开源过程中,有没有发生过什么问题? 答:题目有时候会出现类似的(已经尽量避免了,后期准备做个题库管理的工具,加上点人工智能分词,就能分析出题目是否类似了)问:在开源过程中遇到最大的困难是什么? 答:是自己的坚持!刚开始时,会有各种好心的朋友提建议,随着时间的增长也会暴露出问题,比如说端午节去玩时,由于忘带电脑,就只发了issue,没有更新README,朋友们一眼就看出来了。问:为何要纯手工发布而不写个工具做自动化发布呢? 答:怕变成自动化后,我就很少关注这事了。但我后期我会写些工具来辅助,比如说题目的管理等。问:会坚持多久? 答:很久问:如果硬要加个期限呢?答:5年问:别人做的面试题都标有大厂的标签,为何你不标下 答:很多时候,我们都是小人物,也有很多人都跟我一样,并非人人都是BAT出身,每个人都是从新手一步步过来的。问:别人做的面试题都标高级、进阶之类的,为何你不标下 答:标了高级、进阶只是看着好看而已,只有自己学到了才是真货。问:宗旨是什么 答:勤思考,多动手,善总结,能坚持问:给前端人员有什么建议吗? 答:学习方法:集中学习法,分散学习法。学习是个积累的过程,希望大家能每天保持学习,平时的积累,是要深度的,不是只看下题就会了!学习本该孤独的。问:你写的死磕自己,愉悦大家是怎么理解呢? 答:推荐大家去看看罗振宇《罗辑思维》,每天早上6点发布60s语音,这年头敢死磕自己的太少了!

October 16, 2019 · 1 min · jiezi

Vue原理Vue源码阅读总结大会-终

写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Vue源码阅读总结大会 - 终 终于啊终于啊,把 Vue 系列的文章发完了了,如释重负的感jio啊,今天就打算总结下,我这段时间来的历程和收获,本文纯吹水,没有技术含量,各位客官权当娱乐消遣也无谓,来收集个表情包也是可以的 学习源码用时花了3个多月读源码,花了六个月 写文章,花了九个月发文章 耗时如下 从 2018 - 9 - 10 开始读源码 然后从 2018 - 12 - 5 开始写文章 然后 2019 - 6 - 2 写完所有文章 然后 2019 - 8 - 19 发完所有文章(也就是今天) 我不是写了就马上发的,我写完一篇文章之后,要等一段时间之后,再重新审核一遍再发送,这样一来,既可以发现遗漏的错误,也可能可以收获不同的心得 你以为这时间算长的了吗?? 其实如果只用晚上下班回去的时间写的话......写文章估计得用一年......我不仅内容追求简单,可以让我们在以后忘记的时候迅速捡回来,我还要追求排版好看(鳖跟我说难看好不喽,我花了很多心思的哈哈),因为我知道排版难看的文章一秒都不想爱看下去.... 然后我为什么只用半年呢,我.....不好说....哈哈哈 不过也算很长了,历时这么长,真的是非常难熬的,在 坚持和 放弃中 摇摆不定,57 篇文章真不是搞笑的啊,差点崩溃了 幸好给自己定的奖励,一路撑着我走到现在 比如写完这个系列,我打算给自己买双鞋子..... 咳咳,回到正题 阅读源码不难,难的是深度阅读源码 ...

October 14, 2019 · 1 min · jiezi

用CSS新属性实现特殊的图片显示效果

1 概述1.1 前言使用一个或多个图像相关的CSS属性(background-blend-mode, mix-blend-mode, or filter)可以实现许多特殊的图片显示效果。本文转载自Bennett Feely的个人网站,文中共列举了20种图片显示效果。 详细代码及英文原文请访问Bennett Feely的主页。 2 效果列表2.1 铅笔画效果效果示例 SCSS代码.pencil-effect { $url : url(photo.jpg); background-image: $url; background-size: cover; background-position: center; @supports (filter: invert(1)) and (background-blend-mode: difference) { background-image: $url, $url; background-blend-mode: difference; background-position: calc(50% - 1px) calc(50% - 1px), calc(50% + 1px) calc(50% + 1px); filter: brightness(2) invert(1) grayscale(1); box-shadow: inset 0 0 0 1px black; }}查看示例程序 2.2 水彩效果效果示例 SCSS代码.watercolor-effect { $url : url(photo.jpg); background-image: $url; background-size: cover; background-position: center; @supports (filter: blur(2px)) and (mix-blend-mode: multiply) { position: relative; overflow: hidden; &:before, &:after { display: block; content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-size: cover; } &:before { background-image: $url, $url; background-blend-mode: difference; background-position: calc(50% - 1px) calc(50% - 1px), calc(50% + 1px) calc(50% + 1px); filter: brightness(2) invert(1) grayscale(1); box-shadow: inset 0 0 0 1px black; } &:after { background-image: $url; background-position: center; mix-blend-mode: multiply; filter: brightness(1.3) blur(2px) contrast(2); } }}查看示例程序 ...

September 20, 2019 · 5 min · jiezi

剑指offerWEB前端面试直通车

现在程序员大军越来越庞大,行业竞争激烈,面试应聘的难度也提升了不少,一个前端招聘岗位就可能收到几百上千份简历,企业要在这么多人中快速、准确的找出自己需要的人,面试的环节就显得尤为重要。在经历了十几家面试之后,我整理了一些心得体会,也把我自己的一些成功经验跟大家交流分享,希望大家都能找到自己心仪的岗位,实现自己的职业目标和人生价值。 面试细节面试着装面试的时候一定要干净整洁,衣着得体,不能穿的特别随意,或者妆容、打扮特别夸张,即使在你看来这是新潮时尚,也需要分清场合,面试官会觉得这样的人很浮躁、不稳定,即使你技术再好,单就这一点可能也会扣掉一大半的印象分。细节决定成败,面试过程中的每一个环节都不能掉以轻心。 时间观念面试的过程中一定要有时间观念,提前查好出行路线,考虑好途中会不会出现堵车的特殊情况,可以改换成地铁这种比较稳妥的交通工具,最好是按照约定时间提前十五至二十分钟到达面试地点,如果你早到了也不要立马联系工作人员,因为可能上一个面试还没结束,或者打乱别人的工作计划。 面试迟到会给面试官留下非常不好的第一印象,那么之后你就很难翻盘了,除非你真的是遇到了特殊情况,这时你要提前告知面试官,更改时间或者取消面试,迟到或者失约对于面试者和面试官都不是一个好的体验。因为企业会根据时段,安排好人员面试,如果你这边耽搁了或者时间延后就会直接影响之后的面试进度,也有可能影响面试官的工作安排。这在工作中也是很重要的职业素养,同时也反映了一个人的做事原则和对工作的责任心,再严重一点可能还会上升到诚信问题,如果你连这些基本的职场规则还没学会,那么很难争取到一个好的工作机会。 保持通信畅通一定要确保你留在简历上的联系方式是可以随时联系到你本人的,因为企业一般会通过招聘平台或者你的联系电话与你沟通面试事宜,如果hr联系你的时候你的电话无法接通,除非你的条件真的非常优秀,否则很大概率他是不会再联系你第二次了,不要因为漏接电话或者电话欠费这种原因让你失去宝贵的面试机会,而这样的一次机会或许就是改变你命运的一次机会。 面试前的热身对于刚毕业出来找工作的同学来说,可能经验不足,对面试没有什么概念。建议在你投递心仪公司的时候可以先投几家公司做做热身,这个时候不需要有任何的心理包袱,就当是去练练手,所以面试的过程可能会发挥得更顺畅、更自然,说不定这个阶段就会获得offer,并且比你之前想去的那家公司待遇还好,这岂不是意外之喜。 面试总结复盘在面试中我们要打起十二分精神,面试结束后也不能松懈,应该趁着记忆还新鲜,马上把面试题复盘出来,或者在面试的过程中做好录音备份,晚上回家的时候详细的整理出来。多做总结,会对自己有更清晰的认识,即使面试失败也是很宝贵的经验,你需要从中总结出失败的原因,是技术方面的缺失,还是表达的失误。同时也要明确企业在面试的过程中看中的是什么,现在应用的比较多的技术是什么。每一次失败的面试都是为下一次成功的面试做铺垫,通过总结你会更有针对的性的提升自己。 简历简历内容一定要用心制作简历,虽然我只说一遍,但是简历真的非常重要!简历是你向面试官展示自己的第一张名片,简历的好坏也会直接影响你在面试官心中的第一印象,这个一点也不夸张。有工作经验的同学,一定要将自己的优势充分展现出来。如果是没有工作经验的应届毕业生,可以将自己在学校或者实习期间做的项目着重描写一下。不要照搬网上的简历模板,简历应该简洁流畅,每一个元素都是为应聘岗位而生,不要花太多的篇幅描写你在学校学生会的经历、你参加了什么社团、担任过什么班级干部,可以简略的概括,面试官不会因为你在学校当了什么会的干部就对你感兴趣,他只在乎你有参与过哪些开发项目、技术能力如何、能为公司创造什么价值。 简历制作不要从网络上下载装饰过度、花里胡哨的简历模板,尽量选择商务简洁的风格,技术人员的简历要以阅读性为主,重点信息要突出,装饰颜色控制在两种以内,尽量不要选择太有个性的字体,字体数量控制在两种以内。控制好简历的篇幅及排版,尽量占满整个页面,如果一页展示不开可以设计成两页,但是不要有一页只有一两行内容的情况出现,也最好不要超过两页。 简历投递互联网简历投递平台个人推荐Boss、拉勾,一般投递时间为早上9点-10点、下午1:30-3点,这个时段是hr处理简历的时间,最好不要选择周五投递,一般快到周末的时候工作人员都会开始本周工作的收尾。 文件格式一般要准备两份格式的简历:word格式和pdf格式,准备word格式主要是方便公司复制粘贴你的个人信息,pdf格式方便mac电脑打开,同时留给你你设计的空间也更大一些。 文件名称格式为:姓名-求职意向-联系方式,这样方便hr下载好你的简历及时的联系你。 简历编写简历编写中一定要注意的几个问题是: 避免信息缺失:基本的个人信息、联系方式、求职意向一定要写完整、写明确。避免信息错误:不能出现明显的信息错误,比如工作时间、毕业时间、项目起止时间,如果连这些基本的信息都写错,很可能让人对你简历的可信度产生怀疑。错别字问题:这是一个非常低级的错误,一定要对自己简历中的内容来回检查几遍,确保语句通顺,没有错别字,有的时候就是一个小小的错别字让你失去面试的机会,因为会让让别人对你产生做事不认真、不细致的感觉。求职意向一定要写在突出的位置!版头最好放置姓名、联系方式、求职意向这三个最重要的板块,让人一眼就可以注意到,hr每天要处理上百份简历,平均到每一份简历上的时间也就是几秒钟,如果他让他阅读一份花里胡哨、找不出关键信息的简历,那么他可能会直接PASS这份简历。个人基本信息 必填信息:姓名、联系方式、求职意向、年龄/出生年月、毕业院校、专业照片:一定要选择正规证件照,现在拍最美证件照的摄影工作室也很多,比如天真蓝、白海豚、海马体,花上点钱拍一张得体的证件照获得一个宝贵的面试机会,这波不亏,就当是为自己的投资了。就算不放也千万不要选择过度美颜的自拍、生活照、旅游照、非主流大头贴这种奇葩照片,记住你是要去面试找工作的,不是去选美的。现住址(可选):如果你住的离要应聘的公司比较近的话可以写上,因为公司喜欢招聘住在公司附近的人,方便上下班。院校背景 本人是双非二本,自从高考失利后一直没有放弃提升自己,一份漂亮的学历确实能在求职面试的过程中帮你敲开大厂的门。即使没有耀眼的学历,通过努力也可以获得证明自己的机会。 不要再讨论学历重不重要了,在互联网的圈子中,核心是你本身的技术,除非你牛逼到逆天,那啥都不说了,但是大部分都是普通人,学历是一辈子的事情,那些高考能够碾压你的人,进入社会,只要他们愿意,照样能碾压你,你努力,你拼命,别人也不会睡大觉等你,所以,学习是一辈子的事,只要有机会,就要不断提升,你会看到不一样的世界。 工作经历 工作经历按照时间的先后顺序排列,最近的工作写在前头,最好不要出现断档,如果有很明显的断档需要自圆其说,能解释的过去。如果出现长期的断档可能会让hr觉得你能力不行,找工作的周期很长,或者让hr觉得你不稳定,比较爱折腾,进入公司工作一阵子就会离职。 在招聘平台搜索一下你应聘的岗位,了解一下公司对该岗位的招聘需求,hr都是通过关键词去搜索简历,看看出现最多的关键词都有哪些,带入你的工作经历中,适当展开,切记不要只是单纯堆砌和摘抄。 关于跳槽:很多团队很看重人员稳定性,不建议大家频繁换工作,对职业生涯影响很大,如果工作经历很多,可以适当删减,周期短的工作就不必呈现在简历上了。 技能描述 在这个部分可以适当夸张,但是不要过分,吹的天花乱坠,比如你只是使用过一些nodejs的模块,了解一些php语法就在简历上写精通nodejs、php等后端语言,到时候面试官一问就知道你的简历水分有多大了。当你的技术不能达标时,只要你的人品达标,也能为自己加分不少。在面试过程中,用你的真诚和诚信打动面试官,让他觉得你是可塑之才,经过一段时间的锻炼和培养可以很快成长,说不定会给你一个工作机会。但是如果你有太多浮夸的成分,明明是自己不会的技术,还想尽办法在面试官面前展现你有多优秀,会产生适得其反的效果。 关于技能清单和技能关键字可以参考这份技术简历模板: https://github.com/geekcompan... 如果你的简历要投递给有机器(简历分选系统)和不如机器(不懂技术的HR)筛选简历环节的地方,请一定从里边高频关键词中选择5~10个适合你自己的。 项目经历 其实工作经验并不能严格意义上等同于技术水平,有四五年工作年限的人不如刚工作一两年的人这种现象比比皆是,有可能你初入社会,没有工作经验是正常的,但是没有项目经验就是你的问题了,学习技术必须要在项目中实践才可以巩固,网上有海量的资源,大批的开源项目,自己找几个练习项目,把技术点搞清楚,流程理清楚,这不是一件难事。如果连模拟的项目都没有,那怎么证明你的技术能力呢?难道只是在网上看视频么?这样能学得好才怪,更别提找工作了。很多应届的毕业生只是在学校里学了一些理论基础,并没有在项目中实际操作,想着到了公司里再去实践,那样你学到的只能是技巧,还远远达不到技术的水平,技术就是为了解决问题而存在的,多动手才能获得技术,坐等只能浪费时间。 作为前端开发人员,必须要掌握的就是Html5、CSS3、JavaScript这些基础的知识点,你的项目经历中起码要有一个用原生JS编写的PC端网站,证明你对于JS能充分的理解并且使用,有些人觉得原生JS在工作中用的不是特别多,概念又难理解,就算只会使用框架也能够胜任web前端的工作,索性就放弃不学了。在面试过程中JavaScript的部分占了很大的比重,即使工作中使用的频率不高,但是它是前端知识的基础,所有的框架都是基于它来封装的,如果基础不扎实,就没有办法快速学习新知识,在工作中灵活变通。其实面试时,考察这些技能,面试官并不仅仅是考验你的技术,更多的是为了检验你是否真的热爱前端领域,是否对javaScript这门语言有学习的兴趣,是不是对前端技术有求知欲和好奇心,是不是有基本的学习能力和理解能力,这些都是一个开发人员该有的基本素养。 现在市面上有很多的js框架可供选择,而且前端技术发展的很快,说不定马上就有新的框架诞生,我们不可能把所有的都学一遍再来找工作,企业也不是说想招一个全都会的员工,考虑到用人成本和学习成本,只能在招聘的时候通过对基础知识的考查,来看你的基础是否扎实,如果你的JavaScript知识很牢固,那么任何框架对你来说都不是难事,只要花个几天的功夫就可以轻松上手使用,因为他们背后的原理都是相通的,只要掌握了使用方法就可以得心应手。就像学习过C语言的人,再学习Java等语言都是手到擒来的事。在职场上,能力经验到了一定阶段,都不是为了面技术,更多的是为了了解求职者对开发工作的态度,学习理解的深度和沟通的感觉。面试 JavaScript 原生技能,就是这个目的。 目前大部分的前端岗位招聘需求都包括能熟练使用框架,目前比较热门的是vue和react框架,所以针对这两个框架的项目至少一样一个,剩下的可以从当下比较流行的前端技术中选择一个:混合开发、小程序、微信公众号原生JSSDK开发,一般项目的数量控制在4-5个为宜。 自我评价 这个板块主要是针对应届生,有两年以上工作经验的人可以忽略。一定要摒弃之前的套路,写成小作文,或者直接复制粘贴网上的模板,说一些很空的内容,过多的描述你的性格人品、生平履历、兴趣爱好。 在自我评价中,应该将更多的信息呈现留给跟应聘岗位相关的项目经历上,写之前先明确岗位的招聘需求,然后与之一一对应展开,用项目中使用到的技术点证明你的能力符合这个岗位的需求,这样才能引起面试官对你的兴趣,你这个板块也展现了它的价值。 一个比较好的应届生自我评价案例: 大学中系统地学习计算机相关理论基础,大四到公司实习,具有一年的前端开发经验,能快速对接产品需求、前后端工作。对web前端有很大的兴趣并有独立自主学习的能力,具备独立分析和解决问题的能力。业余时间会自主钻研前端技术丰富自己的前端技能栈。代码强迫症患者,注重团队合作,具有良好的沟通能力。 面试问答自我介绍一般面试开始之前面试官都会让你做一下自我介绍,这个过程中主要是考察你的表达能力和临场的应变能力,面试官也是借这个机会迅速的浏览一下你的简历内容,对你有一个大概的了解,拉近与你的距离,打开面试的气氛。 自我介绍是你对整场面试的布局,会直接影响你后面的面试走向,所以自我介绍最重要的功能就是将你的亮点展示给hr,说一些你曾经做过的、符合应聘岗位需求的成功案例,引起他对你的兴趣,让他有进一步了解你的冲动。所以在准备自我介绍前你需要挖掘自己的优势、分析公司的岗位招聘需求,提炼出关键词,了解企业文化,找出自己与之相契合的特质、筛选重组成一份有策略的自我介绍,并将它熟练记忆,控制在1分钟-2分钟,最多不要超过3分钟,不要说与应聘无关的内容。 千万不要只是把简历上的内容复述一遍,这样毫无意义,面试官更想通过自我介绍了解你简历之外的亮点,能让他对你感兴趣。如果在面试的过程中感到紧张,忘记准备好的内容,平时就要多加练习,跟身边的朋友或自己对着镜子,直到可以流利的将自我介绍说出来为止。这个环节的核心要回答你的优势,比如说你掌握的技术和熟练使用的框架,重点就是要让面试官记住你,一定要放松、自然、自信,不要让人感觉你只是在机械的背诵,适当的停顿,时不时的跟面试官有眼神的交流,人在紧张的时候就会有很多下意识的小动作,一定要克制自己不要看天花板,不要眼神飘到别的地方,更不要翻白眼。 自我介绍包含内容: 个人基本介绍:简单罗列你的个人信息即可,如姓名、毕业院校、所学专业、求职意向。工作经历:这个部分主要是针对有相关工作经验的人,可以简单介绍我曾在XXX公司担任XXX一职,主要负责的是XXX内容,最后取得了XXX成果。通过分析企业的招聘需求,用自己具体的工作经验向面试官证明你具备应聘该岗位的能力,主要就是讲我做了什么,并且获得了什么成果,这个环节不用讲的太具体,如果面试官感兴趣会在之后的环节跟你讨论相关细节。切记不要只是堆砌一些形容词如:乐于助人、活泼开朗、勤奋努力,没有具体事例证明就显得毫无根据。个人经历:如果是刚毕业的应届生,没有工作经验,可以说一些自己在学校中比较亮眼的经历,比如参加过哪些计算机相关的比赛,跟随导师参与过哪些开发项目,大四的时候在公司实习,编写过哪些案例,证明你有做好这份工作的潜力和态度。或者说一些自己与众不同的特长,让面试官觉得你是一个充满活力、积极向上的年轻人,公司喜欢这样的新鲜血液加入,来带动团队的工作氛围。从你的这些过往经历中也可以发掘可以匹配工作岗位的特质,有的时候会获得意想不到的效果。说一下你的优缺点这个问题也是一个双刃剑,一定要说自己真正擅长、并且能给公司带来切实利益的方面,不要说的太跑题,比如我很有运动天赋、我会演奏乐器,也不要说的太空,比如我很诚实很勤劳,你可以结合行业属性以及项目经验,比如项目管理、项目推动、专业优势去回答。展现你的综合素质,比如我js基础很扎实,平时喜欢关注前端领域的新技术,遇到新的框架或者没接触过的知识可以很快上手,有很强的学习能力和自我驱动力。 说缺点的时候切记你所叙述的经历不要对眼前的应聘造成不良影响,尽量说一些不会影响到工作的缺点,但是不要把行业的基本素养当成缺点来说,比如我有强迫症,我写代码必须格式要对齐,做技术的人都知道这是前端开发的基本规范,虽然我们知道聪明的面试者会把缺点当成优点来说,但是千万不要聪明反被聪明误,戏太过了就适得其反。人无完人,每个人都会有缺点,说一些别人可以接受的缺点不会给你的面试造成太大影响,尽可以放心、真诚的展示真实的自己。 这个问题没有标准答案,只能结合自己的实际情况进行回答,并且在每次面试后根据面试官当场的反馈及面试结果不断完善,从而找到一个“完美”的答案。 面试中的送命题你为什么离开上家公司?这是一个看似稀松平常的问题,其实特别致命,如果回答得不好很可能之前的所有努力统统白费。马云爸爸对于这个问题曾给过一个一针见血的回答:为什么要离职?要么钱给的不够,要么心受委屈了。道理虽然是这么个道理,但是对于我等屁民以下这些作死的回答一定要避免,即使它就是真实原因:薪资太低、福利待遇太差、经常加班、管理制度太严格;领导及同事太难相处;公司规模太小,没有成长空间; 面试官也是公司员工,你觉得有什么离职原因是他们不知道的?大部分的员工上班一半的时间都在考虑要不要离职。所以面试官主要是想通过这个问题了解下你之前的工作情况,是主动离职,还是被动离职,你的技术和能力能否胜任这份工作,你对工作有没有足够的热情和责任心,是不是遇到压力就会想离职,能不能在一个城市一个岗位稳定发展,还是三天两头就想跳槽。 回答这个问题的时候一定不要表达出自己对上家公司的负面情绪,避免说前东家不好,领导不好,任何负面评价,尽量表现出是自己的原因,而非公司,对上家公司要抱有感恩之心。可以从客观原因出发,比如上班地点离家太远,很多时间都浪费在了通勤的路上,我个人还是希望把更多的时间和精力放在工作上,所以想寻找一份新的工作机会。 大公司or小公司有些面试官会问你怎么看待大公司和小公司,你更青睐哪一种工作机会,其实这也是很多同学比较近纠结的一个点,我们选择工作时有三个关键因素:薪资、平台和成长,在我看来工作的前三年优先级排序是这样的:成长>平台>薪资,很多大公司为了平薪,人员流动不会特别大,薪资待遇不会实时根据市场更新,它需要保证新员工跟之前进入公司的老员工薪资持平,所以薪资方面不会特别有竞争力,但是在你进入到公司之后会给你一段适应期,有技术总监去带你学习,不会让你马上上手写项目,这样你会有更多时间思考和整理,尤其对于工作时间不长的同学来说,这样梳理知识体系的机会非常难得,可以让你学习的东西更深更系统,把学习经验转成实践能力。 并且在大公司遇到优秀同事的概率更大,和优秀的人一起工作会激励你不断向上,你可以在学习和模仿中慢慢进步,和优秀的人共事才会有危机感,学习别人工作、思考的方式,让自己更快的成长,有些改变会让自己受益终身。所以我的建议是,如果有加入大公司工作的机会,一定要好好把握,不要只着眼于当下,将自身的发展放在首位。 一开始的选择是非常重要的,工作的黄金时间稍纵即逝,但是选择的前提是你要有可供选择的机会,如果你都没有机会更何谈选择,当很多机会摆在我们面前时,一定要认真思考什么是我们真正想要的,不要追随别人的脚步,觉得大部人的选择就是对的,我们不能保证每一次选择都是正确的,但是我们能保证不后悔,遇事要冷静,多思考,最后跟着自己的心做决定。这里说的选择不仅仅是选择去哪个公司,从事什么方向,还有与什么样的同事工作,选择什么样的leader,甚至是生活中的事情。 描述项目经历项目经历是我们作为技术人员,简历中最为重要的一个模块,也是企业最为关心和重视的一个部分,通过项目经历可以知道你的工作经验和技术能力是否符合公司的招聘需求。面试过程中有一个绕不开的环节就是让你介绍一下你的项目经历,常见的问法就是请你说一下你最近做过的一个项目,都用到了哪些技术,团队规模多大,人员是怎么分工的,你在项目中担任的角色是什么,最后项目取得了什么样的成果。 面试官没有超能力,他在看你简历的时候是没办法核实你项目的真实性的,这是你做的项目,而且你接手的时间肯定会持续至少三四个月,所以根本无需紧张,你是对于这个项目最了解的人,而面试官只能根据你说的内容作出判断,如果在你的回答中找不出明显的漏洞那就只能算你真的做过。 想要回答好这个模块有几个关键点需要注意一下,首先就是在回答问题的过程中一定要流利,对于你写在简历上的内容一定要倒背如流,如果你在表述的过程中磕磕绊绊,嗯嗯啊啊,那么就会给面试官留下一个非常不好的印象,起码觉得这个人的表述能力有问题,面试是一个考察综合能力的过程,如果你的沟通能力有问题,那么很可能会影响你之后的团队合作。如果对于一些关键点比如项目名称,起止时间,项目中用到的技术点都说错了,那么项目经历的可信度就非常低了,面试官会抓住这些漏洞深究,如果你不能给出合理解释,很可能让面试官觉得你诚信有问题,简历造假,这是最坏的情况,一般这种就直接出局。 另外面试前需要熟悉面试公司的招聘需求,如果该公司明确说了需要react方向的前端人员,你却大谈vue,那么纵使你说的天花乱坠也引不起面试官的兴趣,然后最后面试官问你有没有使用过react,你却说不好意思,没用过,那面试直接结束,这等于浪费双方的时间。所以提前做功课,在叙述的过程中将公司的招聘需求穿插进去,不露痕迹的说一些面试官想听的点,给面试官后续的提问做铺垫,但是这个时候你是在介绍项目,不是在说明亮点,所以不需要详细展开说,一旦你详细说,面试官可能会觉得你啰嗦又拖沓。 比如针对这样一则招聘需求,你在进行项目描述的时候可以说: 我上一个项目是一款移动端的webApp,主要为用户提供影讯查询及在线购票等一站式电影服务,采用vue-cli脚手架搭建开发环境,使用flex弹性盒布局及rem技术自适应适配不同分辨率的移动端设备,数据请求采用axios发送ajax,配合后端人员完成页面数据的读取和加载,最后采用webpack打包上线。接下来面试官会针对你的回答展开问一些技术问题,如果你在描述项目的过程中埋下提前准备好的知识点,面试官很可能会被你带着走,引到你熟悉的技术领域,在有限的时间内回答准备好的问题点,被问到其他问题的几率就少了。如果你没有把握住这个环节就相当于把宝贵的提问权全权交给了面试官,那么你接下来的问答的风险就比较大了。所以在面试前一定要做好充足的准备,你有足够的时间去排兵布阵,而面试官只能在短短的时间内针对你的表现作出反应,所以他要提取出他比较关心的、实际工作中会用到的技术点来验证你的能力,看看你是否真的了解并且实际应用过这些技术,还是仅仅停留在了解概念,在网上查阅了一些资料这个阶段。 在接下来的回答中一定要自信、积极、流利,针对面试官的问题不能只是简单的一句话回应:了解、做过、不知道,这个时候千万不能惜字如金,如果你吝于回答问题,那么面试官也会吝于给你offer或者高薪。针对每一个问题要适当的展开,宁可只说自己熟悉的内容,也不要为了拖时间说一些自己不了解的知识点,因为如果你要是抛出了一个你并不熟悉的概念,面试官很可能会继续提问细节,比如之前面试官问我:请你说一下vue中路由模式,我回答有hash路由和history路由,hash路由会在url地址栏中显示一个"#",如果不想要显示这个"#"可以使用history模式,但是需要后端人员配合我们去做配置,然后面试官就顺口问了:为什么需要后端人员去做配置,后端人员怎么去做配置?而我当时功课没做足,对于这块概念没有准备,所以这部分的风险你要自己承担。 如果你有提前了解过diff算法,就可以在回答:react中一般在哪个生命周期中请求数据?的时候巧妙的引出diff算法和fiber算法,然后在面试官询问关于算法问题时,针对两个算法的原理和异同稍作展开,借机说一下自己平时会关注一些最新、最前沿的技术,会不断深入了解一些框架和技术的底层实现,而不仅仅是停留在使用层面,整个过程就很自然流畅了。时间控制在半分钟内,回答内容根据面试官的反应酌情控制,如果面试官给你了积极的反馈就可以继续展开,如果被面试官打断,就说明这不是面试官想了解的关键点,不是项目必备的技术。 面试官没有义务挖掘你的亮点,一定要自己主动去提出一些自己使用的比较熟练,并且目前比较热门的技术,跟公司的招聘需求对口,在一些开放性的问题中适当的引出,作为自己的加分项。面试官很忙,一定要在最短的时间内充分的展示自己,不要只等着面试官去提问。 你在项目中遇到哪些问题,如何解决?这一块比较抽象,根据你自己的项目来,着重讲你熟悉、有把握的模块,一般面试官都会从中抽取问题来向你提问,看看你对前端技术的掌握程度以及遇到难题时解决问题的能力。回答这类问题,基本原则是:通过失败说成功,不要只强调结果,更要多描述你解决问题的过程,说一下你的收获和成长,同样的"说一次成功的职业经历"也是类似的回答思路。 在面试过程中要保证关键的技术点对答如流,即使过程中被问到了几个不熟悉的知识点也不用慌张,只要如实回答不知道就好了,一定不要含糊其辞,更不能乱说一通,因为前端技术更新很快,不断的推陈出新,我们不能保证将所有的知识都囊括,如果遇到回答错误或者回答不上来的问题要虚心向面试官请教,好的面试官会抛出问题跟你探讨,他们很愿意去帮助新人,无私分享,得到帮助后要记得说:"谢谢,回去之后我会着重把这块知识加强一下,如果公司的项目中需要用到这样的技术点,我会在短时间内学习、运用好"。给面试官留下一个勤学好问的好印象,不要仅仅把它当成一次面试,这更是一次学习和提升自己的机会。整个过程应该是双向的、正面的,有的时候你使用到的一些新技术面试官可能没有了解过,面试官在问求职者的时候,他自己也不见得多精通,可是他就是要面试这类内容。其实,他面试你这类题,并不是希望你多了解,掌握的多好。主要是看你对前沿技术的关注度和对新技术的求知欲。 如果你能将面试当成是一次技术探讨,那就可以更加从容的去应对。很多时候面试官就是技术总监,要不就是你以后一起工作的同事,面试过程中给你传递出来的感觉非常重要,很可能就决定了以后工作的氛围和模式,对于你之后选择公司、工作环境和工作伙伴提供了一个很有价值的参考。 对于Web前端来说,是一个更新特别快的行业,几乎每年都有不少新的技术,作为一个Web前端开发人员,如果对新技术不敏感,对新技术没有学习的欲望,那么可能很快会被行业淘汰。那么,企业招这样的求职者有什么用?所以技术面试中一定要凸显出自己有很强的求知欲,对新技术是非常感兴趣且愿意去不断学习,公司一般都不会拒绝爱学习的人。这一点对于应届毕业生或者没有相关工作经验的人来说尤为重要,这个时候面试官看中的不是你的技术掌握的如何,而是你有没有发展的潜力,他会更想了解你的软实力,比如你的沟通能力、处事能力、学习能力、解决问题的能力,这些都是在面试过程中通过和你的聊天一点一点去发掘的,所以如果你的技术不占优势,你就要抓住机会向面试官展示你这方面的软实力。 但是如果你的回答中出现了明显的技术漏洞,比如你说熟练使用vue框架却连vuex的流程或者vue的生命周期函数这种基础性概念都回答错误,这时候就比较危险了,面试官会直接怀疑你这个项目的真实性,会通过更多问题确认你的技术能力,到底是技术能力差还是框架根本就没使用过,不会让你在面试中企图蒙混过关。 ...

September 10, 2019 · 1 min · jiezi

前端这些年我到底经历了什么上

正文前端路漫漫,吾将上下而求索。故事应该从 2011 年说起,那时我刚上大学,读的是软件工程专业。 那时大学里这种专业的课除了数学和英语外,基本上都是些计算机语言的课程,比如《C#语言程序设计基础》、《面向对象程序设计》等。 说实话可能骨子里就是做前端的命吧(虽然当时并不知道前端是什么),我对这些后台编程语言并不感兴趣。 因此大一大二过去了,我对自己的人生毫无规划可言,对自己将来毕业后能做什么也是一片迷茫,基本上这两年除了在学生组织里混迹外也别无是处了。 到 2013 年的时候情况突然发生了转变,可能上大三了吧(比较闲),更想通过课余时间来赚点钱,和其他找兼职的同学不一样的是,我开始接触到了“网赚”,百度搜索“用电脑赚钱”的时候很容易就被各种广告和推广给吸引了。 那时还付费买了课程和资料学习,虽然基本没有赚到钱吧,但是不得不说我从课程里开始学会了如何建站(当时的大部分网站都是 php 写的)以及做 SEO,开始学用 WordPress 搭建博客,用 Discuz 搭建论坛,因此也购买了服务器申请了好几个域名,感觉那时能有一个属于自己的博客是种很 Nice 的体验。 当然当用惯了各种 WordPress 的模版后也就腻了,想玩出自己的花样来,于是就开始改它的源码,这时候我才开始接触 HTML 和 CSS,当时感觉用 CSS 写一个动态效果(还称不上动画)是件很牛逼的事情。 为了能尽快打造出令我满意的个人博客,我开始借助学校图书馆学习相关的技术,我还清楚的记得我借的第一本前端的书籍是李刚的《疯狂 HTML + CSS + JavaScript》,很厚的一本书。 那时候图书馆里称得上前端的书籍大多是什么《网页设计与网站建设从入门到精通》、《网页制作与网站建设实战大全》等,还有一本比较经典的就是 《锋利的 jQuery》,现在京东上还有的卖。 就是这些书伴我度过了大三和大四上学期。不管上什么课,我都会占据教室的后排位置(最佳打酱油位置)摊一本前端的书在那边看。因此我大学的毕业设计也是和前端相关的一个个人博客系统的搭建,主要亮点就在于博客前端部分的各种动画和样式。 其实当时毕业设计偏前端的估计寥寥无几吧,答辩评审老师他们也无从问答,毕竟学校里就没有专业的前端老师,索性他们发现了我的兴趣所在,也便让我过了,这也得益于我找到了自己的第一份实习工作。 我大四实习是在一家规模 100 人左右的网络公司,住的是 4 人宿舍,工资很低,2000 一个月,但是发的是现金,因此每到发工资的时候拿到一叠毛爷爷心里也是美滋滋的。因为是实习,当时面试我的前端主要看重了我很强的学习能力和在这方面的兴趣,对经验要求也没有太高。 虽然在这家公司实习仅仅干了3个多月(从 2014 年底到 2015 年初),但是很充实,很有激情。每天晚上在宿舍和其他几个实习伙伴在一起都能畅谈技术和人生,周六周日也都会去公司主动加班或学习。 那时候,公司前端的主要任务就是用 HTML 和 CSS(用的是 Kendo UI 和 less) 画页面,处理各种浏览器的兼容性问题,JS 对于我一个实习生来说基本接触不到,大多都是后台负责写的(基本都是 jQuery)。 离开公司的主要原因还是希望自己能趁着年轻气盛去大公司瞧瞧,因此我离职那天还给组长发了封邮件,以感谢她的悉心栽培和指导。 此后,我便开始向我期望的公司和目标迈进,此时我简历中的写的技能是这样的: ...

September 9, 2019 · 1 min · jiezi

Vue原理Diff-白话版

写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Diff - 白话版 终于到了最后一块内容了!今天我们就来简单概括一下 Diff,内容一点都不多哦,全是图片 Diff 作为 Vue 比较重要的一部分内容,还是非常有必要深入了解的 此篇文章就会分几块内容进行简单阐述,不会出现任何的源码,只是为了帮助大家建立一种思路,了解下 Diff 的大概内容 1、Diff 的作用2、Diff 的做法3、Diff 的比较逻辑4、简单的例子下面就开始我们的正文 Diff 作用Diff 的出现,就会为了减少更新量,找到最小差异部分DOM,只更新差异部分DOM就好了 这样消耗就会小一些 数据变化一下,没必要把其他没有涉及的没有变化的DOM 也替换了 Diff 做法Vue 只会对新旧节点中 父节点是相同节点 的 那一层子节点 进行比较 也可以说成是 只有两个新旧节点是相同节点的时候,才会去比较他们各自的子节点 最大的根节点一开始可以直接比较 这也叫做 同层级比较,并不需要递归,虽然好像降低了一些复用性,也是为了避免过度优化,是一种很高效的 Diff 算法 新旧节点是什么所有的 新旧节点 指的都是 Vnode 节点,Vue 只会比较 Vnode 节点,而不是比较 DOM 因为 Vnode 是 JS 对象,不受平台限制,所以以它作为比较基础,代码逻辑后期不需要改动 拿到比较结果后,根据不同平台调用相应的方法进行处理就好了 想了解 Vnode 更多信息可以转到这篇文章 VNode - 源码版 ...

September 9, 2019 · 2 min · jiezi

Vue实战如何实现商品评价栏目14

这篇我们来实现商品评价栏目。 完成评分组件的结构: 我们先来设置一个ratings容器,还是熟悉的老情况,ratings-wrapper的高度可能会超过ratings,这时候我们肯定会让ratings内出现滚动条的,ref也是老朋友了,配合Bscroll实现ratings-wrapper的滚动。 接着我们通过overview来构建商家评分内容。 最后评论的内容content部分,我们通过点击全部,有图,点评,来显示不同的内容,content这个部分就是我们经常遇到的俗称选项卡。 <div class="ratings" ref="ratingView"> <div class="ratings-wrapper"> <div class="overview"> <div class="overview-left"> <div class="comment-score"> <p class="score">{{ratings.comment_score}}</p> <p class="text">商家评分</p> </div> <div class="other-score"> <div class="quality-score item"> <span class="text">口味</span> <span class="score">{{ratings.quality_score}}</span> </div> <div class="pack-score item"> <span class="text">包装</span> <span class="score">{{ratings.pack_score}}</span> </div> </div> </div> <div class="overview-right"> <div class="delivery-score"> <p class="score">{{ratings.delivery_score}}</p> <p class="text">配送评分</p> </div> </div> </div> <div class="content"> <div class="rating-select" v-if="ratings.tab"> <span class="item" @click="selectTypeFn(2)" :class="{'active':selectType==2}" >{{ratings.tab[0].comment_score_title}}</span> <span class="item" @click="selectTypeFn(1)" :class="{'active':selectType==1}" >{{ratings.tab[1].comment_score_title}}</span> <span class="item" @click="selectTypeFn(0)" :class="{'active':selectType==0}"> <img src="./icon_sub_tab_dp_normal@2x.png" v-show="selectType!=0"> <img src="./icon_sub_tab_dp_highlighted@2x.png" v-show="selectType==0"> {{ratings.tab[2].comment_score_title}} </span> </div> <div class="labels-view"> <span v-for="item in ratings.labels" class="item" :class="{'highligh':item.label_star>0}" >{{item.content}}{{item.label_count}}</span> </div> <ul class="rating-list"> <li v-for="comment in selectComments" class="comment-item"> <div class="comment-header"> <img :src="comment.user_pic_url" v-if="comment.user_pic_url"> <img src="./anonymity.png" v-if="!comment.user_pic_url"> </div> <div class="comment-main"> <div class="user">{{comment.user_name}}</div> <div class="time">{{fotmatDate(comment.comment_time)}}</div> <div class="star-wrapper"> <span class="text">评分</span> </div> <div class="c_content" v-html="commentStr(comment.comment)"></div> <div class="img-wrapper" v-if="comment.comment_pics.length"> <img v-for="item in comment.comment_pics" :src="item.thumbnail_url"> </div> </div> </li> </ul> </div> </div> </div></template>获取评分数据 ...

September 8, 2019 · 5 min · jiezi

一起来聊一下-JavaScript-的用途和那些特性

JavaScript 简介我们一起来聊一下 JavaScript,用它能做什么,它有哪些特性,以及一些跟它配合使用的技术。 什么是 JavaScript?JavaScript 最初的目的是为了“赋予网页生命”。 这种编程语言我们称之为脚本。它们可以写在 HTML 中,在页面加载的时候会自动执行。 脚本作为纯文本存在和执行。它们不需要特殊的准备或编译即可运行。 这方面,JavaScript 和 Java 有很大的区别。 为什么叫 <u>Java</u>Script?JavaScript 在刚诞生的时候,它的名字叫 “LiveScript”。但是因为当时 Java 很流行,所以决定将一种新语言定位为 Java 的“弟弟”会有助于它的流行。 随着 JavaScript 的发展,它已经变成了一门独立的语言,同时也有了自己的语言规范 ECMAScript。现在,它和 Java 之间没有任何关系。 现在,JavaScript 不仅仅是在浏览器内执行,也可以在服务端执行,甚至还能在任意搭载了 JavaScript 引擎 的设备中都可以执行。 浏览器中嵌入了 JavaScript 引擎,有时也称作 JavaScript 虚拟机。 不同的引擎有不同的“代号”,例如: V8) —— Chrome 和 Opera 中的 JavaScript 引擎。SpiderMonkey —— Firefox 中的 JavaScript 引擎。……还有其他一些代号,像“Trident”,“Chakra”用于不同版本的 IE,“ChakraCore”用于 Microsoft Edge,“Nitro”和“SquirrelFish”用于 Safari,等等。上面这些名称很容易记忆,因为经常出现在网上开发者的文章中。我们也会用到这些名称。例如:某个新的功能,如果“JavaScript 引擎 V8 是支持的”,那么我们可以认为这个功能大概能在 Chrome 和 Opera 中正常运行。 引擎是如何工作的? 引擎很复杂,但是基本原理很简单。 引擎(通常嵌入在浏览器中)读取(“解析”)脚本。然后将脚本转化(“编译”)为机器语言。然后这机器语言代码快速地运行。引擎会对流程中的每个阶段都进行优化。它甚至可以在运行时监视编译的脚本,分析数据流并根据这些对机器代码应用优化。最后,脚本会执行地非常快。 ...

September 7, 2019 · 1 min · jiezi

JS的callapply与bind详解及其模拟实现

call, apply 与 bind1.call() 与 apply()call或apply会自动执行对应的函数 fun.call(thisNew[, arg1[, arg2[, ...]]])fun.apply(thisNew[, argsArray])thisNew: fun函数运行时指定的this值,可能的值为: 不传,或者传null,undefined, this指向window对象传递另一个函数的函数名fun2,this指向函数fun2的引用值为原始值(数字,字符串,布尔值),this会指向该原始值的自动包装对象,如 String、Number、Boolean传递一个对象,函数中的this指向这个对象用例: call: window.name = 'windowName'var obj = { name: 'objName'}function getName(p1, p2) { console.log('name === ', name) console.log('p1 === ', p1) console.log('p2 === ', p2)}getName('str1', 'str2')getName.call(obj, 'str1', 'str2')apply: Math.max.apply(null, [2, 3, 1, 4])2.bind()bind()方法会创建一个新函数,称为绑定函数。bind是ES5新增的一个方法,不会执行对应的函数,而是返回对绑定函数的引用。 fun.bind(thisNew[, arg1[, arg2[, ...]]]);用例: var $ = document.querySelectorAll.bind(document)3.三者异同相同: 改变函数体内 this 的指向不同: call、apply的区别:接受参数的方式不一样bind不立即执行。而apply、call 立即执行4.模拟实现call: Function.prototype.customCall = function () { if (typeof this !== 'function') { throw new TypeError('error!') } let context = arguments[0] || window context.fn = this let args = [...arguments].slice(1) let result = context.fn(...args) delete context.fn return result}apply: ...

August 28, 2019 · 1 min · jiezi

学Node必须掌握的Buffer和Stream

本文并不介绍 Buffer 和 Stream 使用的api,而是把对 Buffer 和 Stream 的理解带给大家。 之前发了篇文章《Nodejs核心模块简介》,笼统的介绍了下 Events模块、fs模块、stream的使用、http模块。 文章也在我的 github 博客上,欢迎订阅。 因为想学好 node 这些东西几乎是必须掌握的。这篇文章来说一下在 node 中几乎无处不在的 Buffer 和 Stream,什么是 Buffer 以及它和 Stream 到底什么关系? 马上揭晓。 BufferBuffer 是个类数组的对象,可以把它当做数组更好理解些,只不过里面存的是二进制数据。 先创建个 buffer 来看看它打印出来的样子: const str = 'hello';const buf = Buffer.from(str);console.log(buf); // <Buffer 68 65 6c 6c 6f>buf 里装的数据是字符串 hello,而 buf 的长度为 5 ,hello 的长度也是 5,所以 Buffer 中每个元素占一个字节(英文每个字母是一个字节)。 Buffer 是什么从代码使用来看,Buffer 是类数组对象。从内存角度看,Buffer 是在内存中开辟的一块区域。 Buffer 翻译过来是缓冲器,它主要用来暂存数据。 为了更好理解,用大白话把上面哪句翻译一下:Buffer 就是我们常坐的公交车,人就是数据,人上车就表示在 Buffer 中输入数据, 到站了人就下车,Buffer 里的数据就会输出 ...

August 20, 2019 · 1 min · jiezi

JavaScript匹配elective后的数字输出

一、问题Url 有以下三种情况: var url_1 = 'https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=&local_province_id=33'; var url_2 = 'https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800&local_province_id=33'; var url_3 = 'https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800,700&local_province_id=33';匹配 elective 后的数字输出(写出你认为的最优解法): [] || ['800'] || ['800','700']二、答案答题可以考虑下以下几点: 效率高;可以扩展换 Url,换字段;elective 是跟在一堆空值后面,要效率较高的排除掉前面的匹配;匹配完 elective 的值之后, & 后面的匹配需要立刻停止,减少性能消耗;第三个的 Url 中带了 ,,也要考虑其他符号的可能性。2.1 方案一function getUrlValue(url){ if(!url) return; // let res = url.match(/(?<=elective=)(\d+(,\d+)*)/); // let res = /(?<=elective=)(\d+(.\d)*)/g.exec(url); let res = url.match(/(?<=elective=)(\d+(,\d+)*)/); return res ? res[0].split(',') : [];}其中:这个正则表达式 <=是零宽度断言的写法,断言 elective=有无内容,是匹配elective=的字符的,(?<=elective=) 是指匹配以elective=开头的字符串;(\d+(.\d)*)指匹配数字开头,可能不定数量逗号分隔后是数字的字符串。 2.2 方案二function getQueryFromUrl(key, url) { const matches = url.match(new RegExp(`(\\?|&)${key}=([^&]*)(&|$)`)); return !matches || matches.length <= 0 ? [] : (matches[2] ? matches[2].split(',') : []);}getQueryFromUrl('elective' , url_1)2.3 方案三IE 不支持。 ...

July 16, 2019 · 1 min · jiezi

一段代码带你理解js执行上下文的工作流程

原文链接,欢迎关注我的博客 我相信很多前端初学者一开始都会被执行上下文这个概念弄晕,或者说似懂非懂。对于工作两年的我来说,说来实在惭愧,虽然知道它大概是什么,但总觉得没有一个更为清晰的认识(无法把它的工作过程描述清楚),因此最近特意温习了一遍,写下了这篇文章 执行上下文要说清它的大体工作流程,需要提前说明三个基本概念,分别是thread of exection(线程)、variable envirnoment(变量环境)、call Stack(调用栈),这些概念我们或多或少接触过,接下来我会通过一段示例代码,和一系列图片,进一步解释这三个概念在执行上下文的运作流程。 一段代码const num = 2;function addOne(input) { const output = input + 1; return output;}const result = addOne(2);这段代码做了什么在运行上面这些代码前,js 引擎做的第一件是就是创建一个global execution context,也就是全局执行上下文: 先看图中的黑色箭头,它表示线程thread的执行顺序,众所周知 js 是单线程的,它会一行行、从上往下去执行代码;而右边的global memory,它用于存储当前上下文中的数据,由于线程目前处于全局上下文环境,故加了个global的前缀。 在这段代码中,第一行我们声明了一个名为num的不可变变量,并赋值为4, 因此global memory中就会分配内存,存储这个变量: 接着继续,当线程执行到第二行时,问题就来了:我们创建了一个addOne的变量,并把一个函数赋值于它,那在global memory里,到底存的是个啥?为了解答这个问题,我特意打印了一下: function addOne(input) { const output = input + 1; return output;}console.log(addOne);看,我们竟然把函数里的内容完完整整打印出来了,很明显,它存的是一个函数内部的“文本信息”。 其实很容易理解,当执行第二行的时候,该函数并没有被调用,因此线程不会立刻解析里面的内容,而是把它内部的信息以“文本内容”的形式保存下来,当需要执行的时候,才去解析变量里的函数内容,这也很好地解析了为什么函数内的异常仅会在函数被调用时才抛出来。 因此这时global execution context长这样: 由于addOne里保存的是函数内容,目前对于线程而言它是未知的,因此我们这里特意用一个带有输入输出箭头的函数图标,代表它是一个未被解析的函数。 我们继续执行第三步:还是创建了一个变量result,但此时它被赋予undefined,因为线程暂时无法从addOne这个函数里获知它的返回值。 由于addOne函数被调用了,线程会从刚刚保存的addOne变量中取出内容,去解析、执行它。这时 js 就创建了一个新的执行上下文——local execution context,即当前的执行上下文,这是一个船新的上下文,因此我特意用一个新图片去描述它: 首先这个memory我加了个local前缀,表面当前存储的都是此上下文中的变量数据。无论是上述的global memory,亦或是现在、或未来的local memory,我们可以用一个更为专业的术语variable envirnoment去描述这种存储环境。 此外,这个黑箭头我特意画了个拐角,意味它是从全局上下文进来的,local memory首先会分配内存给变量input,它在调用时就被2赋值了,紧接着又创建了一个output标签并把计算结果3赋值给它。最后,当线程遇到离开上下文的标识——return,便离开上下文,并把ouput的结果一并返回出去。 此时,这个上下文就没用了(被执行完了),于是乎垃圾回收便盯上了它,选择一个恰当的时机把里面的local memory删光光。 ...

July 13, 2019 · 1 min · jiezi

Vue原理Event-白话版

写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Event - 白话版 Vue 事件是我最感兴趣的东西之一,一直想研究玩玩 特别是组件自定义事件,很想知道,给子组件绑定自定义事件,子组件是怎么触发的 巴拉巴拉的 开始正文了 在 Vue 中,事件大概分为 4 种 1、自定义事件 2、DOM 事件 3、组件DOM 事件 4、组件自定义事件 然后再细分,就只有两种 1、自定义事件 2、DOM 事件 下面就来粗略说一下事件 自定义事件自定义事件 是使用观察者模式建立起来的一种事件机制 分为 个人使用 和 组件使用 自定义事件主要由下面两部分构成 1、有事件存储器 2、绑定事件,触发事件,解绑事件三个函数 在 Vue 中,每个实例都会添加一个属性_events,用来存放本实例上注册的自定义事件 _events 就是 事件存储器,是一个对象 属性名是 事件名,属性值是事件回调 个人调用自定义事件我也经常在项目中使用到 自定义事件,像下面这样 没错,$on 就是注册事件,$emit 是 触发事件,$off 就是 解绑事件 在哪个实例上注册的事件,事件就属于哪个实例,正常情况下,你是不可能能触发别的实例上的事件的 而给组件绑定自定义事件 是怎么样的呢? 结果也是一样的,前面的解析处理可以不管,最后同样是使用内置的 $on 方法去注册事件 ...

July 10, 2019 · 1 min · jiezi

Vue原理Component-白话版

写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】Component - 白话版 component 从模板上使用到挂载到页面上,到底经历了一个怎么样的流程??里面到底掺杂了什么神奇的东西,母猪为何半夜惨叫,这一切的背后,究竟是.... component 从模板上使用到挂载到页面上,到底经历了一个怎么样的流程??里面到底掺杂了什么神奇的东西,母猪为何半夜惨叫,这一切的背后,究竟是.... 好吧,马上进入主题,component 挂载流程 好了,既然说的是 component,那么其他的无关步骤自然是要略过的 总的说起来,component 创建流程,就两个步骤 1、创建 component 外壳VNode2、挂载 component dom我们一步一步来说 创建组件vnode“这里说的组件vnode,是外壳vnode,不懂下面会说” 现在有一个页面A 使用是了 test 组件 然后页面被解析成了一个渲染函数 现在要开始执行页面A渲染函数,这个渲染函数执行得到 【模板对应的 VNode】 其中 _c 的作用就是,根据传入的参数,构造相应的 VNode 执行到 _c('test'),需要构建一个标签为 test 的 vnode,但是发现,诶?test 不是一个正常的 html 标签啊 于是送去非正常标签研究院进行研究 ,哈哈,就是去做一些特殊处理 做的是什么呢? 1、构建组件的构造函数,处理父组件给子组件绑定的数据,比如 props,事件,slot 等等 2、创建组件外壳VNode,就是下面这个 相信大家应该清楚什么是外壳节点了,细节可以跳到下文相关内容看 VNode - 源码版 ...

July 8, 2019 · 1 min · jiezi

JavaScript深入浅出第3课什么是垃圾回收算法

摘要: JS是如何回收内存的? 《JavaScript深入浅出》系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼?JavaScript深入浅出第2课:函数是一等公民是什么意思呢?JavaScript深入浅出第3课:什么是垃圾回收算法?最近垃圾回收这个话题非常火,大家不能随随便便的扔垃圾了,还得先分类,这样方便对垃圾进行回收再利用。 其实,对于写代码来说,也有垃圾回收(garbage collection)这个问题,这里所说的垃圾,指的是程序中不再需要的内存空间,垃圾回收指的是回收这些不再需要的内存空间,让程序可以重新利用这些释放的内存空间。 手动管理内存对于C这种底层语言来说,我们可以使用malloc()函数分配内存空间,当所分配的内存不再需要的时候,可以使用free()函数来释放内存空间。 #include <stdio.h>#include <stdlib.h>#define TRUE 1int main (){ int *p, i, n, sum; while (TRUE) { printf ("请输入数组长度: "); scanf ("%d", &n); p = (int *) malloc (n * sizeof (int)); // 分配内存空间 sum = 0; for (i = 0; i < n; ++i) { *(p + i) = i + 1; sum += *(p + i); } printf ("sum = %d\n", sum); free (p); // 释放内存空间 } return 0;}示例代码很简单,输入一个整数n,程序计算1、2、3...n的和。大家可以在Online C Compiler上运行这段代码。 ...

July 3, 2019 · 1 min · jiezi

阿里云前端技术周刊第十一期

作者:亦才 校对:染陌 知乎:阿里云中台前端/全栈团队专栏 Github:阿里云前端技术周刊 给我们投稿:传送门 参与交流:传送门 前端速报 npm已落伍,下一代包管理器Tink正在孵化, 了解一下想了解 TypeScript 在淘宝的实践,可以看看这个阿里圆心:前端路上的思考,为你解惑未来的前端趋势,了解一下为你精选蚂蚁开源TOP 4 的博客介绍,想随时了解最新动态的,可以收藏下,点击了解更多趣前端 overscroll-behavior 滚动溢出 css 草案发布,可解决父子容器滚动条联动问题,点击了解详情Chrome 76 Beta 版功能尝鲜:dark 模式、轻松安装 PWA、隐身模式难检测,详情2019 年 13 大 GraphQL 工具和库,点击了解详情来自对 Optional chaining JS 特性草案的完整解读,可以好好学习下React Hooks 源码浅析,让你了解 hook 的本质,赶紧来看看Flutter 知识点科普,让你快速了解它的功能,来看看吧编者推荐 微前端的那些事儿 想认真的了解微前端,可以看看这个!想动手开始搞微前端,可以看看这个!想给别人吹吹微前端,可以看看这个! 马蜂窝容器化平台前端赋能实践 本文将结合马蜂窝容器化平台赋能前端应用构建的实践经验,介绍整个平台背后的设计和实现原理、取得的一些效果及问题的优化方案,同时可以学习下,Docker+Kubernetes的工程化实践。 厂内动态 UI2CODE闲鱼基于图片生成跨端代码 来自 闲鱼团队在 GIAC2019 上的演讲 ,讲述他们在UI2Code的一些实践。 MNN - 端侧推理引擎面临的挑战与应对 淘宝无线开发专家——陈以鎏(离青)在 GMTC 全球大前端技术大会为大家分享了 MNN 开发、开源中的思考与总结,通过淘宝在移动AI 上的实践经验,你将会了解移动 AI 的发展状况和应用场景,以及通过端侧推理引擎了解移动/IoT深度优化策略。 关于我们我们是阿里云智能中台体验技术团队。详情 如有兴趣加入我们,简历/沟通请至:chuck.ql@alibaba-inc.com

July 1, 2019 · 1 min · jiezi

阿里云前端技术周刊第十期

作者:@南逸(chuck.ql))校对:@染陌(ranmo.cy)) 知乎:阿里云中台前端/全栈团队专栏Github:阿里云前端技术周刊 给我们投稿:传送门参与交流:传送门 前端速报 Jetbrains,发布了2019年开发者报告,可以去看看有多少人跟你习惯一样;了解一下Apple 作为白金终端用户成员加入 CNCF,对此内容感兴趣的朋友可参考 Apple Join CNCF 的官方说明;github 新功能,使用存储库模板生成新存储库, github.blogumijs发布2.8版本,支持 SSR 和 prerender,让SSR变得更简单;[]()了解一下 趣前端 更优雅地基于 canvas 在前端画海报,https://juejin.im/post/5d087c0d6fb9a07eda031959推荐一个css渐变工具,通过颜色节点、角度以及颜色比例,来生成渐变效果代码,工具做的比较小清新;戳我看看 编者推荐  Hillhouse Captial 发布2019中国互联网趋势报告;下载附件:hhcn2019.pdf用JS开发跨平台桌面应用,从原理到实践,https://mp.weixin.qq.com/s/4WaUM8iJoEYgrI_HpC5MOQ;github不仅可以同性交友,还可以看民间故事,这里搜集了各类民间故事;ES6正式支持Promise之后,Event Loop跟之前有些不一样,本文从 Promise 对象出发讲解Event Loop,文章图文并茂,写的非常不错;戳我阅读 附赠两个正在标准化审核的api的讲解:Promise.allSettled、Promise.any;JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行; 那什么时候应该使用Web Worker,看完这篇文章你或许就有答案了; 厂内动态 《蚂蚁金服的前端框架和工程化实践》本文为在 GMTC 2019 上分享的文字稿,介绍蚂蚁金服前端框架是怎么一步一步演变而来,以后对未来的一些规划; 跨界碰撞 一个高质量的设计资源网站,所有资源免费可商用,包括插画、图标、UI Kits 等 300 套资源;Interfacer - 300+ free design resources 关于我们我们是阿里云智能中台体验技术团队。详情 如有兴趣加入我们,简历/沟通请至:chuck.ql@alibaba-inc.com

June 30, 2019 · 1 min · jiezi

Vue原理看Vue源码不会调试不行啊

写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧 【Vue原理】学会调试Vue源码 调试是程序猿必备的技能,如果你不会调试,你的下场就是......... 嗯,一样可以拿高工资............ 不过据我了解,连张鑫旭大佬都喜欢使用 console.log 调试,但是你以为别人不用,你就以为别人不会吗,你真的太天真了.... 下面的评论也是...看来同是天涯沦落人 我在项目中也是使用 console.log 调试啊,但是阅读源码不一样啊,你试试一直用 console.log 调试,搞不死你 好了,进入正题.... 进入VSCode调试界面是是是,让我们把眼睛移动到 VSCODE 左边活动栏 这边 1、有个小虫 ,点击进入调试界面 2、或者按快捷键, ctrl+shift+D 错!其实第一步你应该打开 VSCode 创建调试配置文件点击这个小设置按钮 之后,会弹窗,让你选择调试的类型,我们选择 Chrome ,骚年 Duang 的一声,你会发现自动生成了一个配置文件 然后这一步你就成功了呗....到下一步了 配置调试配置文件配置文件有很多选项,我只给出最简单的可以使用的版本 { "version": "0.2.0", "configurations": [ { "type": "chrome", "request": "launch", "name": "调试 Vue 的调用走向", "file": "${workspaceRoot}/index.html", } ]}解释一下 ( • • )✧ ...

June 27, 2019 · 2 min · jiezi

监控微信小程序中的慢HTTP请求

摘要: 请求时间太长,影响用户体验,使用 Fundebug 监控慢请求。 Fundebug 的微信小程序监控插件在 0.5.0 版本已经支持监控 HTTP 请求错误,在小程序中通过wx.request发起 HTTP 请求,如果请求失败,会被捕获并上报。时隔一年,微信小程序插件已经更新到 1.3.1, 而且提供了一个非常有用的功能,支持监控 HTTP 慢请求。对于轻量级的性能分析,可以说已经够用。 本文我们以一个天气微信小程序为例(由bodekjan开发),来演示如何监控慢请求。bmap-wx.js中的weather()函数调用百度地图小程序 api 提供的接口来获取天气预报信息。 接入监控由于使用百度的 api,我们无法确认该接口的稳定性,可能有时候会特别慢,导致天气信息显示不出来。于是,我们使用 Fundebug 来监控请求过慢的情况。接下来,我们来演示如何监控慢请求。注册账户后,记得要在创建项目是选择“微信小程序”这一项目类型。 根据指示完成接入流程: 在app.js顶部加入下面的代码(记得将 apikey 替换成你自己的): var fundebug = require("./utils/fundebug.1.3.1.min.js");fundebug.init({ apikey: "YOUR-API-KEY", monitorMethodCall: true, monitorMethodArguments: true, monitorHttpData: true, setSystemInfo: true, setUserInfo: true, setLocation: true, httpTimeout: 200});虽然init()函数只要设置apikey即可使用,但是为了最大程度发挥监控的威力,我们不妨多设置一些监控选项。微信小程序插件有很多的可配置项,由于涉及到数据,默认处于关闭状态。我们可以监控函数调用(monitorMethodCall),以及函数调用的参数(monitorMethodArguments),监控 HTTP 请求的 Body 中的数据(monitorHttpData),获取系统信息(setSystemInfo)、用户信息(setUserInfo)、地理位置(setLocation)。 监控慢请求最后,最重要的一步,配置httpTimeout来监控超过特定时长的请求,httpTimeout 类型为 Number,单位为毫秒(ms)。演示起见,我们将时间设置为 200 毫秒。 在微信开发者工具内运行代码,Fundebug 立马收到报错。小程序发往https://api.map.baidu.com/telematics/v3/weather接口的请求时长为 571ms,超过预设时间 200ms。 错误详情该请求返回代码 200,表明能够正常获取数据。点击该条错误,查看错误详情: ...

June 27, 2019 · 1 min · jiezi

前端架构师亲述前端工程师成长之路的-N-问-及-回答

问题回答者:黄轶,目前就职于 Zoom 公司担任前端架构师,曾就职于滴滴和百度,毕业于北京科技大学。1. 前端开发问题 大佬,能分享下学习路径么,感觉天天忙着开发业务,但是能力好像没有太大提升,不知道该怎么充实自己 ? 解答 业务开发有没有痛点,能不能通过技术的手段解决 ?平时开发业务用到了哪些技术栈和周边的生态链,我是否对他们熟练掌握了,对他们的实现原理呢 ?平时开发遇到了 bug,调试了很久,能不能提升自己快速定位 bug,解决问题的能力 ?如果上面分配了一个需求,没有现成的轮子可以用,我是否可以快速造一个出来 ?如果使用第三方轮子出现问题,我能否能找到合适的解决方案,甚至参与共建 ?以上提到了这些问题,不妨问问自己,如果没有做的足够好,都是你可以提升的方向。问题 我想知道你为什么对前端这个职业(行业),总是保持一颗好奇心,每天都不停探索,每天保持学习进步,你是怎样坚持下来的呢 ? 就像医院里的医生(教授/专家),在这个行业刻苦钻研了大半辈子,怎样保持每天学习的这种精神 ?探索精神 ?并且长久坚持下去 ?为社会做出了非常多的贡献。 我知道你是以怎样的决心和毅力保持每天学习,不停探索前进 ? 解答 主要是兴趣驱动吧,对技术保持热情和好奇。另外就是成就感,当我 get 到某个新技能,解决了某个复杂的问题的时候会非常有成就感。工作前几年的时间是非常关键的,是成长空间大且精力最旺盛的阶段,一定要在这个阶段多学知识。学习是无止境的,尤大说过一句话我印象非常深刻 ”做脑力工作的人,往往钻研得越深,越发现自己的渺小和无知“ ,与君共勉。问题 最近拿到了滴滴出行的实习生 offer,我想问一下您对实习生 (或者说初步踏入 IT 行业的学生) 在融入部门和提升上有什么建议 ? 解答 实习生一定要多做业务,工作要积极主动,争取转正机会。另外,非常推荐去我之前的团队,现在是苗老板负责,你可以私下联系他喔~问题 感觉自己的 js 基础很薄弱啊,我想问如果想进大厂你指的基础具体一点到底指啥啊,我是一个非科班出身的求解呀 ? 解答 如果是应届生,大厂关注的是你的基础和潜力。如果是社招,大厂会关注你的经验和能力,以及潜力。如果你有心仪的大厂,不妨去看一下他们的招聘要求,以及关注一下他们对外输出的东西。非科班是一个劣势,那么你就务必要花时间去补一些计算机相关的理论知识,简历有需要亮点,最好能有一些技术输出,比如很多人会做博客、写系列文章、做有趣的项目等等。另外,最好的时机是等大厂缺人,招人名额多的时候去投简历,也可以多认识一些找内推机会。最后,一切的一切,都离不开硬实力,所以优先提升自己的硬实力,多花时间学习。问题 黄轶老师,你对于在项目中推行 BFF 模式有什么见解吗 ?希望你可以回答的略广一点,非常期待您的回答。 解答 BFF 在服务聚合上还是很有优势的吧,特别是微服务特别火的今天,前端只需要关注所需要的数据,不用关注底层提供这些数据的服务。我在滴滴和 Zoom 的时候都是这么玩的~问题 请问一下,你做兼职的话,一般是关注那些方面呢 ? 还有比较建议在哪些渠道寻找兼职做呢 ? 解答 主要关注的是性价比,因为牺牲了自己的业余时间,要么是多挣钱(很难),要么是提升能力。最好是熟人介绍,没有的话可以去水木论坛找找看(我曾经找到过),其它渠道没有经验,我就不推荐了。问题 黄老师,想问下你对于前后端数据交互的最佳实践的看法,ajax ?axios ?等等,有没有系统学习的推荐。 解答 前后端交互通常有 HTTP 和 WebSocket 2 种通讯方式,建议你首先系统的学习一下 HTTP 相关知识,推荐看 《HTTP 权威指南》或者是 《图解 HTTP》。另外你提到的 axios 只是对 Ajax 的封装,如果你想了解它的实现原理,正好前阵子我在慕课网做了一门课程《基于TypeScript从零重构axios》,学一遍后你会对 axios 的实现细节会了如执掌,同时也可以巩固不少 HTTP 相关的知识。问题 ...

June 21, 2019 · 3 min · jiezi

热门-macOS-开源应用收集

作者: LeanCloud weakish 安利 6 款热门的 macOS 应用,其中包括三个提高效率的小工具(把 Dock 放到 TouchBar 上、在终端打开当前文件夹、基于 Lua 自动化重复任务),航拍屏保,媒体播放器,古代游戏模拟器。这些应用都是开源的(使用 Swift 和 Objective C 编写),不仅可以免费获得,还有源代码可供观摩借鉴。 Pock想要最大化屏幕空间利用但又不喜欢自动隐藏 Dock?试试 Pock,把 Dock 放到 TouchBar 上。很久以前 macOS 就把应用程序的菜单栏放到顶部状态栏,现在 Pock 把 Dock 放到 TouBar 上,是不是挺对称的?Pock 会保留应用图标的小红点,这样你就不会错过重要的通知信息。Esc、亮度、音量、播放之类的常用功能键也都还在,用起来很方便。 https://pock.pigigaldi.com/ OpenInTerminal只需一次点击,便可在终端中打开文件管理器的当前文件夹或选中的文件夹。 初次使用时需要选择终端应用(支持 Terminal、iTerm、Hyper、Alacritty),部分终端应用支持选择打开新标签页或新窗口。 https://github.com/Ji4n1ng/Op... HammerspoonmacOS 自带的 Automator 可以让你通过编写 AppleScript 自动化重复任务。不过,如果你用不惯 AppleScript 的话,可以试试 Hammerspoon,基于 Lua 自动化重复任务。其实 Lua 也和大多数主流编程语言不大一样,不过总比 AppleScript 正常多了。 例如,下面一段代码实现了到达咖啡馆后(通过 WiFi SSID 识别)发消息召唤小伙伴的功能。 coffeeShopWifi = "Baristartisan_Guest"lastSSID = hs.wifi.currentNetwork()wifiWatcher = nilfunction ssidChanged() newSSID = hs.wifi.currentNetwork() if newSSID == coffeeShopWifi and lastSSID ~= coffeeShopWifi then -- We have arrived at the coffee shop hs.messages.iMessage("iphonefriend@hipstermail.com", "Hey! I'm at Baristartisan's, come join me!") hs.messages.SMS("+1234567890", "Hey, you don't have an iPhone, but you should still come for a coffee") endendwifiWatcher = hs.wifi.watcher.new(ssidChanged)wifiWatcher:start()http://www.hammerspoon.org/ ...

June 18, 2019 · 1 min · jiezi

时至5G时代是否还有必要谈前端性能优化

之前,何同学的视频在网上活了一阵子。引发了我们思考:5G将会给我们带来什么。同时也回顾了4G乃至3G时代已经给我们带来了哪些新的变革。最近,一个问题总是时不时的冒出我的脑海:前端性能优化时候还有必要? 回顾前端性能优化 然后我找到了 雅虎军规 的 35 条 尽量减少 HTTP 请求个数——须权衡使用 CDN(内容分发网络)为文件头指定 Expires 或 Cache-Control ,使内容具有缓存性。避免空的 src 和 href使用 gzip 压缩内容把 CSS 放到顶部把 JS 放到底部避免使用 CSS 表达式将 CSS 和 JS 放到外部文件中减少 DNS 查找次数精简 CSS 和 JS避免跳转剔除重复的 JS 和 CSS配置 ETags使 AJAX 可缓存尽早刷新输出缓冲使用 GET 来完成 AJAX 请求延迟加载预加载减少 DOM 元素个数根据域名划分页面内容尽量减少 iframe 的个数避免 404减少 Cookie 的大小使用无 cookie 的域减少 DOM 访问开发智能事件处理程序用 link 代替 @import避免使用滤镜优化图像优化 CSS Spirite不要在 HTML 中缩放图像——须权衡favicon.ico要小而且可缓存保持单个内容小于25K打包组件成复合文本我们归档一下这里我们着重说明的网络相关的优化,而非浏览器端性能上的: 1.尽量减少 HTTP 请求个数——须权衡5.使用 gzip 压缩内容10.减少 DNS 查找次数11.精简 CSS 和 JS13.剔除重复的 JS 和 CSS15.使 AJAX 可缓存17.使用 GET 来完成 AJAX 请求29.避免使用滤镜31.优化 CSS Spirite32.不要在 HTML 中缩放图像——须权衡33.favicon.ico要小而且可缓存34.保持单个内容小于25K35.打包组件成复合文本然后就剩下这么几个了。作为现在前沿的前端技术,webpack已经帮我们做了5,11,13,33,35。而且其中的13.剔除重复的 JS 和 CSS,在框架盛行的时代,似乎我们已经选择基于框架的覆写而非直接修改框架的方式来构建我们的代码,因为维护成本。也就是说,我们在成本权衡下回做适当的放弃13.与此同时,在 resultful 盛行的今天,17. 使用 GET 来完成 AJAX 请求也不能满足需求,而被部分舍弃。然后字体图标的流行,把31. 优化 CSS Spirite的问题也变成了历史。接着我们看看还剩下些什么: ...

June 17, 2019 · 1 min · jiezi

阿里云前端技术周刊第九期

作者:灵沼校对:染陌 知乎:阿里云中台前端/全栈团队专栏Github:阿里云前端技术周刊 给我们投稿:传送门参与交流:传送门 前端速报 拒绝重复造轮子!GitHub推出新功能repository template,帮助开发者在所有项目中重用代码WHATWG 击败 W3C,赢得 HTML 和 DOM 的控制权,了解一下为React Hooks编写类似Redux的简单中间件,戳我看看吧趣前端 Service worker mindset 当我们在谈论service worker的时候,我们在谈论什么?应该掌握的思维模式有哪些? 除了这篇文章,这里还提供了一个非常精美生动的免费游戏来帮助你快速掌握service worker。 The economics of package management 对于前端工程师来说npm已经跟吃饭喝水一样不可或缺,但如果有朝一日npm关闭服务呢?或者还记得当时的left-pad事件么?某种程度上,npm「并不爱你」。 这是npm, Inc的前CTO, C.J.Silverio在JSConfEUwatch上演讲的文字版,不仅叙述了js包管理生态的历史,也表达出对npm的所有权为公司控制的担忧。这也是她为何投入新的包管理器Entropic开发的原因(可允许多个registry共存互通)。 编者推荐 走进身份管理 身份管理对企业信息安全至关重要,本文从概念、需求、管理等几个角度阐述身份管理的要点并提供系统化解决方案(Authing)。 History of Node.js on a Timeline Node.js十周年系列文章回顾,包含很多标志性的事件。 Yup Yup是一个Javascript object schema验证库。API和风格参考了Joi(nodejs流行的对象验证库),但是相较Joi更轻量、体积更小,适合用于浏览器端。完全声明式的验证规则、并可描述对象属性之间的级联验证,可用于表单验证,流行的react表单库Formik就内置了对Yup的支持。 跨界碰撞 比个手势,AI就识别出Emoji,浏览器运行无压力,体验一下 大疆发布首款教育机器人机甲大师 RoboMaster S1,启蒙编程思维,程序员从娃娃抓起 关于我们我们是阿里云智能中台体验技术团队。详情 如有兴趣加入我们,简历/沟通请至:lingzhao.sd@alibaba-inc.com

June 16, 2019 · 1 min · jiezi

Hexo博客多端同步问题

Hexo博客多端同步问题搭完博客,发现只有公司电脑上有源文件,如果回家就没发继续更新博客了。也不能拿着U盘到处拷贝。所以就把博客源文件放到github上解决同步问题。 博客源文件同步在博客根目录执行 git init git remote add origin git@github.com:lanpangzhi/lanpangzhi.github.io.git # 添加远程仓库 注意这里要添加你自己的仓库 lanpangzhi 换成你自己的用户名 git checkout -b hexo # 新建hexo分支并切换到hexo分支 git add . # 所有变化提交到暂存区 git commit -m "解决同步问题" # 提交文件 git push origin hexo # 推送hexo分支这就成功了,github上已经有博客的源文件了。 推荐把hexo设置为默认分支。 git submodule 实现第三方主题同步因为之前是直接把第三方主题克隆到博客目录,有什么改动是无法推送到作者Git仓库的,这个时候需要把第三方主题的项目Fork到自己仓库,自己账号下生成一个同名的仓库,并对应一个url,我们应该git clone自己账号下仓库的url。 执行如下操作。 git submodule add git@github.com:lanpangzhi/hexo-theme-next.git themes/next 把自己仓库下面第三方主题添加到Git子模块, 注 : themes/next 这里的目录是因为我用的next主题才会写themes/next 如果你用的不是next请把next替换成你的第三方主题文件夹名字。 博客的根目录会多一个.gitmodules文件,这是一个配置文件,保存了项目 URL 和你拉取到的本地子目录。 这就添加成功了,然后执行如下操作。 git add . # 所有变化提交到暂存区 git commit -m "添加第三方主题Git子模块" # 提交文件 git push origin hexo # 推送hexo分支更换电脑同步博客和第三方主题同步博客电脑上一定要先node和git,执行如下操作。 ...

June 12, 2019 · 1 min · jiezi

阿里云前端技术周刊第七期

作者:联民 校对:染陌 知乎:阿里云中台前端/全栈团队专栏 Github:阿里云前端技术周刊 给我们投稿:传送门 参与交流:传送门 前端速报 微软官方放出针对 Mac OS 用户的 Microsoft Edge Canary 预览版本,它基于开源的 Chromium 打造, 在 Tab 切换和媒体播放上, 针对 Touch Bar 做了特定支持,下载地址 Node 12.3.0 发布, 添加 --experimental-wasm-modules 特性,支持通过 import './module.wasm' 引入 WebAssembly 模块,查看链接Express 发布了近 7 个月以来的新版本 4.17.0,新增了 2 个小特性。express.raw 和 express.text, 查看链接编者推荐 PixiJS V5发布跨设备的快速轻量2D引擎库。 让你可以不需要关心 WebGL 深入知识也能充分发挥硬件加速的优势,创建各种 2d 效果。 PixiJS 有很多有趣的 DEMO , 也可以自己尝试编写一个例子。 Understanding WebViews提到互联网内世界的入口的时候,我们通常想到的是 Web 浏览器。这是一篇揭露浏览器内核 Webview 神秘面纱的文章, 介绍了它与 App 的共存关系和各类使用场景举例,是一篇科普类的好文 Linear Algebra with JavaScript (墙)这是一组系列文章, 作者使用 JS 编写了关于向量、线性变换、矩阵、线性方程等线性代数知识的大量 DEMO , 探索线性代数的奥妙。通过 JS 学习线性代数,是一个很有趣新颖的切入点。 ...

June 9, 2019 · 1 min · jiezi

阿里云前端技术周刊第八期

作者:若欢校对:染陌 知乎:阿里云中台前端/全栈团队专栏Github:阿里云前端技术周刊 给我们投稿:传送门参与交流:传送门 前端速报 Angular 8 发布,想知道新版本都有哪些特性,快来戳我瞧瞧吧。TypeScript 3.5 版本发布,这不是一个大的版本迭代,但改进的性能,增量编译和Omit帮助类型,肯定会受到 TypeScript 用户的欢迎,不信就来试试看。趣前端 你用的那些CSS转场动画可以换一换了传统转场动画就是滑来滑去,淡入淡出这些。时代在召唤,技术在发展,可以试一试使用一些新的转场动画了。此文乃张鑫旭大神出品,必属精品,值得一读。 StylieStylie 是一个动画曲线代码导出工具,你只需要调整好曲线即可导出 CSS。 GB StudioGB Studio是适用于Mac,Linux和Windows的免费且易于使用的Game Boy复古冒险游戏creator。想了解如何从零开始制作自己的 GameBoy 游戏,这篇不容错过。 只使用 CSS 的实时聊天一个匪夷所思的实验,不使用 JS,只使用 CSS 实现实时聊天,如何实现的?快来瞅瞅吧。 编者推荐 webpack 5.0 新特性尝鲜虽然webpack5还没正式上线,但这并无妨碍我们对changelog上的新特性进行尝鲜实战。 Node.js 技术栈该文档是作者从事 Node.js Developer 以来的学习历程,旨在为大家提供一个较详细的学习教程,侧重点更倾向于 Node.js 服务端所涉及的技术栈,如果该文能使您得到帮助,不要吝啬你的小星星哦~ 五种使用 Array reduce 求平均数的方法数组作为 JavaScript 比较常用的数据类型之一,它的大部分方法都很容易理解和使用,但你真的把它们的功能使用到极致了吗?一起来看看如何借助 Array reduce 求平均数吧。 JavaScript 开发人员应该具备的技能在互联网技术如火如荼发展的今天,前端开发者很难知道应该要去关注些什么,如果你对此感到疑惑,不妨来看下CV Compiler的团队整理的2019 JavaScript的发展趋势报告。 厂内动态 Ant Design 4.0 进行时!Ant Design 于 17 年 12 月发布 3.0 以来,已经经历了 16 个月的时间。在此期间,我们修复了海量 Bug、以及增加大量新功能(更新日志)。我们也发布了 Ant Design Pro 4.0。支持了 TypeScript、区块以及对布局进行抽象。与此同时,我们也在思考下一步是什么,如何才能使 Ant Design 走的更远,我们预计在今年 Q4 发布 Ant Design 4.0 版本。以下是关于 4.0 的详细计划,当然这仍在计划中。正式发布时可能会有调整。 ...

June 9, 2019 · 1 min · jiezi

数据结构的JavaScript描述

《数据结构与算法JavaScript描述》,有一种花了正版的钱买了盗版的书的感觉。花了点时间整理了一下,可以保证都能跑通。对着截图敲一遍,比复制黏贴效果好。 (点开图片加载大图需要时间) 列表 栈 队列 链表 字典 散列 集合 二叉查找树 图

June 7, 2019 · 1 min · jiezi

nginx部署代理跨域

关于nginx,咱们先了解nginx在开发过程中的主要作用nginx解决跨域nginx负载均衡一、nginx解决跨域如果要理解什么是跨域 广义上的跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。即浏览器的同源策略/SOP限制引起的跨域也属于在内;那么什么是同源策略呢?同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。同源策略即: 协议+域名+端口"三者相同常见的跨域场景如下: URL 说明 是否允许通信 http://www.baidu.com/hello.js http://www.baidu.com/world.js 同一域名,不同文件或路径 允许(无跨域) http://www.baidu.com/hello/world.js http://www.baidu.com:8000/hello.js http://www.baidu.com/hello.js 同一域名,不同端口 不允许(有跨域) http://www.baidu.com/hello.js https://www.baidu.com/world.js 同一域名,不同协议 不允许(有跨域) http://www.baidu.com/hello.js http://192.168.22.128/world.js 域名和域名对应ip 不允许(有跨域) http://baidu.com/hello.js http://x.baidu.com/hello.js 主域相同,子域不同 不允许(有跨域) http://www.baidu.com/hello.js http://www.baidu.com/hello.js http://www.bai.com/world.js 不同域名 不允许(有跨域)常见的跨域解决方案有如下:1. jsonp解决跨域2. document.domain + iframe解决跨域3. nginx代理解决跨域4. nodejs中间件代理解决跨域重点来了 nginx代理解决跨域;server { listen 80; server_name localhost; //前端域名 具体原理解释在下方 location / { // location / 代理所有请求 而如果是 location /api 则匹配到有/api 前缀的请求才会代理 proxy_pass www.baidu.com; // 服务端域名 } }前端server域名是localhost服务器server域名是www.baidu.com根据浏览器的SOP/同源策略 localhost对www.baidu.com发起请求一定会出现跨域问题;但现在只要我们启动nginx服务器把server_name设置成前端的域名,此时前端发起的请求相当于是localhost对localhost发起,这样是不会引起跨域的;但真实情况是,nginx对localhost的请求代理回 www.baidu.com这里赘述一下什么是代理; ...

June 4, 2019 · 1 min · jiezi

阿里云前端技术周刊第三期

作者:兆庆 校对:染陌知乎:阿里云中台前端/全栈团队专栏 Github:阿里云前端技术周刊 给我们投稿:传送门 参与交流:传送门 前端速报Electron 发布 v5.0.0。更多阿里巴巴官方发布免费商用字体:阿里巴巴普惠体。更多Chrome 74 正式发布,已经支持 private class fields。更多VS Code Remote 发布!开启远程开发新时代。更多飞冰(ICE)4 月新动态。更多编者推荐UForm 一种新的表单解决方案。相信做中后台的前端在处理复杂表单时一定遇到很多问题,面向复杂场景的高性能表单解决方案(背景篇)一文列举了一些常见痛点,如果你在开发时也有类似的痛点,不妨试试 UForm 表单解决方案。它引入 Rxjs 将表单联动集中处理,避免在 JSX 中做各种判断;使用 JSchema 进行表单描述,再配合 React Hook 可以非常方便的做表单拆分,再也不用担心写出一个上千行的表单组件! build-your-own-x 内容非常丰富,通过代码示例教你造各种各样的轮子,不推荐重复造轮子,但轮子是怎么造的还是推荐了解一下~ 脑壳疼的Webpack-tapable Tapable 暴露很多有用的钩子函数,主要服务于 Webpack 的插件机制,类似于NodeJS 中的 EventEmitter,本文介绍了各个钩子函数的实现原理,对于理解 JavaScript 异步编程很有帮助。 如何用数据驱动效能提升? | 解密蚂蚁研发效能 埋头做业务的同时,也要看看能用技术赋能点什么,这篇文章提供了一个大致的方法论,如何用技术手段提升研发效能。 工具尝鲜Shepherd是一款便于我们为一款产品做新手指引的工具库,通过一些简单的api就可以实现该功能,目前对于Vue,React,Angular,Ember框架都有支持。 autosub是一个可以自动为视频添加字幕的工具。vscode-leetcode让你可以在 vscode 里刷LeetCode~关于我们我们是阿里云智能中台体验技术团队。详情 如有兴趣加入我们,简历/沟通请至:zhaoqing.szq@alibaba-inc.com

May 26, 2019 · 1 min · jiezi

阿里云前端技术周刊第六期

作者:靖鑫校对:染陌 知乎:阿里云中台前端/全栈团队专栏Github:阿里云前端技术周刊 给我们投稿:传送门参与交流:传送门 前端速报 V8引擎7.5版本发布,最新的V8引擎带来的新特性可以让我们预知未来Node及Chrome将会拥有的能力,本次它主要带来了WebAssembly的隐式缓存能力以及令人眼前一亮的数字分隔符,例如1_091_134_908点我阅读详情TypeScript 3.5即将于5月30日发布,优化构建速度,新增Omit帮助函数点我阅读详情开发指南算法数构 in JS dsa.js是一个非常实用的工具库,它实现了常见的算法和数据结构模型,例如快排、Map、LinkList,推荐它给大家有两个用意。 如果你是在校大学生,这是非常好的教学资料,它的源码可以反复阅读,祝你的数构成绩更上一层楼。如果你已经工作,每日限于业务之中,思考下除了每天都在引用的Array,Map以外,可否引入其他数据结构来为业务进行建模,从而让代码更加清晰和健壮。链接地址:https://github.com/amejiarosa... Web站点优化的最佳实践网站 web.dev是由Google出品的面向Web站点优化的网站,它为我们提供了常见场景(加载、SEO、安全、可访问性)的优化指南,循序渐进地从背景知识再延伸到解决方案,通读全站,你会如沐春风,会对自己的站点优化产生新的idea。链接地址:https://web.dev Throttle和debounce在React中的应用throttle和denounce是我们老生常谈的API,但是在我们日常的开发场景中,是非常实用的,一个常见的例子便是输入搜索框,这篇文章为我们介绍了在React中的的Throttle和debounce应用。链接地址:https://blog.bitsrc.io/improv... 如何伪造和获取用户真实的IP目光转向服务端,我们需要对来访的请求做一些分流、限流等逻辑,如何获取用户真实的IP成为了一个有意思的话题,本文为大家梳理获取IP的常见问题,并介绍了egg.js里的处理思路,对此感兴趣的同学不容错过。链接地址:https://www.yuque.com/egg/nod... 开源项目2分钟快速实现视差滚动 视差滚动效果在现代站点应用越来越多了,我们期望能够有一个简洁的,性能良好的,并且不依赖于特殊框架的工具库来快速实现,这不,simpleParallax便可以满足我们的愿望,原生JavaScript编写,使用CSS3 Transform实现,无副作用,在你的项目中试试吧。链接地址:https://github.com/geosigno/s... 基于WebGL实现的酷炫流体渲染效果 非常酷炫的流体粒子效果,强迫症必备,做一些酷炫的活动页如果能适当应用那便再好不过。链接地址:https://github.com/PavelDoGre... 跨界碰撞JavaScript 如何开发 IoT 应用 JavaScript在开发者圈里一直有着不错的生态,甚至有句玩笑话,Javascript will rule the world,随着网络的普及和成本的降低,越来越多的「传统设备」接入互联网变得不是那么遥远,越来越多的互联网企业也投入到这个领域的研发,物联网和边缘计算应运而起。对于JavaScript而言,如果能够快速扩展到这个端,想必是一件非常有意义的事情,本文会为你介绍JavaScript开发IOT应用的基本策略,或许对你而言,仅仅是多了一些API,多了一些事件,但是对整个世界,却是溢出了一片缤纷,话不多说,跟着兴趣前去了解吧。链接地址:https://www.infoq.cn/article/...*Mrzkp 有效提升你的职场写作能力做的再多,不表达出来也无济于事,作为一名职场人士,我们避免不了大大小小的写作与汇报,了解这篇读书笔记,可以给你提供一些写作锦囊,攒攒小技巧。链接地址:https://www.yuque.com/quxiaof... 关于我们我们是阿里云智能中台体验技术团队。详情 如有兴趣加入我们,简历/沟通请至:jingxin.sjx@alibaba-inc.com

May 26, 2019 · 1 min · jiezi

阿里云前端技术周刊第四期

作者:弱冠校对:兆庆 知乎:阿里云中台前端/全栈团队专栏 Github:阿里云前端技术周刊 给我们投稿:传送门 参与交流:传送门 前端速报本周举行的微软Build 2019 大会上宣布了一系列开发者工具和服务:WSL2、Windows Terminal、量子开发、VS Online 等。更多使用 VS Code 进行远程开发 更多Babylon.js 4.0发布: (非常)强大的 WebGL 图形引擎 更多What's New In DevTools (Chrome 74) 更多Node 12.2.0 (Current) Released [更多]()编者推荐Python - 100天从新手到大师不会一两门后端语言的前端不是好开发,如果你还不知道从哪开始学习,那就来看看这个教程吧 leetcode题解正在准备面试的小伙伴对leetcode可能不陌生,想知道别人是怎么解题的吗? 一名【合格】前端工程师的自检清单前端有三宝:HTML、CSS、JavaScript,通过这篇文章,可以对自己目前的知识储备有个简单的认知 Node.js最佳实践nodejs 上手很简单,但是真正在项目中使用的时候会发现要考虑很多问题:目录结构定义、编码风格、项目环境配置、异常处理、代码质量、安全等。这篇文章会告诉你怎么做 使用CSS Grid做响应式布局6 行 css 实现响应式布局 趣前端有意思的动效 传送门 用动画的形式呈现解LeetCode题目的思路 传送门在浏览器上使用JavaScript模块 传送门React Patterns and Templates 传送门Why, How, and When to Use Semantic HTML and ARIA 传送门关于我们我们是阿里云智能中台体验技术团队。详情 如有兴趣加入我们,简历/沟通请至:qianshan.wengqs@alibaba-inc.com

May 26, 2019 · 1 min · jiezi

阿里云前端技术周刊第二期

作者:也树 校对:染陌 素材:也树、英布《阿里云前端技术周刊》由阿里云智能商业中台体验技术团队整理编写。 知乎:阿里云中台前端/全栈团队专栏 Github:阿里云前端技术周刊 给我们投稿:传送门 参与交流:传送门 前端速报本周 Node.js 12 发布第一个 Current 版本,包括 V8 引擎升级、ES 新特性支持、启动及解析速度提升,以及诊断工具的优化升级等,官方原文介绍请看 Node.js 12 值得关注的新特性。著名 CSS 专家 Rachel Andrew 4 月份在加拿大 W3C交流会议 上关于 CSS 新功能的分享,包括 CSS-Grid-2、CSS Scroll Snap、Conic Gradients 等。演示文稿传送门本周 create-react-app 发布 3.0 版本,主要变化有升级 Jest,更好地支持 hooks、Typescript 以及浏览器兼容能力增强。完整 Changelog 编者推荐[useEffect 完整指南](https://overreacted.io/zh-han...React 团队核心成员 Dan Abramov 关于 useEffect API 的详细介绍与示例,有多个语言版本可供查看。 CSS layout cookbookMDN 为前端开发者总结的常用 CSS 布局方式,可以了解 CSS 新特性为我们的页面布局方式带来的改变。 趣前端quicklink预加载视窗内的链接对应下探页的静态资源,让你的页面切换如丝般顺滑。立即体验 VisBug通过这个 Chrome 插件,能让任意一个网页变成画板,肆意挥洒你的设计灵感吧! React95能够让你梦回 windows95 的 React 组件库。 ...

May 26, 2019 · 1 min · jiezi

阿里云前端技术周刊第五期

作者:雏恬校对:染陌 知乎:阿里云中台前端/全栈团队专栏Github:阿里云前端技术周刊 给我们投稿:传送门参与交流:传送门 前端速报GitHub Package Registry 发布!你依旧是那个我们所爱的 GitHub!更多Google I/O 2019 召开,Chrome 开发者团队发布了 “Web at Google I/O 2019” 到 YouTube 上,包含了此次大会有关 Web 技术的所有视频,值得一看。更多在 Microsoft Build 2019 上 Edge 浏览器宣布了一些新功能,其中包括能收藏网页信息的 Collections、保护用户隐私的 Privacy tools、与 Chrome 同源的开发者工具等等。更多趣前端基于 HTML5 Canvas 的交互式地铁线路图使用Canvas开发交互式地铁线路图,带你深入掌握Canvas开发技能。 Flutter and Chrome OS: Better Together使用 Flutter 开发 Chrome OS 应用。 LeetCode - 001 - 两数之和(two-sum)没事儿刷刷LeetCode,让思维保持活跃。 你知道 JavaScript 有 535 种方法刷新页面吗使用 JavaScript 有多少种方式重新加载页面? 编者推荐探索 Serverless 中的前端开发模式从前端开发模式的演进、基于 Serverless 的前端开发案例以及 Serverless 开发最佳实践等方面,与大家探讨 Serverless 中的前端开发模式。 ...

May 26, 2019 · 1 min · jiezi

前端开发工程师找工作应该选择大公司还是小公司

大公司做开发有面子,小公司做开发有金子?小公司做开发是否更容易拿到offer?大公司做开发是否会接触到最前沿的项目?大小公司做开发,职业发展前景如何?金三银四虽然过去了,但现在来谈这些问题还不迟,如果你准备在下半年就业,那今天教你如何选择就业公司,帮助自己打好职业发展的黄金五年第一枪! 其实上面这些问题都是我在这个行业那么多年,很多学员或者朋友经常问我的,那么我今天就来给大家讲一下这些问题,分析一下大小公司的优劣,以及大家在就业选择的时候需要注意的一些地方。 薪资福利比较待遇和福利,这个是大家最关心的,先来聊最刺激的。 大公司国内的大公司,肯定就是选择一二线的互联网公司了。第一梯队:BAT(百度,阿里,腾讯),开发工程师心之所向,技术天堂。第二梯队:网易,美团,字节跳动,滴滴,360,京东,爱奇艺,小米,携程等等这些发展不错的互联网公司 一线公司的特点就是钱多,公司运行稳定,福利待遇充足,比如说腾讯的底薪比同行的高出30%,员工餐厅、咖啡厅,健身房,K歌跳舞打游戏,住房福利等等。还有阿里的也是高薪,住房+教育福利,特色食堂,各种娱乐活动。百度offer直接就是14.6个月薪水,小吃点心送到工位,员工宿舍,健康保障。 小公司但是小公司的福利你以为就会很差吗?国内很多小公司福利都还是不错的,招起开发人员来也是从不“手软”,同水平技术能力,基本的开发工资待遇底薪都会和BAT相当 。虽然说整体的福利不能完全和打公司媲美,但是也是能别出心裁,努力表现出来对员工的关怀的。比如说餐补等各种补助,健身房,员工饭堂咖啡厅,节假日问候礼等等。 如果你运气好,找对了公司,正好是在小公司蓬勃发展的时期加入了公司,到上市的时候,你还能以创始员工身份获得丰厚的股份收益。这就是很多人做开发的人说的:选对startup,一夜致富不是梦。 学习机会比较大公司在大公司做开发,你能学习到规范化的工作流程和职业技能的系统性培养。这可以帮助你培养出高效良好的工作习惯。而一旦掌握了正确的工作习惯,以后无论做什么岗位都能快速上手。打下这样良好的基础,在开发工程师黄金5年里是非常重要的。此外,大公司的员工可获得更多的知识和学习资源。比如,不同于小公司,大公司一般都有非常完善的代码文档和 CodeBase。千万不要小看好像流水账一样的记录内容,这可都是宝贵的学习资源。比如阿里就有专门的java开发规范手册。通过查看这些文档,开发工程师可以从中了解到某个专业的复杂的企业级项目,以及它每一部分的设计思路、每一段代码的具体作用。又比如,很多大公司都会有内部培训课程,manager会根据不同员工的工作需求,建议他们去上不同的课程,汲取新的技术知识。 小公司在学习机会上,小公司就没办法有大公司那么多的积累了,但是小公司最大的优势就没有边界的“野蛮生长”。在小公司,你会接触到各种各样的任务,获得来自不同岗位、不同业务的工作经验和锻炼机会,直接可以锻炼你的能力广度。不像大公司里,一年到头见不到大老板几面,在国内很多小公司都是扁平化管理,所以你可以在小公司随时随地与“高层”零距离接触。这就意味着,你有更多的机会和“大牛”一起工作,并从中获得更多高级的工作经验。而这样的机会,很多人要在大公司待4、5年才有可能获得。 职业发展比较作为一名开发工程师,你所参与开发企业项目的影响力和参与度都是很重要的,这个是可以直接影响你的职业发展的。大公司在大公司,由于公司规模大,厉害的人也多,你的影响力和参与度十分有限。而且,因为公司体系完整,分工明确,你很有可能会日复一日的做相同的工作,有种“螺丝钉”的感觉。有时候,即使你有很好的想法,可是因为大公司有很长的决策流程和复杂的人事制度,所以等你的想法层层上报,时机可能已经过去了。普遍的说,刚进大公司的新人,起码要花3个月的时间才能熟悉公司的流程,适应规则。一点点来,慢慢的才能产生实际的参与度和影响力。 不过也有好处,大公司的企业项目远超小公司的庞大项目,在未来,如果你有机会参与到这些复杂的问题,也能接触到有社会影响力的大项目,大公司会作为你升级个人能力很好的一个平台。从这个角度来看,大概是的长期发展上限会比小公司高一些。 但是,并不是所有的“螺丝钉”都能熬出头,想要达到这样一个上限,不断地学习和长期的个人努力是必不可少的。因此,很多开发工程师在大公司待了一段时间后,就会跳槽去小公司寻找突破点。小公司在小公司里,由于公司规模不大,很多时候需要一个人做更多的事情,参与的事情多了,一开始的个人影响力和上升空间会更大一些。举个例子,小公司没有像大公司那样,有非常完整的代码文档,做开发工程师,不仅要学会"拧螺丝",还要学会自己摸索着“造轮子”、“造发动机”,最后“造一台完整的车上”。虽然自己造出来的车子没有大公司造的跑得快,但是你还是可以获得满满的参与感和成就感。不过在小公司工作,就没有在大公司工作那样的“安全感”了。毕竟公司的发展和个人的发展是密不可分的。如果一开始就选好队伍,遇到像瑞幸咖啡这样的潜力股,当然前途无限光明啦但是也有很多创业公司在初期摸爬滚打,好不容上市了却股票暴跌,很多员工不得不跳槽的也有。 招聘标准比较大公司对大公司来说,他们有比较深厚的技术和财务基础,更有能力培养新人。因此,在面试的时候,大公司对应聘者的实战经验不一定要求很高,通常会主要考察应聘者的技术知识体系,学习能力和基本素养。虽然对经验要求比较低,但是在学历方面,也会趋向学习能力更强的高学历。 小公司而小公司,比如说像大疆、瓜子、小红书这些独角兽公司的面试要求反而更高,有时候甚至比BAT还严格。除了基本功之外,他们也非常看重应聘者是否有和公司现有业务的项目的实际工作经验,是否能快速的融入技术团队。 这主要是因为小公司发展还不成熟,产品需要快速迭代,而团队规模比较小,他们需要的是能入职后快速做事的老手。 最后其实大公司和小公司各有优劣,没有好不好,只有合不合适。但是在大家选择的时候,可以将以下几点作为重点考虑: 自己的职业目标 + 方向公司未来的成长形势不过,无论你去到哪个公司,扎实的基本功和丰富的项目经历,才是打开你求职道路的不二法门。

May 24, 2019 · 1 min · jiezi

ES6入门之对象的扩展

1. 属性的简洁表示法在ES6中 允许直接写入变量和函数,作为对象的属性和方法,使得代码的书写更为简洁。const f = 'a'const b = {f}b // {f: 'a'}等同于const b = {f: f}在ES6中允许在对象内直接写变量,这时候属性名为变量名,属性值就是变量值 function u(x, y){ return {x, y}}// ====function u(x, y){ return {x: x, y: y }}u(1, 2) // {x:1, y: 2}或者一下写法:function o() { const x = 1; const x = 2; return {x, y}}o() // {x:1, y:2}2. 属性名表达式在JavaScript中属性名的表达式的方法有两种,一种 直接用标识符作为属性名,第二种用表达式作为属性名。第二种写的时候表达式要放在方括号之内//一obj.foo = true//二obj['a' + 'bc'] = 123//三let t = 'm'let obj = { [t]: true, ['a' + 'bc']: 123}表达式还可以用来定义方法名(注意:属性名表达式不能和简洁表示法同时使用) ...

May 22, 2019 · 2 min · jiezi

小白教程一小时上手最流行的前端框架vue

前言 vue是现在很火的一个前端MVVM框架,它以数据驱动和组件化的思想构建,与angular和react并称前端三大框架。相比angular和react,vue更加轻巧、高性能、也很容易上手。大家也可以移步vue官网,看一下它的介绍和核心功能介绍。简单粗暴的理解就是:用vue开发的时候,就是操作数据,然后vue就会处理,以数据驱动去改变DOM。使用vue,我们可以集中精力于如何处理数据上,数据改变后,页面显示也会随之改变。相比jquery那种操作DOM元素的开发方式,能有效提高开发效率,个人觉得有接近两三倍的提升。 一、 安装 我们可以通过npm或者直接引入script标签两种方式来安装vue。这里为了方便说明,采用第二种方式,我们只需要在html页面引入标签即可。个人测试开发可以使用bootcdn的资源。 <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>二、核心思想 “数据绑定”是vue的核心思想,这里笔者举一个hello world例子来说明这种思想。 html代码 <div id="app"> <p>{{ message }}</p> <input v-model="message"></div>javascript代码 new Vue({ el: '#app', data: { message: 'Hello Vue!' }})页面效果 我们在html代码里面设置了一个id为“app”的div,然后在javascript里面实例化了一个属性el为“#app”的vue对象,表示这个vue对象用来处理该div的显示。 接着在vue对象的data属性里面设置了一个message字段,把这个字段和页面的p元素和input元素双向绑定起来。 这样只要message字段改变,p元素的内容就会改变。只要input的输入内容改变,message字段就会改变,从而导致p元素的内容改变。所以我们改变页面中输入框的值,p元素里面的内容也随之改变。 三、vue实例基本组成 new Vue({ el: '#app', data: { message: 'Hello Vue!', url: 'www.salasolo.com' }, methods:{ showMsg: function(){ alert(this.message) }, jumpUrl: function(){ location.href = this.url } },})可以看到,一个vue实例有三个基本的属性,el属性用来指定绑定的页面容器,data属性里面存放页面展示的数据,methods放置页面调用的一些方法。 四、数据绑定 使用下面的语法可以将页面元素的内容和vue实例的data属性里面的字段绑定起来。 1.文本 <span>消息: {{ message }}</span>2.原始html <span v-html="htmlCode"></span>3.列表 <span v-for="item in list">{{item}}</span>4.条件 ...

May 10, 2019 · 1 min · jiezi

刘博文代码无终点坚持跑就不会输

图灵访谈第1027期 2012年,他17岁,中专毕业。2015年,他20岁,加入国内知名互联网公司360,成为360最大前端团队奇舞团的一员。现任360导航事业部资深前端工程师。 2019年,他24岁,出版首部技术书籍《深入浅出Vue.js》。 目前负责360导航首页及二级页创新项目等亿级PV站点的设计与优化,推动Vue.js成为部门内广泛使用的核心技术栈,独立研发相关开发工具与技术解决方案并使之成功落地。 从中专毕业的门外汉,到360前端工程师并出版技术书籍,他完成了职业生涯的巨大跨越。他是怎样自主学习,快速成长的?本期图灵访谈对话刘博文,一起来了解他的前端之路。 8000块钱在北京能活多久?「虽然也很努力,但我觉得更多的是靠运气。」17岁那年我中专毕业,是学计算机的。但当时的中专就是告诉我什么是计算机,有个职业可以用计算机去工作。 刚毕业的时候,我到沈阳的一家企业去上班,不会JS,CSS也只是略懂。面试的时候,他们可能不知道我的水平,觉得我还能干活,就让我去了。结果入职后发现,我啥也不会啊,又不好意思直接让我走。就给了我两个选择,一个就是接着干,当学徒,学徒就没有工资;还有一个就是别在这干了。我想了想自己确实挺菜,那就跟着学吧。 同学都说我傻,不给钱还给人干活。现在回头看,是我运气好。如果没有这个当学徒的机会,我就没办法踏入这个行业。 2013年,我18岁,想自己来北京。那时家里人有一点担心。他们是不支持的,但还是给了我5000块钱,觉得等我钱花完了就自己回来了,总不能在那饿死。 但他们肯定想不到,我就用这5000块钱,加上自己攒的,一共8000块钱,一直坚持到现在。 当时我算好了这8000块钱,要在北京租个房子,押一付三,一个月房租按1500算,一共需要6000。我包都拎来北京了,还没找工作呢。就是住一个小旅店,每天还要花200块钱。也就是说我要在10天内找到工作并租个房子。 当时也是命好,真的找到一个特别小的公司,让我去上班。因为我知道自己的水平,能找到工作还挺高兴的,先能养活自己就行。而且公司最好的一点就是供住,员工可以每个月花200块钱住在宿舍里面。这就直接解决了我的生存问题,也是我在北京迈开的第一步。 工作了一段时间后,我还是只会写页面,切图,而且忙到没有时间学习。这样下去肯定不行,我就换了一个比较轻松的公司,为了有时间去学 JS。后来学到一定阶段的时候,我遇到瓶颈了,因为学的东西没办法在工作中用上。 我就又换了一个公司,这家公司只用一种语言就是 JS,服务端是用 Node.js 写的,比较符合我的需要。我可以充分去实践和提升技术,而且工作任务很繁重,那是我成长最快的一个阶段。 再后来,就到了现在的公司360。360给我的感觉像学校,整体工作氛围是比较轻松和自由的,任务不会把人压到一点时间都没有,我们有充分的时间自己去学东西。而且像月影、成银、李松峰老师和屈屈这种大牛会经常在公司内部讲课,有什么不懂的还可以去请教。 Vue.js 才没有看起来那么简单!初识Vue.js时,它还未被众人认可。想不到5年后,为它写了一本书。我接触 Vue.js 比较早,大概是2014年。因为上一份工作接手了一个同事的项目,就是用 Vue.js 写的。当时它是零点几的版本,还没有正式的一点零版本。我简单了解了一下,发现它和 Angular 1 很像,挺轻,挺优雅的。需求都能满足,学习成本还不高。 当时用 Vue.js 的人比较少,大家都没怎么听说过。它不火到什么程度呢?我们组新来了一个人,跟我一起写项目,我说项目是用 Vue.js 写的,就给他看了一下代码,讲了一下项目。然后,第二天他就离职了。 有半年的时间吧,我都在想是不是因为我们组的这个项目,用 Vue.js 他觉得太 low 了,所以不想干了?直到后来 Vue.js 被大家广泛认可,我才打消了这个想法。 我刚入职360的时候,我们组的项目都运行了很长时间,很稳定。一次偶然的机会,我们打算新开发一个后台管理系统,大家开会讨论技术选型。就业务来讲,我认为使用框架和对应的组件库会极大降低开发成本,就强烈推荐使用 Vue.js 技术栈,因为考虑到学习成本比较低,而且我对 Vue.js 比较熟。 现在大家已经习惯了使用框架开发,但在当时,我的提议遭到了非常强烈的反对。大家不停地提出各种问题,我也不停地给出解决方案,会议室现场变成了辩论会。 最终,我的 leader 给了我一个机会,如果想使用 Vue.js,就要在短时间解决两个最重要的问题,登录和部署流程。因为公司的统一登陆中心是结合后端来实现的,纯单页静态项目就意味着之前的登陆完全不能用了。部署流程也需要全新的解决方案。 当时我还有其他任务,所以就只能利用下班和周末的时间去做,好在最终问题解决了。这就是我们组正式使用 Vue.js 技术栈的时间点,也算是在后台项目中的一次试水。后来,我们组开发一个新产品,是面向C端的项目。在技术选型时,我又一次强烈推荐 Vue.js。因为上一个项目,有一些同学已经熟悉了 Vue.js 的开发模式,这次我也解决了一些遇到的问题(由于产品是图文内容类,存在 SEO 问题,等等)。就是这个项目真正推动 Vue.js 成为了我们的核心技术栈。 对 Vue.js 越来越熟悉,我在博客上陆续发布了一些梳理它内部原理的文章,作为总结和记录。2018年,王军花老师看到了我的博客,找到了我,问我有没有兴趣写本书。当时我感觉很突然,这东西我写不了啊。心里边是很想写的,又担心写不好,内心很挣扎。一天后,我和军花老师说可以试一下。 可能跟性格有关系,我从来都不是等把一切都准备好了,再去做一件事。一般都是机会来了,先干着再说。中间有问题再去解决问题。 当时我给自己定了的目标是6月份交稿。我列了一个大纲,然后倒推,一个月为一个节点。写作过程中,每个节点的进度可能比预期的快或慢,但总体在可控的范围内。 ...

May 7, 2019 · 1 min · jiezi

四年前端狗面试被虐如何翻身

April 25, 2019 · 0 min · jiezi

2019-前端框架对比及评测

Jacek Schae 原作,授权 LeanCloud 翻译。 我们将基于 RealWorld 示例应用对比前端框架。RealWorld 示例应用的特点: RealWorld 应用比待办事项类应用更复杂。通常待办事项类应用不足以传达足够多的知识见解构建实际应用。 标准化项目遵循特定规则。提供后端 API、静态标记语言、风格、API 规范。 专业人士编写、审阅理想情况下,会是高一致性、高真实度的项目,由使用该技术的专业人士编写或审阅。 比较的库和框架撰写本文时,RealWorld 示例应用仓库共包括 18 个 Conduit (Medium.com 克隆应用)实现。 本文不考虑框架的流行程度,RealWorld 仓库中列出的前端框架皆纳入对比范围。 测度性能应用显示内容、可以使用需要花多久? 尺寸应用有多大?我们只比较编译后的 JavaScript 文件大小。所有应用使用同样的 CSS 样式文件,CSS 文件加载自 CDN。所有应用使用的 HTML 也是一样的。这些框架都支持编译或转换为 JavaScript,所以我们仅仅测量 JavaScript 文件大小。 代码行数根据规范创建 RealWorld 应用需要多少行代码?公平地说,某些实现的功能要略微多一点,但这应该没有什么显著的影响。我们仅仅测量每个应用的 src/ 目录。 性能我们将使用 Chrome 的 [Lighthouse Audit] 测试性能。Lighthouse 返回 0 至 100 间的评分。0 为最低分。 配置所有测试均使用如下配置: 性能评分基于以下测度得出: First Contentful Paint (页面中内容元素首次渲染时间)First Meaningful Paint (页面中有意义的内容元素首次渲染时间)Speed Index (页面加载过程视觉上的变化速度)First CPU Idle (到 CPU 首次空闲的时间)Time to Interactive (到页面可交互的时间)Estimated Input Latency (预计输入延迟)详见 Lighthouse 评分指南。 ...

April 24, 2019 · 1 min · jiezi

《阿里云前端技术周刊》第一期

作者:染陌写在前面这是一个前端技术蓬勃发展的时代,从小程序到 PWA,从 Node.js 到三大框架,各种技术层出不穷。各种新技术需要我们怀揣着好奇心去探索学习,开阔自己的技术视野以及技术广度。然而互联网上的资源多而不精,本着将更多优质的资源整合学习的目的,《阿里云前端技术周刊》诞生了!《阿里云前端技术周刊》由阿里云智能商业中台体验技术团队整理编写,希望能给大家带来更多有价值的内容,共同学习,共同进步!欢迎大家关注我们,后续会为大家提供更多高质量的内容输出。知乎: 阿里云中台前端/全栈团队专栏Github:阿里云前端技术周刊给我们投稿->传送门前端速报Chrome75 将原生支持图片以及iframe实现通过loading属性进行懒加载。更多<img loading=“lazy” /><iframe loading=“lazy”></iframe>微软发布基于 Chromium 的预览版 Edge。 更多jQuery 3.4.0 版本发布。更多JS 引擎 V8 发布 v7.4 性能再次大幅提高。更多编者推荐《24 个实例入门并掌握「Webpack4」》文章由一系列 Webpack 的实例为读者讲解 Webpack4 的使用,将各个技术点拆开剖析讲解,有利于读者快速学习理解 Webpack4 的基本使用。《Serverless 给前端带来了什么》一篇文章带领大家看看 Serverless 能给前端带来怎么样的价值与能力。《逐行分析Koa v1 中间件原理》一篇非常精细的剖析 koa 中间件原理的文章,逐行级别的代码分析,带领读者深入 koa 中间件。《前端开发人员手册》一本非常全面的前端开发人员手册,从各种知识点到资源建议,内容非常丰富,值得一看。趣前端OS.js一款用 JavaScript 编写的运行于浏览器上的桌面操作系统。Octotree一款为 GitHub 提供一份更直观展示目录结构的插件,妈妈再也不用担心我在 Web 端看代码啦~关于我们我们是阿里云中台前端团队。详情如有兴趣加入我们,简历请发至: ranmo.cy@alibaba-inc.com

April 20, 2019 · 1 min · jiezi

在 Bilibili 做前端

前言来B站两年,简单记录一下这期间部门前端的变化以及自己的收获。技术上的变化17年9月,我刚加入B站直播这个大家庭。当时前端主要业务重心在web。当时,简单的前后端分离已经完成。前端提供一个 html 模板放到静态资源机上面,html 模板里面引用了所需的 js 和 css,访问页面地址时,把这个静态模板返回给用户,然后执行 js,再通过 ajax 请求 api 拿到数据,渲染页面。私有 npm 平台已经运行了一段时间,web 端的各种抽象组件在实际项目中已投产应用。rider 发布系统已经接入,docker 打包之后发布自动到指定环境。整体来看,前端技术上没有明显的短板,前端组件化、工程化实现程度较高。步入18年,前端团队在技术上主要做了这几项:重要前端页面 ssr + A/B TEST 分组实验能力重点建设 Hybrid 能力游戏引擎能力建设整治代码质量实现了对首页以及房间页的服务端渲染,并对这两项主要前端业务进行持续优化,大幅降低首帧时间 45%。对于重要的房间页,完成了基于分支发布的A/B TEST能力建设,可以支持多种分组方式,支持任意实验比例,可在线设置调节。由于产品重心由 web 端转向移动端,Hybrid 能力开始建设,H5 页面与 App 的交互逐步增加,创建了半屏 webview 协议,使 H5 页面在 App 内拥有极大的灵活性。但只有 Hybrid 是不够的,前端页面的首屏加载慢这一问题开始逐渐突出,针对该问题,接入了 app 的离线缓存,使重要的前端页面首屏与原生体验相近。利用游戏引擎重构了扭蛋机项目,满足了设计对于该页面“恐怖”的动画效果要求。(感兴趣的可以点开 bilibili app -> 直播中心 -> 扭蛋)针对代码质量问题,开始综合整治。利用内部工具, 自动进行 TS Lint & ES Lint 检测;增加组件的 Unit Test。最终,代码的千行 bug 率小于4,组件的单元测试覆盖率超过 50%。19年来临,技术总监对整个团队提出了使命:Tech Redefine Living这个很虚,但是自从总监分享过一遍他的规划之后,好好想想,我们可以一试(团队招人中,来了一起喝总监的鸡汤)!个人收获业务上提出来最好是解决方案,其次是问题经常会遇到这样的场景,需求评审的时候产品运营当场表态,这个项目要求啥啥啥上线,啥啥啥功能要具备。压根不会管你手上有多少活,你现在有多忙,就是压缩开发时间,要求又快又好。以前的做法:做不完,找领导自己加加班应该可以,闷头把事情做完,然后,交付给测试的质量并不合格,增大测试的工作量。这种做法直接的结果是,自己心里充满了抱怨,感觉自己被亏欠了很多。现在,我会提出具体的解决方案,比如,这个项目一定要做的话,它会影响哪些项目,这个项目的上线时间如果是定死的,那么哪些功能是必要的,必须完成的,哪些功能是“锦上添花”,可以二期或者直接砍掉的。但是,如果真的事情已经超出自己能力范围怎么办?抛出问题,向上反馈,请求 leader 帮忙解决。离开业务,技术很容易变成自嗨之前的我,一直认为,能写出框架的才是牛逼的,能用上最新的技术才是牛逼的,能搞定所有技术问题才是牛逼的。在B站的这段时间,改变了我的一些想法。脱离了业务的技术,很容易被忽略,因为并不知道这种技术可以在哪些地方应用,可以提升哪些数据。不对业务起增益作用的技术,很容易成为一个人的自嗨,团队其他成员无法参与进来。当技术能够与业务很好的结合的时候,自己的期望与团队的期望正好可以相互增益。比如,你想用 ssr 在线上项目,需要有严格的技术论证,确保自己可以 cover 住,降级策略是否存在等等。当把这些事情弄清之后,你就是团队里最适合做这件事的人,自己也能收获满足感。总结这两年,技术团队一直在变,一直在往好的地方转变。在今年,业务上的挑战很多,自我期望也很高,期望年底能够对这篇文章的内容做些增加。

April 15, 2019 · 1 min · jiezi

ES6入门之变量的解构赋值

数组的解构赋值基本用法ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为结构。在ES6之前想要为变量赋值,只能指定其值,如下:let a = 1;let b = 2而在ES6中可以写成这样,如下:let [a,b] = [1,2]// a = 1, b = 2值得注意的是,等式两边的值要对等,这样左边的变量才会被赋上右边对应的值,如果不对等左边的值将会出现undefined,如下写法:let [foo,[[bar],baz]] = [1,[[2],3]]foo // 1bar // 2baz // 3注意:只有左右两边的 格式一定要对等,数量可以不对等。let [a,b,c] = [1,2]a = 1, b = 2, c = undefinedlet [a,,c] = [1,2,3]a = 1, c = 3let [a, …b] = [1,2,3]a = 1, b = [2,3]let [a] = []let [b,a] = [1]a = undefined还有一种情况,等号左边为数组,但是等号右边为其他值,将会报错。如下:let [a] = 1;let [a] = false;let [a] = NaN;let [a] = undefined;let [a] = null;let [a] = {};以上都会报错但是如果左边为数组,右边为字符串,将会取字符串的第一个下标的值let [a] = ‘121321’ a = ‘1’let [a] = ‘adgasg’ a = ‘a’对于Set结构,同样可以使用数组的解构赋值。let [x,y,z] = new Set([1,2,3])x = 1, y = 2, z = 3默认值解构赋值允许指定默认值let [a = 3] = [] // a:3let [a = 3,b] = [,4] // a:3 b:4let [a = 3,b] = [5,4] // a:5 b:4特殊let [a = 3] = [undefined] // a:3let [a = 3] = [null] // a:nullTips: 在es6中使用严格相等运算符,在结构赋值中如果需要默认值生效,则应对等的值为undefined的时候才会采用默认值,否则还是使用赋值。上面中null 不严格等于undefined++如果默认值的赋值为一个表达式,只有当等号右边的赋值没有值为undefined的时候,才会取表达式中的值,如下:function demo(){ console.log(‘demo’)}let [a = demo()] = [] // a: demolet [a = demo()] = [1] // a : 1对象的解构赋值与数组的不同点是,数组的元素必须和赋值的元素要位置一致才能正确的赋值,而对象的解构赋值则是等号两边的变量和属性同名即可取到正确的值。否则值为 undefinedlet {a,b} = {a:‘23’,b:‘3’}let {a,b} = {b:‘3’,a:‘23’}// 上面两个的值 都是 a: 23 b: 3let {a,b} = {a:‘3’,c:’d’}//a: 3 b: undefined对象的解构赋值还有将某一个现有对象的方法赋值到一个新的变量,如下:let {sin,cos} = Math// Math 中的sin cos 方法将赋值给变量 sin coslet {log} = console// log(2) === console.log(2)如果等号左边的变量名不能和等号右边的对象的属性名一致,则必须写成如下格式:let {a:b} = {a:‘ss’} // b:ss//a是属性名,b才是实际赋值的变量名对象的解构赋值一样是可以嵌套解构的,如下:第一种:let obj = { p:[ ‘Hello’, {y:‘world’} ]}let {p:[x,{y}]} = obj // x: Hello, y: world这边的p只是属性不是变量,如果p想赋值可以写成:let {p,:[x,{y}]} = obj第二种:const a = { loc: { t :1, b :{ c:1, d:2 } }}let {loc:{t,b:{c,d}}} = a或者let {loc,loc:{t,b,b:{c,d}}} = a嵌套赋值let o = {}, arr = []({foo:o.prop,bar: arr[0]} = {foo:123,bar:true})//o: 123, arr = [true]如果解构模式 是嵌套的对象,如果子对象所在的父属性不存在,则会报错,如下:let {foo:{bar}} = {baz:‘baz’} //报错默认值let {x = 3} = {}// x: 3let {x,y = 5} = {x : 1}// x: 1, y: 5let {x: y = 5} = {}// y = 5let {x: y = 5} = {x : 4}// y = 4let {x: y = ‘hhhh’} = {}//y = ‘hhhh’Tips:以上左边 x为属性名,y为变量let {x = 5} = {x: undefined}// x: 5let {x = 4} = {x: null}// x: null同数组一样遵循 严格等于 只有右边为undefined的时候默认值才会生效注意点:1)不能将已声明的变量用于解构赋值,因为已经是一个代码块。字符串的解构赋值如果赋值的对象是数组,字符串将被分割为数组的格式,一一对应赋值let [a,b] = ‘ha’// a = h , b = a同时可以获得字符串的长度:let {length:len} = ‘12121’// len = 5数值和布尔值的解构赋值如果等号右边是数字或者布尔值 则转换成对象或者说,除了是数组和对象,其他值都将转换成对象,null 和 undefined 除外。如下:let {t:s} = 123let {t: s} = true函数参数的解构赋值function add([x,y]){ return x+y}add([3,5]) // 8[[3,5],[6,7]].map(([a,b]) => a + b)//8 , 13function m({x=3, y=4} = {}){ return [x,y]}m({x:33,y:8}) // [33,8]m({x:32}) // [32,4]m({}) // [3,4]m() // [3,4]function m({x,y} = {x=0,y=0}){ return [x,y]}m({x:33,y:8}) // [33,8]// 代替右边的 x:0, y:0 所以是传值 33 8m({x:32}) // [32,undefined]//因为传值替代右边的赋值,但是只有x没有y//所以y是取 左边y的默认值,因为你没有赋值 为undefinedm({}) // [undefined,undefined] // 取左边x,y的默认值,因为没有赋值 为undefinedm() // [0,0]// 没有传值,使用本身的赋值 都是0其他不能使用圆括号的情况变量声明语句函数参数赋值语句的模式可以使用圆括号的情况赋值语句的非模式部分,可以使用圆括号解构赋值的用途交换变量的值从函数返回多个值函数参数的定义提取JOSN数据函数参数的默认值遍历Map解构输入模块的指定方法欢迎关注 公众号【小夭同学】ES6入门系列ES6入门之let、cont ...

April 10, 2019 · 2 min · jiezi

最全的前端Git使用教程

常见信息master: 默认开发分支origin:默认远程版本库Head: 默认开发分支Head^:Head 的父提交创建新仓库git initgit init [project-name] # 新建一个目录,并将其初始化为git仓库git clone [url] # 拷贝一个git仓库到本地配置Git 的配置文件是 .gitconfig,可以放在用户的主目录(全局配置)下或项目目录下(项目配置) 。# 显示当前的 git 配置git config –list # 编辑 Git 配置git config -e [–global] # 设置用来提交代码的用户信息git config [–global] user.name “[name]” git config [–global] user.email “[email address]“添加删除文件# 将指定文件添加到暂存区git add [file1] [file2] … # 将指定目录添加到暂存区,包括子目录git add [dir] # 将当前目录中的所有文件添加到暂存区git add . # 对同一个文件多次更改,建议分开提交git add -p # 将指定文件从工作区删除,并将本次删除添加到暂存区git rm [file1] [file2] … # 停止追踪指定的文件,不会删除文件git rm –cached [file] # 对指定文件进行重命名,并添加到暂存区中git mv [file-original] [file-renamed] 代码提交# 将暂存区中的文件提交到代码仓库git commit -m [message] # 将指定的文件从暂存区中提交到仓库git commit [file1] [file2] … -m [message] # 将工作区的更改直接提交到仓库git commit -a # 提交前展示所有的变动git commit -v # 使用新提交代替上次提交,如果代码没有任何变动,将会用于重写上次提交的提交信息git commit –amend -m [message] # 重做上次的提交,并将指定的文件包含其中git commit –amend [file1] [file2] … 分支相关# 列出本地分支git branch # 列出所有远程分支git branch -r # 列出本地和远程的所有分支git branch -a # 新建分支,并留在当前分支git branch [branch-name] # 新建分支,并切换到新建分支git checkout -b [branch-name] # 指向某次提交新建分支git branch [branch] [commit] # 创建一个新分支,并与指定的远程分支建立跟踪关系git branch –track [branch] [remote-branch] # 切换到指定分支,并更新工作区git checkout [branch-name] # 切换到上一个分支git checkout - # 将本地分支与指定的远程分支建立跟踪关心git branch –set-upstream [branch] [remote-branch]# 合并指定分支与当前分支git merge [branch] # 将指定的提交合并到本地分支git cheery-pick [commit] # 删除本地指定分支git branch -d [branch-name] # 删除远程分支git push origin –delete [branch-name]git push -dr [remote/branch]标签操作# 列出所有标签git tag# 在当前 tag 上创建一个新标签git tag [tag]# 在指定 tag 上创建一个新标签git tag [tag] [commit]# 删除本地标签git tag -d [tag]# 删除远程标签git push origin :refs/tags/[tagName]# 查看标签信息git show [tag]# 提交指定标签git push [remote] –tags# 创建一个新分支,指向特定的标签git checkout -b [branch] [tag]查看信息# 显示有变动的文件git status# 显示当前分支的提交历史git log# 显示提交历史和每次提交的文件git log –stat# 指定关键字搜索提交历史git log -S [keyword]# 显示自某次提交以来的所有更改,一次提交显示一行git log [tag] HEAD –pretty=format:$s# 显示自某次提交以来的所有更改,其提交描述必须符合搜索条件git log [tag] HEAD –grep feature# 显示指定文件的提交历史git log –flollow [file]git whatchanged [file]# 显示与指定文件相关的每个差异git log -p [file]# 显示最近 5 次提交git log -5 –pretty –oneline# 显示所有的提交用户,已提交数目多少排名git shortlog -sn# 显示指定文件何时被何人修改过git blame [file]# 显示暂存区和工作区文件差别git diff# 显示暂存区和上一次提交的差别git diff –cached [file]# 显示工作区和当前分支的最近一次提交的差别git diff HEAD# 显示指定两次提交的差别git diff [first-branch]…[second-branch]# 显示今天提交了多少代码git diff –shortstat “@{0 day ago}”# 显示特定提交的提交信息和更改的内容git show [commit]# 某次提交改动了哪些文件git show –name-only [commit]# 显示某个提交的特定文件的内容git show [commit]:[filename]# 显示当前分支的最新提交git reflog远程同步# 从远程分支下载所有变动git fetch [remote]# 显示所有远程仓库git remote -v# 显示某个远程参考信息git remote show [remote]# 新建一个远程仓库,并命名git remote add [shortname] [url]# 检索远程村粗库的更改,并与本地分支合并git pull [remote] [branch]# 将本地分支提交到远程仓库git push [remote] [branch]# 将当前分支强制提交到远程仓库,即使有冲突存在git push [remote] –force# 将所有分支提交到远程仓库git push [remote] –all#### 撤销操作# 将暂存区中的指定文件还原到工作区,保留文件变动git checkout [file]# 将指定文件从某个提交还原到暂存区和工作区git checkout [commit] [file]# 将暂存区中的所有文件还原到工作区git checkout .# 重置暂存区中的指定文件,与先前的提交保持一致,但保持工作空间的变动不变git reset [file]# 重置暂存区和工作区中的指定文件,并与最近一次提交保持一致,工作空间文件变动不会保留git reset –hard# 重置暂存区,指向指定的某次提交,工作区的内容不会被覆盖git reset [commit]# 重置暂存区和工作区中的指定文件,并与指定的某次提交保持一致,工作区的内容会被覆盖git reset –hard [commit]# 将 HEAD 重置为指定的某次提交,保持暂存区和工作区的内容不变git reset –keep [commit]# 新建新提交以撤销指定的提交git revert [commit]# 暂存为提交的变动,并在稍后移动它们git stashgit stash popgit stash apply其他# 生成用于发布的存档git archive欢迎关注 公众号【前端开发小白】 ...

April 4, 2019 · 2 min · jiezi

前端生涯的第二年-2018

回顾18年,怎么讲,工作上有很多不顺利吧,经常会特别的焦虑,在这座城市找不到存在感,觉得很难够留在这个城市。崩塌,你会发现你原来的各种各样的认识,你会发现你全都没法说服自己,没法证明它是对的,它都不对了。你会怀疑自己,怀疑一切。你会发现你对这个世界一无所知。我原来觉得自己只要努力,只要不停的努力,只要不停的学习,我可以获得我想要的东西,现在发现这一切好像都太可能了。对了,18年末尾,我辞掉了工作,认识我的朋友觉得之前都那么多份工作经验了,这一个还说个锤子,但是这一个辞职原因不一样,真的不一样。自己的不合群,令人反感的企业文化,错综复杂的同事关系,学不会的阿谀奉承,XX的工作气氛与付出不匹配的工资,不懂行的老板,被肆意侵占的个人时间。岁月不居,时节如流。距离2019农历春节还剩下5天,家里也搞好清洁了,空出点时间,于是打算花点时间对这一年做一个总结。学习JS已经不是原来的JS了不是所有前端都在写 JS。已经有很多前端在用 TypeScript 了,还有一些前端在用 Reason、Elm、ClojureScript 和 Dart。尤其是 TypeScript 的发展势头最猛,JS 学得好的前端很快就能上手 TypeScript,很多大公司的前端对 TypeScript 更是爱不释手。趋势:前端 == 全端移动 App、移动网页、PC 应用、PC 网页、微信小程序、支付宝小程序、百度小程序、各种小程序……面试其实在去年大学毕业的时候,我就说过2018这一年一定是我技术成长最快的一年,但是现在我认为我当初的想法是错误的,其实在技术方面,这一年,我收获的并不多,在工作上,一些业务需求都是重复的,本身前端就没有过多的逻辑,再加上自律性不强,没能静下心下深究那些更深层次的东西,这才导致有换工作有压力的危机感。陆陆续续进行了一大波面试的直接原因。老实讲,面试的过程并不顺利。像各种大公司,如腾讯、YY的面试我都参加了几次,我一直认为自己的技术水平还是不错的,但在实际面试中,还是会对一些问题有所疏漏,以至于答的不能让面试官满意,以至于最终基本都挂掉了。还有一次印象比较深刻的经历就是,在内推流程中直接简历评估就被 PASS 掉了,这让我一度很是蛋疼,备受打击。但后来也明白了,面试这个事情,最忌讳的就是妄自菲薄,因为挂掉不一定意味着你的能力不行,也可能是不合适,而且,面试也不是一个可以量化的考核过程,达标并不意味着通过,面试者肯定会选择最好的那一个,况且,千里马常有,而伯乐不常有,所以也没必要太计较结果。总结2018,有开心,有失望,有快乐,有彷徨,但我觉得这一年更多的是在迷茫和焦虑中摸索前行。一个人的变化只有自己是最不容易察觉到的,也是只有自己最容易感受到的。这一年,毕业、就业,自己潜移默化中改变了很多。2019,想对自己说:少些浮躁,多关注本质,多尝试,少回头,不要很快被磨平棱角。

March 29, 2019 · 1 min · jiezi

前端开发在淘宝主要是在做什么事情?

前阵子,有些师弟师妹问我:在淘宝,前端开发主要是在做什么事情?作为一个在淘宝已经工作 5 年的「老兵」,我想我有资格来全面地回答一下这个问题,并通过这个机会向外部介绍一下我们团队的同学。按照领域来划分,我们主要在做这些事情:Node 架构从 Node.js 应用框架到全链路监控以及故障演练,从基于 TypeScript 的 IoC 容器到 Serverless Node.js 运行时,我们都在做。主要是七念同学在负责这方面的工作。中后台在中后台领域,我们通过打造桌面工具帮助开发者极速构建前端应用,当然还有通过智能界面设计平台的建设以革新前端的开发模式。在 Github 上,我们有 1w+ star 开源项目 ICE。通过关注这个仓库,你可以了解我们的工作动态。主要是元彦同学在负责这方面的工作。前端智能化在淘宝有成千上万的界面,为了提效与业务密切相关的开发场景效率,我们基于计算机视觉、深度学习等,从设计稿( Sketch、PSD、静态图片)一键智能生成高可维护性代码。我们持续在探索智能化的世界。主要是秒净同学在负责这方面的工作。终端架构淘宝 H5 主站、前端数据体系、海报搭建平台、个性化定制的跨端解决方案等场景,主要是我们北京团队的同学在负责。他们专注于挖掘业务价值、提升性能体验、拓展技术边界。这方面海文同学有着丰富的经验。前端搭建为了更好地支持双十一、双十二活动页面、小程序的产出,我们有专门负责搭建系统的同学。他们着力于实现可视化的方式从 0 到 1 搭建页面,配置页面动态数据,后期页面运维等一系列服务。步天、苏河同学在负责这方面的工作。前端开放在面向商家装修的中后台应用,面向 ISV 的开放平台,我们在尝试 Weex 在跨端应用开发的最佳实践,推进 IDE 在工程链路中的集成。正豪同学在这方面有着丰富的经验。前端工程阿大同学正在打造整个阿里前端开发的工程化基础底层体系,业内领先的前端工程底层系统开发,他对从项目初始化到线上编译、扫描、发布的全链路体系架构设计与实现有着丰富的经验。图形渲染我们还有一群致力于 WebGL/WebGPU 跨端标准化实现的小伙伴,诞生了为极致渲染而生的图形渲染引擎 GCanvas,正在面向 5G/IoT 发力创造新一代渲染框架。二同同学在负责这个方向。以上便是我们在淘宝主要在做的事情。最后,作为一篇软文,我打个小广告。如果你也有兴趣,可邮件联系:xwt.wuji@alibaba-inc.com ,一起来参与。如果你是 2020 届的毕业生,可扫码进入实习生内推流程:

March 28, 2019 · 1 min · jiezi

高效使用VSCode的9点建议

译者按: 充分利用其特性,你会觉得 VSCode 非常强大!原文: Pro tips for Visual Studio Code to be productive in 2018 ????????????译者: Fundebug为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。在开源 IDE 市场,最近几年 Visual Studio Code(简称 VSCode)越来越流行。自从 2015 年对外发布后,根据 2018 年 Stack Overflow 的调查报告,有 35%的开发者转而使用 VSCode。我接下来会介绍一些建议和技巧来让你更加高效的使用 VSCode。Git 和 GitlensGit 可以说是在开发者中最流行的软件,从 IDE 直接操作 Git 会比通过命令行简单很多。Git 模块可以帮助你做 stage、commit、stash、undo 等操作。Gitlens 插件提供了更多的可能性。Gitlens 最有用的特性就是你可以看到每一行代码的 commit 历史。实时共享VSCode Live Share 是一个实验性的特性。官网上这样说到:无论构建什么类型的应用,使用何种语言编程或使用何种操作系统,当需要协作时,实时共享都能够立即将你的项目与队友共享。 队友可实时编辑和调试,无需克隆存储库或设置其环境。通过 Live Share,可以共同进行编辑和调试,同时还可共享音频、服务器、终端、差异、注释等。 无论是进行代码评审、与队友结对编程、参与 Hackathon 活动还是进行互动式讲座,Live Share 都可以通过多种写作方式为你提供支持。JSON to Code是否经历过,当个面对一个 API,你希望它返回的数据结构能够有一个类型定义,但是又不用自己去手动定义? Paste JSON as Code 可以一键将 JSON 文件转换为一个目标语言的类型定义。批量重命名写代码和维护代码的时候少不了做重构,特别是当你重构一个很大的模块或则很大一段代码的时候,一个一个去查找和修改变量/函数名会很头痛。好在 VSCode 可以帮助我们。如果你选中一个变量/方法名,然后按 F2,你可以编辑选中的名字,整个项目中所有相关的实例都会被修改。如果你只想修改当前文件,使用 Command+F2(Mac) 或则 Ctrl+F2(Windows) 命令。跳转到定义当在写代码的时候,面对一个变量/方法,往往会忘记其指代的含义。在这个时候怎么做呢?你要花上数分钟的时间来搜索整个项目,定位到正确的位置。在 VSCode,你可以使用 Command(Mac)/Ctrl(Windows) 并鼠标单击对应的变量/方法名,VSCode 会自动跳转到正确的位置。或则,你可以将光标停留在变量/方法名,然后按下 Command(Mac)/Ctrl(Windows),会在当前光标旁边弹出变量/函数的定义。这样省去跳转到其它位置的麻烦。多行编辑如果你想要插入/删除多个相同文本的实例,你可以创建一个多光标(Multiple cursor)。你可以按住 Option(Mac)/Alt(Windows) 按键,然后每点击一次,光标就在当前位置停住。每一次点击创建一个新的光标,然后就可以同时编辑这些位置。在 HTML 中非常有用,特别是当你想修改类名/超链接,而它在多处出现的时候。DebuggerDebugger 本身内容很多,VSCode 有一个专门介绍的视频。Youtube 视频地址:VSCode debugging Node.js绑定快捷键如果你想高效的工作,将你常用的命令制成快捷键。你可以通过cheat sheet/“查看快捷键绑定”来快速查看核心命令。命令控制台是你最好的朋友,你可以使用 Command+p(Mac)/Ctrl+p(Windows) 来打开。输入文件名,你可以快速跳转到指定的文件。这比你在左侧项目目录慢慢找要快得多。你可以输入 > 来查看所有可用任务用@符号来获取当前文件所有的 Symbols(变量/函数/类名/方法等等)自定义绑定快捷键在 VSCode 有一个命令缺失了,那就是“保存所有”。我们可以自定义一个:Command+Shift+S(Mac)/Ctrl+Shift+S(Windows)。关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/03/26/tips-for-vscode-to-be-productive/ ...

March 26, 2019 · 1 min · jiezi

滴滴出行-前端实习生招聘

你想加入一个对技术充满理想主义的团队吗?你想参与业界最前沿的Chameleon跨端技术解决方案(https://CMLJS.org),一起建设面向全行业的MVVM+标准吗?快来加入滴滴OFD团队!任职要求:1、本科及以上学历,计算机相关专业在校生,工作城市为北京,可实习6个月及以上。2、熟知W3C标准,熟练掌握HTML、CSS、JavaScript(含HTML5、CSS3)3、熟悉流行框架及类库:Vue、React、jQuery、Zepto等4、熟悉构建、发布流程及相关工具者优先,例如Webpack、Gulp、FIS、Grunt等5、熟练使用git等版本管理工具6、了解一种后端语言者优先,例如:NodeJS、PHP、Go、Java等7、有较强的沟通能力等软素质8、有实际生产环境项目经验者优先简历请发送至邮箱:wangzhiliang@didiglobal.com

March 25, 2019 · 1 min · jiezi

不按套路求职,到底有多惨?

身为一个程序员,找工作的时候第一个想到的问题是什么?“简历该怎么写”?还是“面试有哪些细节”?很少有人注意一件事:该找一份什么样的工作?好比老王的儿子小王,人特别聪明,仅仅用了9年,就大学毕业,该成家了。自己成天上网看各种攻略,什么“和女神约会的10大技巧”、“第一次和女孩吃饭该怎么聊天”,托人介绍,天天相亲,唯独没想过:“我喜欢什么样的女孩”。有人说,这还用想,找工作嘛,得有发展,其他的好说。这话说得,好比找对象,人家问你什么标准,女孩找程序员的标准倒是挺明确,无非有车有房、工资上交、父母祥和。但是程序员找女孩就“费劲”了,人“好”就行。问题是,人哪儿“好”?很多人都说要找份“好工作”,也一样,怎么个“好”法,说不清楚,况且每个人情况还不一样。同样一份工作,月薪25k,还给股票期权,但是要经常加班,对于人家来讲这就是机会。但你要是说这段时间,打算多花点精力,和爱人一起,响应一下国家的二胎政策,这活儿对你来说,就完全没有吸引力了。那么,怎么做呢?找工作的时候要不违背下边的四条原则,就不会出大问题。很多人好不容易找份工作,干上三五个月就换一家,打过交道的HR都凑齐12星座了,钱是损失了不少,关键是耽误工夫,别人都积累到一定程度,朝着18k、20k努力去了,自己还在8到10k之间游荡。哪四条原则呢?符合价值观、感兴趣、结合自身情况和匹配职业目标。1.价值观这是最重要的事情,没有之一。听到这个词,你可能会觉得我要跟你谈理想、聊人生,但是工作时间长了,你会发现这个词,比真金白银都实在。我有同学,毕业的时候签了一家公司,月薪12k,要知道那时候普通水平的程序员薪资可是8k左右,每个月都能比同龄人多拿四千块钱!后来毕业吃散伙饭,聊到他马上要去的这家公司,据说是做古董收藏的,这样的公司也招前端?我问他:你是不是觉得收藏古董特有意义?他白了我一眼:我觉得每个月多拿点钱是真的!意义这东西,无所谓。一个月给我30k,让我去电梯里负责开门都行。转眼几年过去了,我看到他在技术博客里写:整个公司就他一个人懂前端,敲出来的东西都是给上了岁数的老年人看的,用不上什么新技术,一天天过得倒是不忙,确切地说是一种“等死”的状态。没过多久,还真把他的公司等死了,重新找工作,技术上完全没有任何优势!我问过他:没想着有空的时候钻研下新技术?他摆了摆手:活干着没劲,谁有那个心情? 所谓的价值观,就是你觉得什么东西对你来说很重要?你觉得做点什么才会有价值?本来生性自由的一个人,喜欢挑战,一毕业进了一家大公司,流程都定好了,只让他负责执行,上个厕所还得先翻翻《员工手册》,做个什么项目也不需要你自由发挥,更别说重构代码了,连给官网换张图片都得打报告!这样的活,能坚持多久?刚开始,你对自己说咬咬牙,就过去了,时间一长呢?这是价值观不符合的问题,只要还在这个公司待着,再过10年也这样,没听说哪个公司因为一个程序员把企业文化改了。2.感兴趣对于程序员来说,兴趣不仅仅是最好的老师,也是唯一的爱好、丰富的精神食粮,有的大神在电脑面前一坐就是十几个钟头,一看外边天黑了,自己也犯迷糊:我女朋友是谁来着?很多人觉得一谈兴趣,就是在灌鸡汤,但是看到技术大牛上百万的年薪,自己又羡慕。说起来这件事吧,还振振有词:你看人家大牛,本身就有天赋吧,还那么努力,往电脑面前一坐就是十几个钟头,咱是比不了啊!大神花的功夫,那是表象,根本原因还是兴趣。当你职位一时半会升不上去,每个月到手的工资也没有太多变动的时候,你在心里默念:我得努力,我得奋斗,我要为我的女神买床垫……这没什么用,就算年轻,鸡血那股劲,两天就过去了!人是感情动物,倒不如从兴趣的角度:这东西挺有意思,我看看能不能把他们家网站扒下来试试(知道你肯定也做过,但是劝你别学坏。)有的程序员上相亲网站,都不忘给人家找Bug,可以说是敬业,他们的内心戏是:唉,搞点小破坏还是挺有意思的哈!3.结合自身情况咱们先说说这“自身情况”主要指什么:你偏向于用什么技术栈?想从事哪个细分行业?这都属于“自身情况”,有人说,都是搞前端的,选技术栈我能理解,细分行业重要吗?虽然都是前端,但你在直播类平台敲代码,就和新闻类平台做项目不一样,就像老师也有很多种,教小学音乐和大学物理根本不是一回事。那怎么“结合自身实际情况”呢?从“技术栈”和“细分行业”来讲。技术栈的选择,初期需要考虑目前的积累、未来的前景,比如Angular 就业机会少入门难,如果你是个小白,完全可以从“0基础福星Vue”开始。但是如果你已经用了Angular好几年了,学它的人少,人才难求,对于你反而是一个机会和优势。这个时候你再从头学Vue,之前的经历形不成你的优势。从长远来看,并非框架决定我们选什么工作,而是工作内容决定了我们要选什么框架!当你能够从本质掌握一个框架,有足够深刻理解的时候,所有框架在你眼中,没多大差别,自然而然地,你就能根据业务需求,用最正确的框架。再说细分行业,假如你一直开发的是新闻类APP,下一份工作去今日头条或者网易新闻是没问题的,可你贸然进入直播类平台,没有任何积累,自然也没什么优势可言。4.职业目标很多人追求事业上的成功,它更像是打麻将而不是赛跑,赛跑你想赢,必须第一个冲到终点,但是麻将要赢,能通过很多方式“和牌”。如果问到目标,很多人的求职目标看起来都很简单:“多赚钱”!但问题是:赚钱的路有很多,对你来说是不是都一样?一份工作年薪50W,这个数字在IT界也不算低了,但如果它需要你996,甚至昼夜连轴转,对于一个需要照顾孩子的宝妈,就不是个好选择。一个人的职业目标可以有很多:在一个细分领域当专家,在一个大型企业当高管,或者在一个初创公司闯出一片天,如果一个人看重自己在职场中的地位,那么进入一家传统企业,对他来说就是灾难:你领导的领导都升不上去,什么时候才轮的上你?其实这四个方面,之所以按照“价值观、兴趣、自身情况、目标”这个顺序来排,除了重要程度之外,“容不容易变”也是个重要考虑因素。一个人的价值观是很难改变,就像你十年前讨厌一个人,到现在也好不到哪儿去。相对来说,职业目标就容易一些:一年前还想着在大厂做高管,现如今有了孩子,找工作的时候先看离家近的。总 结:拿到一份offer,先看它符不符合我们的价值观,工作内容感不感兴趣,再结合自身实际情况,来看它能否帮我们达成自己的职业目标。把握住这些原则,我们就能在一份合适的工作中,完成职业初期的积累;而不是深陷“跳槽漩涡”,在兜兜转转中空耗时间。3月20号我们邀请了,前端职业规划师Maxwell,在线live为大家讲解跳槽、面试相关的实战攻略。

March 17, 2019 · 1 min · jiezi

Web前端面试技术点

常规问题:一般来说会问如下几方面的问题:做过最满意的项目是什么?项目背景为什么要做这件事情?最终达到什么效果?你处于什么样的角色,起到了什么方面的作用?在项目中遇到什么技术问题?具体是如何解决的?如果再做这个项目,你会在哪些方面进行改善?技术二面主要判断技术深度及广度你最擅长的技术是什么?你觉得你在这个技术上的水平到什么程度了?你觉得最高级别应该是怎样的?浏览器及性能一个页面从输入 URL 到页面加载完的过程中都发生了什么事情?越详细越好 (这个问既考察技术深度又考察技术广度,其实要答好是相当难的,注意越详细越好)谈一下你所知道的页面性能优化方法?这些优化方法背后的原理是什么?除了这些常规的,你还了解什么最新的方法么?如何分析页面性能?其它除了前端以外还了解什么其它技术么?对计算机基础的了解情况,比如常见数据结构、编译原理等技术点沟通:HTML+CSS1、盒子模型,块级元素和行内元素特性与区别。 2、行内块的使用,兼容性解决。 3、清除浮动的方式以及各自的优劣。4、文档流的概念、定位的理解以及z-index计算规则&浏览器差异性。 5、CSS选择器以及优先级计算。 6、常用的CSS hack。7、遇到的兼容性问题与解决方法。 8、垂直水平居中的实现方式。9、常用布局的实现(两列布局、三列适应布局,两列等高适应布局等)。Javascript1、犀牛书封面的犀牛属于神马品种?(蛋逼活跃气氛用。。。) 2、常用的浏览器内核。 3、常用的DOM操作,新建、添加、删除、移动、查找等。4、String于Array常用方法。 5、设备与平台监测。 6、DOM的默认事件、事件模型、事件委托、阻止默认事件、冒泡事件的方式等。7、jQuery的bind、live、on、delegate的区别(考察点与上一条重叠,切入点不同)。8、JS变量提升、匿名函数、原型继承、作用域、闭包机制等。 9、对HTTP协议的理解。 10、Ajax的常用操作,JS跨域的实现原理。HTML:语义标签语义化CSS:动态居中动画Bootstrap 样式类Preprocessor兼容性 Hack与特征检测CSS3属性与性能JS:Name hoistingPrototypeClosureMain loopPromiseDelegationCross domainMobile:渐进增强移动端交互兼容性问题Debug工具 方法主体是看简历发挥,对方写什么就问什么为主:框架、库、浏览器工作原理、NLP、算法、HTTP… 辅助问题几乎是我个人必备的问题:为什么做前端,学习前端过程。1、跟什么人在一起工作 2、过去项目的挑战 3、自学的途径3个问题基本上就知道这个人的能力水平和瓶颈了,人的很多局限都是被环境限制的,通过闲聊中夹杂的不经意的问题,候选人的画像就已经很鲜明了。处于当前的环境多长时间,有没有突破环境限制的行动,就能评估出潜力和眼界。什么浏览器兼容、作用域、框架等等的东西不会,不记得都可以学,要不了多长时间,关键还是有没有潜力、有没有好的习惯。在能力方面:对 HTML / CSS / JavaScript 具有专家级别的知识;有较熟练使用 AngularJS / Ember.js / jQuery 或者其它类库的经验;较熟悉第三方组件(插件)生态环境及具体案例;有较熟练使用 Jade / Swig / Handlebars / Mustache 或者其它模板引擎的经验;有较熟练使用 SASS 或者其它 CSS 预处理器的经验;有较熟练使用 CoffeeScript 的经验;对 CSS / JavaScript 设计模式有很好的认识及应用;对常用数据结构和算法熟悉;有使用 GruntJS / GulpJS 任务运行器的经验;有使用 Yeoman 生成器的经验;有诸如 Bower / Volo / JSPM 等前端静态资源包管理器使用经验;熟悉本地及远程(甄姬)调试操作;有 Git 的使用经验;Q:简单介绍下 React / Vue 的生命周期A:几个钩子函数基本能报出来(如果不讲究按顺序、按挂载/更新区分、能把单词用英文念出来并且念对的话),稍微深入一点问下各个阶段都做了什么,一半以上就“不太清楚”了。更有甚者我问React,对方回答 created、mounted,提醒之后还觉得自己没错的。Q:【React】定义一个组件时候,如何决定要用 Functional 还是 Class?A:简单的用 Function,复杂的用 Class。(不能算错吧……但也不能算答到点子上)追问怎么界定“复杂”,答不上来。Q:【React】HOC、(非)受控组件、shouldComponentUpdate、React 16 的变化A:不清楚、没接触过。Q:【Vue】介绍一下计算属性,和 data、methods、watch 的异同A:基本都能巴拉一些,说的大部分都对,但就是说不到最关键的“当且仅当计算属性依赖的 data 改变时才会自动计算”。Q:【Vue】为什么 SFC 里的 data 必须是一个函数返回的对象,而不能就只是一个对象?A:我承认这个问题有点小难,有一定的区分度,不是每个人都有关注过,但是官方文档有说明这一点,但凡看过的肯定有印象。即便没完整看过文档,在初次学习的过程中难道就不觉得奇怪吗?“学而不思”的人和“学而思”的人,区别还是挺大的。Q:CSS 选择器的权重A:经典问题了吧?背都能背出来吧?伪类、伪元素分不清楚,只知道内联、!important、ID、Class之间的顺序,加上其它的就懵了,而且只说谁大于谁,讲不出具体的计算方法。单层选择器比较还行,几个叠加起来就迷糊了。Q:JS 有哪几种原始类型A:基础题,能说上来几个,答不全,主要问题集中在 null 和 undefined 没考虑进去、对象和数组算不算原始类型、以及 Symbol很多人不知道。Q:ES 2015+ 有哪些新特性A:这题可以说的很多,根据应聘者的回答去展开,可以很容易地看出应聘者有没有系统地学习过这方面的东西,以及有没有持续地去跟进语言标准的发展。但这一题能回答的比较好的,寥寥无几,大部分是遇到问题然后零零散散现学的,不够全面、也不够深入,简单用过,但稍微问点细节就只有“尴尬而不失礼仪的微笑”了。Q:工程化工具的使用(Webpack、ESLint、Yarn、Git、……)A:基本都有所接触,但只是“用过”,算不上“会用”,一切顺利还好,真遇到问题了,立马就懵。Q:Node.jsA:写过 Demo 的水平。(比较初级)Q:未来 1~2 年的职业规划、下一步最想学的技术、最希望往什么方向发展、怎么看待XXX技术A:大部分人对自己没有一个明确的态度和规划。说白了就是还没从学校里出来,什么都等着别人来安排。通用技能有哪些(请看如下图)? ...

March 9, 2019 · 1 min · jiezi

《前端十年-我将一切告诉你》人物关系图

《前端十年-我把一切告诉你》人物关系和出场顺序出来了,不知道这个故事里有没有你?这样的公司架构跟很多公司也相似吧,不知道我经历过的东西是否你也在经历或者即将经历,还没写人物出场顺序都那么清晰的出来了,与其说是创作,不如说是讲述,你在我的生命里,充当着什么样的角色?忽然想起朴树的歌,我曾经像你像他像那野草野花,也平凡着,迷茫着……

February 28, 2019 · 1 min · jiezi

面试官问我:什么是JavaScript闭包,我该如何回答

闭包,有人说它是一种设计理念,有人说所有的函数都是闭包。到底什么是闭包?这个问题在面试是时候经常都会被问,很多小白一听就懵逼了,不知道如何回答好。这个问题也有很多朋友在公众号给李老师留言了,问题表达方式不一样,都是终归到一点,就是对闭包没有很清晰的理解。大家经常去网上找相关资料,但是对闭包的说法都是各种各样的,让大家对闭包的定义没有一个概念。所以今天我们来一起讲讲什么是闭包,帮助大家理解,今天的内容可以直接收藏起来。方便以后看。什么是闭包(Closure)简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。MDN 上面这么说:闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。这种官方的概念是比较难理解的,在面试的时候说出来也不是很专业,因为没办法有个具体的逻辑。我个人认为,理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。产生一个闭包创建闭包最常见方式,就是在一个函数内部创建另一个函数。下面例子中的 closure 就是一个闭包:闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域。闭包的注意事项.通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。从上述代码可以看到add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。最后通过 null 释放了 add5 和 add10 对闭包的引用。在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收; 如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。闭包只能取得包含函数中任何变量的最后一个值大家看一下上面这个代码,arr数组中包含了10个匿名函数,每个匿名函数都能访问外部函数的变量i,那么i是多少呢?当arrFunc执行完毕后,其作用域被销毁,但它的变量对象仍保存在内存中,得以被匿名访问,这时i的值为10。要想保存在循环过程中每一个i的值,需要在匿名函数外部再套用一个匿名函数,在这个匿名函数中定义另一个变量并且立即执行来保存i的值。这时最内部的匿名函数访问的是num的值,所以数组中10个匿名函数的返回值就是1-10。闭包中的this对象在上面这段代码中,obj.getName()()实际上是在全局作用域中调用了匿名函数,this指向了window。这里要理解函数名与函数功能是分割开的,不要认为函数在哪里,其内部的this就指向哪里。window才是匿名函数功能执行的环境。如果想使this指向外部函数的执行环境,可以这样改写:在闭包中,arguments与this也有相同的问题。下面的情况也要注意:obj.getName();这时getName()是在对象obj的环境中执行的,所以this指向obj。(obj.getName = obj.getName)赋值语句返回的是等号右边的值,在全局作用域中返回,所以(obj.getName = obj.getName)();的this指向全局。要把函数名和函数功能分割开来。内存泄漏闭包会引用包含函数的整个变量对象,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素无法被销毁。所以我们有必要在对这个元素操作完之后主动销毁。函数内部的定时器当函数内部的定时器引用了外部函数的变量对象时,该变量对象不会被销毁。闭包的应用应用闭包的主要场合是:设计私有的方法和变量。任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。私有变量包括函数的参数、局部变量和函数内定义的其他函数。把有权访问私有变量的公有方法称为特权方法(privileged method)。在这里,我们需要理解两个概念:模块模式(The Module Pattern):为单例创建私有变量和方法。单例(singleton):指的是只有一个实例的对象。JavaScript 一般以对象字面量的方式来创建一个单例对象。上面是普通模式创建的单例,下面使用模块模式创建单例:匿名函数最大的用途是创建闭包,并且还可以构建命名空间,以减少全局变量的使用。从而使用闭包模块化代码,减少全局变量的污染。在这段代码中函数 addEvent 和 removeEvent 都是局部变量,但我们可以通过全局变量 objEvent 使用它,这就大大减少了全局变量的使用,增强了网页的安全性。运用闭包的关键闭包引用外部函数变量对象中的值;在外部函数的外部调用闭包。闭包的缺陷闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。最后 来一道有关闭包的面试题下面代码中,标记 ? 的地方输出分别是什么?大家结合今天讲解的内容,思考一下答案,大家可以把答案发到留意上吧。好了,今天的讲解就那么多,如果你还有什么前端问题想提问的,或者你想李老师下次给大家讲什么内容,可以直接留意提问,说不定下次文章就会讲解了。如果你觉得这篇文章对你有帮助,请转发点赞支持一下!

February 19, 2019 · 1 min · jiezi

2019年前端学习路线

近两年来,前端开发工程师越来越火了,2019年已经到来了,很多准备入行前端开发工程师的小伙伴们,不知道准备得怎么样了呢?有的朋友在想方设法的学习,争取在年后的金三银四能靠实力找到一份满意的工作!还有的小伙伴很迷茫,想学前端,却没有方向!今天来给大家讲讲,在2019年,我们学习前端开发,如何才能高效学会前端开发?零基础起步首先,无论学任何一个技术,都是从零基础开始的,前端开发也是一样。做软件开发,是从事编程开发工作,必须先从语法基础开始学习,通过语法组成产品效果。前端开发的基础语法,由HTML+CSS+JavaScript组成,这是前端开发最基本的3个语言。网页布局基础:HTML+CSSHTML就是超文本标记语言,组成网页内容的最基本语言。你可以直接说他是网页的骨架,网页的图片、文字、视频、音频、程序都需要他引入到网页中体现。光是HTML做网页,只是有了内容,当然是远远不够的。因为只是HTML的话,只能用Table做布局才能勉强做出个成型的网页来。但是从Web2.0时代开始,都是盒子模型布局法了,也就是用DIV+CSS来实现布局了。CSS就是层叠样式表。通过样式属性来对标签进行布局规范,在不再使用table布局的时候,只要CSS样式对网页标签进行对应的布局实现才是正确的开发方式了。HTML(div)+CSS布局,是基础入门的基本步骤,在这个阶段,你需要学习的内容,包括有:1.标签语义化,SEO2.页面加载的流程和原理3.网页结构4.盒子模型(W3C盒子模型和IE盒子模型)5.CSS选择器6.CSS布局浮动、定位在刚刚开始的阶段,大家学习的布局方式基本都是以px为单位的静态布局方法。熟悉好布局方法,先给自己一个小目标,做一个简单的电商网页的基本结构出来,不用特效,不需要交互。浏览器脚本语言:JavaScriptJavaScript是我们学习前端开发中非常重要的一个内容,也是一个大家经常掉坑里的难点。JavaScript现在可以说是互联网时代使用率最高的脚本语言了,在网页中,所有的数据渲染,特效的交互都需要利用JavaScript,来影响浏览器的显示。JavaScript不只是开发网页特效和渲染数据的重要内容,在学习前端开发的后期,大量使用算法和框架的时候,对JavaScript基础的考验也是很多的。在基础阶段,我们学习JavaScript需要注意:1.基本关键字指令2.基本数据类型、数组3.函数4.面向对象编程5.原型链、闭包6.JSON7.Ajax8.DOM(文档对象模型 原生DOM操作)9.事件捕获、冒泡、代理10.常用函数方法11.ES5、6、7在JavaScript部分学习,主要还是要去理解好交互的原理,把原理分析清楚,真的理解语法,那写出多复杂的逻辑也是手到擒来。JavaScript经典类库jQuery说到学习JavaScript,很多小白同学肯定会很头痛他的原生写法。每次逻辑业务都需要手动写,也就是用一次就造一次轮子。觉得很麻烦。如果能简单一点就好了。因为JavaScript有可以封装的特性,所以在后面也出现了很多用JavaScript封装的类库、插件。比如说最经典的类库就是jQuery了。jQuery类库就是在类库里面封装好了很多JavaScript的事件方法。jQuery通过封装,减轻了遍历、对象选择等等很多的问题。把网页特效的实现变得简单化,通过调用方法就可以了。在学习jQuery的时候,需要重点认识的有:1.jQuery语法和JavaScript原生语法的差异2.Dom对象和jQuery对象3.jQuery的入口函数和JavaScript的入口函数的差异4.jQuery事件的执行逻辑。学习jQuery,最需要达到的效果就是能快速的完成网页的特效,比如说轮播图、手风琴菜单、旋转木马、放大镜等等这些特效。能完成一个电商网站的布局+特效开发是最基本的要求了。这些就是零基础学习必备的一些基本内容,在入门前端开发最基本需要掌握的东西,把基础理解好,才能为后面的学习做更多的准备。多终端进阶学习除了基础的PC端,目前移动端可以说是非常火的了。比PC端单一的网页不同,在移动端的技术可以应用到WEB-APP,小程序,Hybrid-App等等。Web-App也就是我们常见的浏览器(以及内置浏览器,比如微信)打开的大型移动端网页。比如我们常见的电商网站,功能性网站,管理网站,在布局和功能上都有APP的效果。做好Web-App开发,最基本的很多人肯定会说响应式布局,但是前端开发是又5种布局法的,除了出名的响应式,还有在移动端最重要的弹性布局法,也就是很多人头疼的rem布局。除了布局方法之外,在H5新特性和触屏事件和设备兼容性问题也是需要信手拈来。小程序这个也不用多说,现在可以说是非常火的,各大平台都有在做自己的小程序,各种砍价,抢票,电商,游戏都有运用。这个以微信小程序为例,主要是微信团队基于前端基础来做的封装语法,主要的还是ES语法。小程序目前很多公司都是招聘前端开发,目前还没有独立的小程序开发工程师,所以小程序可以说是前端工程师高薪就业的加分技能,换句话说就是成熟开发必备了。Hybrid-App又称混合式APP,可能听说的人很少,但是18年是越来越多人去开发了,这种是能直接产出下载到终端的APP的,在体验感上可以说已经具备传统APP的大部分功能了。这种开发门槛较低,也就是前端开发就可以完成。多数都是大包平台就能做,这个你可以后面了解一下。前端主流技术框架前面的都是基础东西,现在去就业前端开发,不是只靠个基础东西,搞个移动端页面就可以算成熟了。前端3大框架,VUE、Angular、React这3个可以说是现在非常火热的了。基础语法都可以写的前端,为什么还要框架?很多小白朋友是不懂什么是框架的,只听过jQuery这些东西,以为就是框架。或者认为框架就是加速开发,觉得这些库、插件就能完成框架的工作了。其实框架的出现,是改变前端地位的重要标志。最重要的表现,就是前后端分离,在前后端分离之前,很多后端开发都是又当爹又当妈的,效果不好效率也不高,我就是在后端出身,深知痛苦。现在的前端项目,比以前是更加复杂化、多样化了。项目复杂了,问题也多了。那框架到底解决了什么问题?解决重复引用外部js,以用jQuery开发为例,很多时候都是不能单一完成一个项目的,还需要引用很多的第三方插件和库,导致会一个项目引入很多外部JS文件。这样不仅让代码变得杂乱,而且很影响打开速度。但是用框架呢,以VUE为例,一般会和构建工具配合,然后就是一个入口文件就可以完成了,在运行时候就在入口引入一次,一劳永逸。使用组件化开发,组件是前端框架里非常强大的功能之一,它可以扩展你的HTML,封装可以重用的代码块,比如你的轮播图、tab切换、页面头部、页面底部等等。这种独立的组件具有了结构(html),表现(css)和行为(js)完整的功能,很大程度的节省了代码量,提高了代码的复用性。特别是团队合作的时候,可以很好的提高使用效率。减少开发周期,如果你觉得jQuery可以减少开发周期了,那其实框架可以比库更快。比如说使用jQuery开发的时候,很多时候是需要频繁去操作DOM,每次效果都要去查找DOM,这样就显得很繁琐了。使用框架的时候,很多功能都得到了封装,比如说很多指令都有数据绑定,数据格式化这些功能。这样更多时候,我们开发的时候只需要关注数据的逻辑就行了。最后这些也就是我们学习前端开发必备的一些知识点了。学习路线放一下给大家。前端开发学习不是单一的,内容比较多,同样应用的场景也非常多。如果你想从事前端开发工作,就要更急专心和努力,坚持方向不动摇!更多前端开发学习,关注公众号【前端研究所】每天更新更多学习教程和方法。

February 16, 2019 · 1 min · jiezi

前端基本功-常见概念(一)

前端基本功-常见概念(一) 点这里前端基本功-常见概念(二) 点这里前端基本功-常见概念(三) 点这里1.什么是原型链当一个引用类型继承另一个引用类型的属性和方法时候就会产生一个原型链。(js高级程序设计)所有 引用类型 都有一个 proto 属性的隐式原型所有 函数 都有一个 prototype属性的显式原型所有 引用类型的 隐式原型,指向其构造函数的 显式原型当试图得到一个属性或方法时,如果这个对象没有,那么会去他的__proto__(即它构造函数的prototype)中查找原型链 是针对构造函数的,比如我先创建了一个函数,然后通过一个变量new了这个函数,那么这个被new出来的函数就会继承创建出来的那个函数的属性,然后如果我访问new出来的这个函数的某个属性,但是我并没有在这个new出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。2.什么是闭包有权访问另一个函数作用域中的变量函数。(js高级程序设计)当一个函数存在对非自身作用域的变量的引用 就产生一个闭包有权访问另一个作用域的函数就是闭包闭包三点作用: 创建私有变量;延长变量生命周期;防止全局变量污染3.什么是作用域就是函数和变量的可访问范围。作用域 是针对变量的,特点是:先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。只有函数作用域和全局作用域(貌似还有个eval作用域),ES6中新增块级作用域那是后话函数外声明的变量为全局作用域,函数内可以使用函数内声明的变量为函数作用域,函数外不可以使用作用域链:一个自由变量一直往上寻找(定义时的)父级作用域内的变量的过程。自由变量:当前作用域没有定义的变量作用域什么时候生成的?页面加载–>创建window全局对象,并生成全局作用域–>然后生成执行上下文,预解析变量(变量提升),生成全局变量对象;$scope补充:花括号内声明的变量为块级作用域,只能内部使用,减少全局污染JavaScript是静态作用域,在对变量进行查询时,变量值由函数定义时的位置决定,和执行时的所处的作用域无关。4.什么是构造函数在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。5.什么是面向对象ECMAscript开发的两种模式:1.面向过程: 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了2.面向对象(OOP): 面向对象是以功能来划分问题,而不是步骤面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性的方法的对象。但是ECMAscript中没有类的概念!prototype是javascript实现与管理继承的一种机制,也是面向对象的设计思想,可以借助prototype属性,可以访问原型内部的属性和方法。通常使用构造函数,当构造函数被实列化后,所有的实例对象都可以访问构造函数的原型(prototype)成员,如果在原型中声明一个成员,所有的实列方法都可以共享它面向对象编程的基本思想是使用对象,类,继承,封装等基本概念来进行程序设计,达到数据结构化,简单抽象的目的(为什么面向对象)优点易维护采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的- 易扩展开发工作的重用性、继承性高,降低重复工作量。缩短了开发周期面向对象的三大特性:继承(子类继承父类,提高复用减少冗余),封装(数据的权限和保密),多态(同一接口的不同实现)面向对象离不开 类 和 实例 两个概念6.什么是响应式设计?响应式设计的基本原理是什么?响应式网站设计(Responsive Web design)是一个网站能够兼容多个终端,而不是为每一个终端做一个特定的版本。基本原理:是通过媒体查询检测不同的设备屏幕尺寸做处理。页面头部必须有meta声明的viewport。<meta name=’viewport’ content=”width=device-width, initial-scale=1. maximum-scale=1,user-scalable=no”>7.什么是高阶函数函数可以作为参数传递函数可以作为返回值输出8.什么是函数式编程?是指通过复合纯函数来构建软件的过程,它避免了共享的状态、易变的数据、以及副作用。函数式编程是声明式而不是命令式,并且应用程序状态通过纯函数流转。简单说,“函数式编程"是一种"编程范式”(programming paradigm),也就是如何编写程序的方法论它具有以下特性:闭包和高阶函数、惰性计算、递归、函数是"第一等公民"、只用"表达式"进一步了解9.css盒模型盒模型 : margin、padding、border、content标准盒模型 width = content 对应css属性 box-sizing:content-box怪异盒模型width = content + padding + border 对应css属性 box-sizing:border-box10.关于跨域关于跨域,有两个误区:✕ 动态请求就会有跨域的问题✔ 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境✕ 跨域就是请求发不出去了✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。同源策略具体限制些什么呢?不能向工作在不同源的的服务请求数据(client to server)但是script标签能够加载非同源的资源,不受同源策略的影响。无法获取不同源的document/cookie等BOM和DOM,可以说任何有关另外一个源的信息都无法得到 (client to client)跨域最常用的方法,应当属CORS如下图所示:只要浏览器检测到响应头带上了CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。CORS把请求分为两种,一种是简单请求,另一种是需要触发预检请求,这两者是相对的,怎样才算“不简单”?只要属于下面的其中一种就不是简单请求:(1)使用了除GET/POST/HEAD之外的请求方式,如PUT/DELETE(2)使用了除Content-Type/Accept等几个常用的http头这个时候就认为需要先发个预检请求,预检请求使用OPTIONS方式去检查当前请求是否安全代码里面只发了一个请求,但在控制台看到了两个请求,第一个是OPTIONS,服务端返回:详见阮一峰的跨域资源共享CORS详解第二种常用的跨域的方法是JSONPJSONP是利用了script标签能够跨域,如下代码所示:function updateList (data) { console.log(data);}$body.append(‘<script src=“http://otherdomain.com/request?callback=updateList"></script>’);代码先定义一个全局函数,然后把这个函数名通过callback参数添加到script标签的src,script的src就是需要跨域的请求,然后这个请求返回可执行的JS文本:// script响应返回的js内容为updateList([{ name: ‘hello’}]);由于它是一个js,并且已经定义了upldateList函数,所以能正常执行,并且跨域的数据通过传参得到。这就是JSONP的原理。小结跨域分为两种,一种是跨域请求,另一种访问跨域的页面,跨域请求可以通过CORS/JSONP等方法进行访问,跨域的页面主要通过postMesssage的方式。由于跨域请求不但能发出去还能带上cookie,所以要规避跨站请求伪造攻击的风险,特别是涉及到钱的那种请求。本节参考文章:我知道的跨域与安全11.http/httpsHTTP超文本传输协议(HTTP)是用于传输诸如HTML的超媒体文档的应用层协议。它被设计用于Web浏览器和Web服务器之间的通信,但它也可以用于其他目的。 HTTP遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。 HTTP是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。举个最常见的例子,用户登陆。用户输入账号,密码,采用HTTP的话,只要在代理服务器上做点手脚就可以拿到你的密码了。用户登陆 –> 代理服务器(做手脚)–> 实际授权服务器在发送端对密码进行加密?没用的,虽然别人不知道你原始密码是多少,但能够拿到加密后的账号密码,照样能登陆。HTTP是应用层协议,位于HTTP协议之下是传输协议TCP。TCP负责传输,HTTP则定义了数据如何进行包装。HTTPSHTTPS相对于HTTP有哪些不同呢?其实就是在HTTP跟TCP中间加多了一层加密层TLS/SSL。神马是TLS/SSL?通俗的讲,TLS、SSL其实是类似的东西,SSL是个加密套件,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密套件基本指的是TLS。传输加密的流程原先是应用层将数据直接给到TCP进行传输,现在改成应用层将数据给到TLS/SSL,将数据加密后,再给到TCP进行传输。HTTPS是如何加密数据的对安全或密码学基础有了解的同学,应该知道常见的加密手段。一般来说,加密分为对称加密、非对称加密(也叫公开密钥加密)HTTPS与HTTP的一些区别HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。HTTP协议运行在TCP之上,所有传输的内容都是明文,内容可能会被窃听。HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。不验证通信方的身份,通信方的身份有可能遭遇伪装。无法证明报文的完整性,报文有可能遭篡改。使用SPDY加快你的网站速度谷歌推行一种协议(HTTP 之下SSL之上[TCP]),可以算是HTTP2的前身,SPDY可以说是综合了HTTPS和HTTP两者优点于一体的传输协议,比如压缩数据(HEADER)多路复用优先级(可以给请求设置优先级)SPDY构成图:SPDY位于HTTP之下,TCP和SSL之上,这样可以轻松兼容老版本的HTTP协议(将HTTP1.x的内容封装成一种新的frame格式),同时可以使用已有的SSL功能。HTTP2HTTP2.0可以说是SPDY的升级版(其实原本也是基于SPDY设计的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,主要是以下两点HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPSHTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATEhttp2 新特性新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。多路复用(MultiPlexing),支持单个连接多次请求,即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。目前,有大多数网站已经启用HTTP2.0,例如YouTuBe,淘宝网等网站,利用chrome控制台可以查看是否启用H2:chrome=>Network=>Name栏右键=>√Protocol本节参考文章:简单比较 http https http2、HTTPS科普扫盲帖12.GET/POSTGET在游览器回退会刷新,而POST会再次提交请求GET请求会被游览器主动缓存,而POST不会,除非手动设置GET请求参数会被完整的保留在游览器历史记录里,而POST中的参数不会被保留GET产生的URL地址可以被收藏,而POST不可以GET参数通过URL传递,而POST放在Request bodyGET请求只能进行URL编码,而POST支持多种编码方式GET请求在URL中传递的参数是有长度限制的,而POST没有限制GET请求会把参数直接暴露在URL上,相比POST更安全对参数的数据类型,GET只接受ASCII字符,而POST没有限制1.请求参数:get参数附在URL后面?隔开,POST参数放在包体中2.大小限制:GET限制为2048字符,post无限制3.安全问题:GET参数暴露在URL中,不如POST安全4.浏览器历史记录:GET可以记录,POST无记录5.缓存:GET可被缓存,post无6.书签:GET可被收藏为书签,post不可7.数据类型:GET只能ASCII码,post无限制13.MVC/MVVMMVCMVC是一种设计模式,它将应用划分为3个部分:数据(模型)、展示层(视图)和用户交互层。结合一下下图,更能理解三者之间的关系。换句话说,一个事件的发生是这样的过程用户和应用交互控制器的事件处理器被触发控制器从模型中请求数据,并将其交给视图视图将数据呈现给用户MVVMMVVM是Model-View-ViewModel的缩写。mvvm是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。在之前的MVC中我们提到一个控制器对应一个视图,控制器用状态机进行管理,如果项目足够大的时候,状态机的代码量就变得非常臃肿,难以维护。性能问题,在MVC中我们大量的操作了DOM,而大量操作DOM会让页面渲染性能降低,加载速度变慢,影响用户体验。最后就是当Model频繁变化的时候,开发者就手动更新View,那么数据的维护就变得困难。为了减小工作量,节约时间,一个更适合前端开发的架构模式就显得非常重要,这时候MVVM模式在前端中的应用就应运而生。mvvm和mvc区别mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当 Model 频繁发生变化,开发者需要主动更新到View 。3种方式实现MVVMdefineProperty(VUE),脏检查(angular),原生js实现(发布订阅者模式)在Angular中实现数据的观测使用的是脏检查,就是在用户进行可能改变ViewModel的操作的时候,对比以前老的ViewModel然后做出改变。vue.js 则是采用 数据劫持 结合 发布者-订阅者模式 的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。本节参考文章:MVC/MVVM14.axios优点同时支持浏览器端和服务端的请求支持promise支持请求和和数据返回的拦截转换请求返回数据,自动转换JSON数据取消请求客户端防止xsrf攻击在node端支持设置代理内部一些针对具体项目环境的二次封装本节参考文章:axios优点15.普通函数/箭头函数1、当要求动态上下文的时候,就不能够使用箭头函数,箭头函数this的固定化2、在使用=>定义函数的时候,this的指向是定义时所在的对象,而不是使用时所在的对象3、不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误4、不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替5、不可以使用yield命令,因此箭头函数不能用作Generator函数class Animal { constructor(){ this.type = ‘animal’ } says(say) { setTimeout(function () { console.log(this.type + ‘says’ + say) },1000) }}var animal = new Animal()animal.says(‘hi’) // undefined says hi我们再来看看=>的情况class Animal() { constructor() { this.type = ‘animal’ } says(say) { setTimeout(() => { console.log(this.type + ’ says ’ + say) }, 1000) }}var animal = new Animal()animal.says(‘hi’) // animal says hi本节参考文章:前端面试之ES6篇 ...

January 13, 2019 · 1 min · jiezi

前端基本功-常见概念(二)

前端基本功-常见概念(一) 点这里前端基本功-常见概念(二) 点这里前端基本功-常见概念(三) 点这里1.let、const/varlet 是更完美的var,不是全局变量,具有块级函数作用域,大多数情况不会发生变量提升。const 定义常量值,不能够重新赋值,如果值是一个对象,可以改变对象里边的属性值var存在的问题var有作用域问题(会污染全局作用域)var可已重复声明var会变量提升预解释var不能定义常量let、const特性let、const不可以重复声明let、const不会声明到全局作用域上let、const不会预解释变量const做常量声明(一般常量名用大写)let声明的变量具有块级作用域let声明的变量不能通过window.变量名进行访问形如for(let x..)的循环是每次迭代都为x创建新的绑定下面是 var 带来的不合理场景var a = []for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i) }}a5 // 10在上述代码中,变量i是var声明的,在全局范围类都有效。所以每一次循环,新的i值都会覆盖旧值,导致最后输出都是10而如果对循环使用let语句的情况,那么每次迭代都是为x创建新的绑定代码如下var a = []for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i) }}a5 // 5重温一下闭包和立即函数两种方法闭包的方法function showNum(i) { return function () { console.log(i) }}var a = []for (var i = 0; i < 5; i++) { a[i] = showNum(i)}立即函数的方法var a = []for (var i = 0; i < 5; i++) { a[i] = (function (i) { return function () { console.log(i) } })(i)}a2本节参考文章:前端面试之ES6篇2.重排/重绘在讨论重排(回流)与重绘之前,我们要知道:浏览器使用流式布局模型 (Flow Based Layout)。浏览器会把HTML成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了Render Tree。有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。一句话:重排必将引起重绘,重绘不一定会引起重排。重排 (Reflow)当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为重排。会导致重排的操作:页面首次渲染浏览器窗口大小发生改变元素尺寸或位置发生改变元素内容变化(文字数量或图片大小等等)元素字体大小变化添加或者删除可见的DOM元素激活CSS伪类(例如::hover)查询某些属性或调用某些方法一些常用且会导致重排的属性和方法:clientWidth、clientHeight、clientTop、clientLeftoffsetWidth、offsetHeight、offsetTop、offsetLeftscrollWidth、scrollHeight、scrollTop、scrollLeftscrollIntoView()、scrollIntoViewIfNeeded()getComputedStyle()getBoundingClientRect()scrollTo()重绘 (Repaint)当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。性能影响回流比重绘的代价要更高。有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。现代浏览器会对频繁的回流或重绘操作进行优化:浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。当你访问以下属性或方法时,浏览器会立刻清空队列:clientWidth、clientHeight、clientTop、clientLeftoffsetWidth、offsetHeight、offsetTop、offsetLeftscrollWidth、scrollHeight、scrollTop、scrollLeftwidth、heightgetComputedStyle()getBoundingClientRect()因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。如何避免CSS避免使用table布局。尽可能在DOM树的最末端改变class。避免设置多层内联样式。将动画效果应用到position属性为absolute或fixed的元素上。避免使用CSS表达式(例如:calc())。JavaScript避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。本节参考文章:浏览器的回流与重绘 (Reflow & Repaint)3.函数节流(throttle)与函数去抖(debounce)Debounce:一部电梯停在某一个楼层,当有一个人进来后,20秒后自动关门,这20秒的等待期间,又一个人按了电梯进来,这20秒又重新计算,直到电梯关门那一刻才算是响应了事件。Throttle:好比一台自动的饮料机,按拿铁按钮,在出饮料的过程中,不管按多少这个按钮,都不会连续出饮料,中间按钮的响应会被忽略,必须要等这一杯的容量全部出完之后,再按拿铁按钮才会出下一杯。4.强缓存/协商缓存浏览器缓存分为强缓存和协商缓存,优先读取强制缓存。当客户端请求某个资源时,获取缓存的流程如下:先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,则直接从本地获取缓存资源,不会发请求到服务器;当强缓存没有命中时,客户端会发送请求到服务器,服务器通过另一些request header验证这个资源是否命中协商缓存,称为http再验证,如果命中,服务器将请求返回,但不返回资源,而是告诉客户端直接从缓存中获取,客户端收到返回后就会从缓存中获取资源;强缓存和协商缓存共同之处在于,如果命中缓存,服务器都不会返回资源;区别是,强缓存不对发送请求到服务器,但协商缓存会。当协商缓存也没命中时,服务器就会将资源发送回客户端。当 ctrl+f5 强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;当 f5 刷新网页时,跳过强缓存,但是会检查协商缓存;强缓存Expires(该字段是 http1.0 时的规范,值为一个绝对时间的 GMT 格式的时间字符串,代表缓存资源的过期时间)Cache-Control:max-age(该字段是 http1.1 的规范,强缓存利用其 max-age 值来判断缓存资源的最大生命周期,它的值单位为秒)协商缓存协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的Last-Modified,If-Modified-SinceLast-Modified 表示本地文件最后修改日期,浏览器会在request header加上If-Modified-Since(上次返回的Last-Modified的值),询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来但是如果在本地打开缓存文件,就会造成 Last-Modified 被修改,所以在 HTTP / 1.1 出现了 ETagETag、If-None-MatchEtag就像一个指纹,资源变化都会导致ETag变化,跟最后修改时间没有关系,ETag可以保证每一个资源是唯一的If-None-Match的header会将上次返回的Etag发送给服务器,询问该资源的Etag是否有更新,有变动就会发送新的资源回来ETag的优先级比Last-Modified更高一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);某些服务器不能精确的得到文件的最后修改时间。推荐必读:http协商缓存VS强缓存、浏览器缓存知识小结及应用、缓存(二)——浏览器缓存机制:强缓存、协商缓存5.原始类型 / 引用类型JavaScript中的内存分为栈内存和堆内存。栈内存和堆内存区别:栈内存运行效率比堆内存高,空间相对堆内存来说较小。区别:值类型属于不可变类型, 由于具有固定长度大小, 其地址和具体内容都存在与栈内存中而引用类型属于可变类型, 一个对象可以赋予多个属性及值,属性值又可以为一个新的引用对象。其地址存在栈内存,其具体内容存在堆内存中。6.cookie/tokentoken和cookie一样都是首次登陆时,由服务器下发,都是当交互时进行验证的功能,作用都是为无状态的HTTP提供的持久机制。token存在哪儿都行,localstorage或者cookie。token和cookie举例,token就是说你告诉我你是谁就可以。cookie 举例:服务员看你的身份证,给你一个编号,以后,进行任何操作,都出示编号后服务员去看查你是谁。token 举例:直接给服务员看自己身份证,服务器不需要去查看你是谁,不需要保存你的会话。当用户logout的时候,cookie和服务器的session都会注销;但是当logout时候token只是注销浏览器信息,不查库。token优势在于,token由于服务器端不存储会话,所以可扩展性强,token还可用于APP中。小结:Token 完全由应用管理,所以它可以避开同源策略Token 可以避免 CSRF 攻击Token 可以是无状态的,可以在多个服务间共享如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token,如果之上自己的那就无所谓了。 本节参考文章:cookie和token的五点区别推荐必读:前后端常见的几种鉴权方式7.cookie/sessionStorage/localStorage1.cookiecookie分为cookie机制和session机制(请大神判断正确性)Session: 是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中,通过在服务器端记录信息确定用户身份Cookie: 是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式,通过在客户端记录信息确定用户身份如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。cookie机制cookie可以通过设置domain属性值,可以不同二级域名下共享cookie,而Storage不可以,比如http://image.baidu.com的cookie http://map.baidu.com是可以访问的,前提是Cookie的domain设置为.http://baidu.com,而Storage是不可以的session机制当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识—称为session id,如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。比较session 在服务器端,cookie 在客户端(浏览器)session保存在服务器,客户端不知道其中的信息;反之,cookie保存在客户端,服务器能够知道其中的信息session会在一定时间内保存在服务器上,当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookiesession中保存的是对象,cookie中保存的是字符串cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。用户验证这种场合一般会用 session用户验证这种场合一般会用 session,因此,维持一个会话的核心就是客户端的唯一标识,即 session idsession 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到,而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的JavaScript原生的用法。Cookie 以名/值对形式存储例如username=John Doe,这里的数据是string类型,如要是其他格式注意进行格式转换。JavaScript 可以使用 document.cookie 属性来创建 、读取、及删除 cookie。JavaScript 中,创建 cookie 如下所示:document.cookie=“username=John Doe”;您还可以为 cookie 添加一个过期时间(以 UTC 或 GMT 时间)。默认情况下,cookie 在浏览器关闭时删除:document.cookie=“username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 GMT”;您可以使用 path 参数告诉浏览器 cookie 的路径。默认情况下,cookie 属于当前页面。document.cookie=“username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 GMT; path=/";设置cookiefunction setCookie(cname,cvalue,exdays){ var SetTime = new Date(); //设置过期时间 SetTime.setTime(SetTime.getTime()+(exdays2460601000)); //设置过期时间 var expires = “expires="+SetTime.toGMTString(); //设置过期时间 document.cookie = cname + “=” + cvalue + “; " + expires; //创建一个cookie}读取cookiefunction getCookie(c_name){if (document.cookie.length>0) { c_start=document.cookie.indexOf(c_name + “=”) if (c_start!=-1){ c_start=c_start + c_name.length+1 c_end=document.cookie.indexOf(”;",c_start) if (c_end==-1) c_end=document.cookie.length return unescape(document.cookie.substring(c_start,c_end)) } }return “"}删除cookie将cookie的有效时间改成昨天。使用jquery.cookies.2.2.0.min.js插件添加/修改cookie并设定过期时间:$.cookies.set(‘cookie_id’, ‘cookie_value’, { hoursToLive: 10 });这里设置的是过期时间是10小时, 还可以这样设置过期时间:expireDate = new Date();expireDate.setTime( expireDate.getTime() + ( 10 * 60 * 60 * 1000 ) );$.cookies.set(‘cookie_id’, ‘cookie_value’, {expiresAt:expireDate});获取cookie$.cookies.get(‘cookie_id’);删除cookie$.cookies.del(‘cookie_id’);2.Storage:localStorage、sessionStorage大小:官方建议是5M存储空间类型:只能操作字符串,在存储之前应该使用JSON.stringfy()方法先进行一步安全转换字符串,取值时再用JSON.parse()方法再转换一次存储的内容: 数组,图片,json,样式,脚本。。。(只要是能序列化成字符串的内容都可以存储)区别:sessionStorage将数据临时存储在session中,浏览器关闭,数据随之消失,localStorage将数据存储在本地,理论上来说数据永远不会消失,除非人为删除注意:数据是明文存储,毫无隐私性可言,绝对不能用于存储基础操作API保存数据localStorage.setItem( key, value );sessionStorage.setItem(keyName,value); // 将value存储到key字段中//或者sessionStorage.keyName=‘value’;读取数据localStorage.getItem( key );sessionStorage.getItem(keyName); //获取指定key的本地存储的值//或者var keyName=sessionStorage.key;删除单个数据localStorage.removeItem( key );sessionStorage.removeItem( key );删除全部数据localStorage.clear( );sessionStorage.clear( );获取索引的keylocalStorage.key( index );sessionStorage.key( index );监听storage事件可以通过监听 window 对象的 storage 事件并指定其事件处理函数,当页面中对 localStorage 或 sessionStorage 进行修改时,则会触发对应的处理函数window.addEventListener(‘storage’,function(e){ console.log(‘key=’+e.key+’,oldValue=’+e.oldValue+’,newValue=’+e.newValue);})localstorage是浏览器多个标签共用的存储空间,可以用来实现多标签之间的通信(ps:session是会话级的存储空间,每个标签页都是单独的触发事件的时间对象(e 参数值)有几个属性:key : 键值。oldValue : 被修改前的值。newValue : 被修改后的值。url : 页面url。storageArea : 被修改的 storage 对象。3.对比共同点:都是保存在浏览器端、且同源的,都受同源策略的制约。区别:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的本节参考文章:缓存(三)——数据存储…其他阅读:关于Cookie、session和Web Storage8.js事件1.事件事件指可以被 JavaScript 侦测到的行为。即鼠标点击、页面或图像载入、鼠标悬浮于页面的某个热点之上、在表单中选取输入框、确认表单、键盘按键等操作。事件通常与函数配合使用,当事件发生时函数才会执行。事件名称:click/mouseover/blur(“不带on”)事件处理程序(事件侦听器):响应某个事件的函数,名称为:onclick/onmouseove/onblur,例如<button onclick=“alert(‘hello’)"></button>2.DOM事件模型:冒泡和捕获冒泡:往上捕获:向下3.事件流事件流指从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。DOM2级事件规定的事件流包括三个阶段:(1)事件捕获阶段(2)处于目标阶段(3)事件冒泡阶段。当事件发生时,最先得到通知的是window,然后是document,由上至下逐级依次而入,直到真正触发事件的那个元素(目标元素)为止,这个过程就是捕获。接下来,事件会从目标元素开始起泡,由下至上逐级依次传播,直到window对象为止,这个过程就是冒泡。所以捕获比冒泡先执行。希望注册在DOM元素上的事件处理程序在捕获阶段还是在冒泡阶段触发,取决于 addEventListener() 方法的第三个参数为 true 还是 false 。其中DOM3级事件在DOM2的基础之上添加了更多的事件类型。描述DOM事件捕获的具体流程window–>document–>html(document.documentElement)–>body(document.body)…4.DOM级别/DOM事件DOM级别一共可以分为4个级别:DOM0级,DOM1级,DOM2级和DOM3级,而DOM事件分为3个级别:DOM0级事件处理,DOM2级事件处理和DOM3级事件处理。其中1级DOM标准中并没有定义事件相关的内容,所以没有所谓的1级DOM事件模型。DOM0:element.onclick = function(){}DOM2:element.addEventlistenter(‘click’,function(){},flase)DOM3:element.addEventlistenter(‘keyup’,function(){},flase)HTML事件处理程序<button onclick=“alert(‘hello’)"></button><button onclick=“doSomething()"></button><button onclick=“try{doSomething();}catch(err){}"></button>DOM0级事件处理程序 btn.onclick=function(){ alert(“hello”); }btn.onclick = null;//来删除指定的事件处理程序。如果我们尝试给事件添加两个事件,如:<button id=“btn”>点击</button> <script> var btn=document.getElementById(“btn”); btn.onclick=function(){ alert(“hello”); } btn.onclick=function(){ alert(“hello again”); }</script>输出,hello again,很明显,第一个事件函数被第二个事件函数给覆盖掉了, 所以,DOM0级事件处理程序不能添加多个,也不能控制事件流到底是捕获还是冒泡。DOM2级事件处理程序addEventListener() —添加事件侦听器函数均有3个参数, 第一个参数是要处理的事件名(不带on前缀的才是事件名) 第二个参数是作为事件处理程序的函数 第三个参数是一个boolean值,默认false表示使用冒泡机制,true表示捕获机制。<button id=“btn”>点击</button> <script> var btn=document.getElementById(“btn”); btn.addEventListener(‘click’,hello,false); btn.addEventListener(‘click’,helloagain,false); function hello(){ alert(“hello”); } function helloagain(){ alert(“hello again”); }</script> removeEventListener() //删除事件侦听器可以绑定多个事件处理程序,但是注意,如果定义了一摸一样时监听方法,是会发生覆盖的,即同样的事件和事件流机制下相同方法只会触发一次,事件触发的顺序是添加的顺序// 为了兼容IE浏览器和标准的浏览器,我们需要编写通用的方法来处理:var EventUtil = { addHandler: function (element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, removeHandler: function (element, type, handler) { if (element.removeEventListener()) { element.removeEventListener(type, handler, false); } else if (element.detachEvent) { element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } }};5.事件对象事件对象是用来记录一些事件发生时的相关信息的对象,但事件对象只有事件发生时才会产生,并且只能是事件处理函数内部访问,在所有事件处理函数运行结束后,事件对象就被销毁!//currentTarget、eventPhase 一个例子:<button id=“btn”>点击</button> <script> var btn=document.getElementById(“btn”); btn.ddEventListener(‘click’, doCurrent, true); // 判断事件的属性 function doCurrent(event) { //获取当前事件触发的div var target = event.currentTarget; //通过判断事件的event.eventPhase属性返回事件传播的当前阶段 //1:捕获阶段、2:正常事件派发和3:起泡阶段。 //得到当前阶段和id值并输出 var msg = (event.eventPhase == 1 ? ‘捕获阶段:’ : ‘冒泡阶段:’)+ target.attributes[“id”].value;; console.log(msg); }</script>当然,事件对象也存在一定的兼容性问题,在IE8及以前本版之中,通过设置属性注册事件处理程序时,调用的时候并未传递事件对象,需要通过全局对象window.event来获取。解决方法如下:function getEvent(event) { event = event || window.event;}在IE浏览器上面是event事件是没有preventDefault()这个属性的,所以在IE上,我们需要设置的属性是returnValuewindow.event.returnValue=falsestopPropagation()也是,所以需要设置cancelBubble,cancelBubble是IE事件对象的一个属性,设置这个属性为true能阻止事件进一步传播。event.cancelBubble=true常见属性解析event.preventDefault()阻止默认行为event.stopPropagation()阻止冒泡。使用了stopPropagation()之后,事件就不能进一步传播了,同时如果是同一个div上有捕获和冒泡两种事件监听,在捕获阶段传播阻止后冒泡阶段事件监听也不会触发。event.stopImmediatePropagation()使用了stopImmediatePropagation()之后,绑定的后续事件监听都会忽略。event.currentTarget当前绑定的事件event.target事件代理时 点击的元素关于捕获和冒泡:理解 addEventListener、捕获和冒泡6.自定义事件jq // 添加一个适当的事件监听器$(’#foo’).on(‘custom’, function(event, param1, param2) { alert(param1 + “\n” + param2);});$(’#foo’).trigger(‘custom’, [‘Custom’, ‘Event’]);原生Event:var eve = new Event(‘custome’)element.addEventListenter(‘custome’,function(){ console.log(‘custome’)})element.dispatchEvent(eve)原生CustomEvent// 添加一个适当的事件监听器obj.addEventListener(“custom”, function(e) { console.log(JSON.stringify(e.detail)); })// 创建并分发事件var event = new CustomEvent(“custom”, {“detail”:{“Custom”:true}});obj.dispatchEvent(event)本节参考文章:一个能拖动,能调整大小,能更新bind值的vue指令-vuedragx7.事件委托(代理)事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。案例一: <button id=“btnAdd”>添加</button> <ul id=“ulList”> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var btnAdd = document.getElementById(‘btnAdd’); var ulList = document.getElementById(‘ulList’); var list = document.getElementsByTagName(’li’); var num = 3; btnAdd.onclick = function () { num++; var li = document.createElement(’li’); li.innerHTML = num; ulList.appendChild(li) } for (i = 0; i < list.length; i++) { list[i].onclick = function(){ alert(this.innerHTML); } } </script> //例子说明,我们为ul添加新的li, //其中对li标签元素绑定了click事件, //但是发现,后增加的元素没有办法触发我们的click事件。解决方法:事件委托 <button id=“btnAdd”>添加</button> <ul id=“ulList”> <li class=“class-1”>1</li> <li class=“class-1”>2</li> <li class=“class-1”>3</li> </ul> <script> var btnAdd = document.getElementById(‘btnAdd’); var ulList = document.getElementById(‘ulList’); var num = 3; ulList.onclick = function(event){ var event = event || window.event; var target = event.target || event.srcElement; // if (target.matches(’li.class-1’)) //#ulList 元素下的 li 元素(并且它的 class 为 class-1) if(target.nodeName.toLowerCase() == ’li’){ alert(target.innerHTML); } } btnAdd.onclick = function () { num++; var li = document.createElement(’li’); li.innerHTML = num; ulList.appendChild(li); } </script>案例二:点击“添加”按钮添加一个按钮,点击添加的按钮移除这个按钮<div class=“wrap” id=“wrap”> <div class=“btn” data-type=“btn” data-feat=“add”>添加</div> <div class=“btn” data-type=“btn” data-feat=“delete”>绘画</div> <div class=“btn” data-type=“btn” data-feat=“delete”>散步</div> <div class=“btn” data-type=“btn” data-feat=“delete”>静坐</div></div>document.getElementById(‘wrap’).addEventListener(‘click’, function(e){ var target = e.target; while(target !== this){ var type = target.dataset.type; if(type == ‘btn’){ var feat = target.dataset.feat; switch(feat){ case ‘add’: this.innerHTML += ‘<div class=“btn” data-type=“btn” data-feat=“delete”>静坐</div>’ return; case ‘delete’: target.parentNode.removeChild(target); return; } } target = target.parentNode; }}, false);适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。推荐阅读:JavaScript 事件委托详解本节参考文章:前端小知识–JavaScript事件流9.link / @import两者都是外部引用 CSS 的方式,但是存在一定的区别:link是XHTML标签,除了能够加载CSS,还可以定义RSS等其他事务;而@import属于CSS范畴,只可以加载CSS。link引用CSS时,在页面载入时同时加载;@import需要页面完全载入以后再加载。link是XHTML标签,无兼容问题;@import则是在CSS2.1提出的,低版本的浏览器不支持。link方式的样式的权重 高于@import的权重.link支持使用Javascript控制DOM改变样式;而@import不支持。本节参考文章:前端面试题-url、href、src10.异步编程的实现方式1.回调函数优点:简单、容易理解缺点:不利于维护,代码耦合高2.事件监听(采用时间驱动模式,取决于某个事件是否发生):优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数缺点:事件驱动型,流程不够清晰3.发布/订阅(观察者模式)类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者4.Promise对象优点:可以利用then方法,进行链式写法;可以书写错误时的回调函数;缺点:编写和理解,相对比较难5.Generator函数优点:函数体内外的数据交换、错误处理机制缺点:流程管理不方便6.async函数优点:内置执行器、更好的语义、更广的适用性、返回的是Promise、结构清晰。缺点:错误处理机制11.documen.write/ innerHTML的区别document.write只能重绘整个页面innerHTML可以重绘页面的一部分12.isPrototypeOf()/instanceofisPrototypeOf() 与 instanceof 运算符不同。在表达式 “object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 本身。isPrototypeOf() 方法允许你检查一个对象是否存在于另一个对象的原型链上。function Foo() {}function Bar() {}function Baz() {}Bar.prototype = Object.create(Foo.prototype);Baz.prototype = Object.create(Bar.prototype);var baz = new Baz();//isPrototypeOfconsole.log(Baz.prototype.isPrototypeOf(baz)); // trueconsole.log(Bar.prototype.isPrototypeOf(baz)); // trueconsole.log(Foo.prototype.isPrototypeOf(baz)); // trueconsole.log(Object.prototype.isPrototypeOf(baz)); // trueif (Foo.prototype.isPrototypeOf(baz)) { // do something safe}//instanceofconsole.log(baz instanceof Baz); // trueconsole.log(baz instanceof Bar); // trueconsole.log(baz instanceof Foo); // trueconsole.log(baz instanceof Object); // truevar obj1 = { name: ’esw’}var obj2 = Object.create(obj1)// isPrototypeOf()方法Object.prototype.isPrototypeOf(obj1) // trueobj1.isPrototypeOf(obj2) // trueObject.prototype.isPrototypeOf(obj2) // true13.constructor、proto__与prototype在javascript中我们每创建一个对象,该对象都会获得一个__proto__属性(该属性是个对象),该属性指向创建该对象的构造函数的原型即prototype,同时__proto__对象有一个constructor属性指向该构造函数。这里我们需要注意的是只有函数才有prototype,每个对象(函数也是对象)都有__proto,Object本身是个构造函数。举例来说:var obj = new Object()// 也可以使用对象字面量创建,但使用Object.create()情况会不一样// Object本身是个构造函数Object instanceof Function // trueobj.proto === Object.prototype // trueobj.proto.constructor === Object // true// 我们一般习惯这样写obj.constructor === Object // true当我们访问obj.constructor的时候,obj本身是没有constructor属性的,但属性访问会沿着__proto__向上查找,即在obj.__proto__里面寻找constructor属性,如果找到了就返回值,如果未找到则继续向上查找直到obj.proto.proto…(proto) === null为止,没有找到则返回undefined。这样由__proto__构成的一条查找属性的线称为‘原型链’。本节参考文章:重新认识javascript对象(三)——原型及原型链、一篇文章带你进一步了解object属性14.浅拷贝/深拷贝1.浅拷贝只能复制值类型的属性。对于引用类型的属性,复制前后的两个对象指向同一内存地址,操作其中一个对象的引用类型属性,另一个对象也会相应发生改变;也就是说只有改变值类型的属性两个对象才不会相互影响。2.深拷贝不仅可以复制值类型的属性,还可以复制引用类型的属性,无论两个对象怎么改变都不会相互影响。浅复制var obj = { a : 1, b: { c: 2 }}// 浅复制function lowerClone(obj){ var newObj=obj.constructor === Array ? [] : {}; for(var i in obj){ newObj[i]=obj[i] } return newObj;}var objClone = lowerClone(obj)objClone.a // 1obj.a // 1objClone.a = 100// 改变复制对象的值类型属性,值类型属性的值不变obj.a // 1objClone.b.c = 200// 改变复制对象的引用类型的属性,引用类型的属性值改变obj.b.c //200深复制var obj = { a : 1, b: { c: 2 }}function deepClone(obj){ if( typeof obj != ‘object’){ return obj; } var newObj=obj.constructor === Array ? [] : {}; for(var i in obj){ newObj[i]=deepClone(obj[i]); } return newObj;}var objClone = deepClone(obj)objClone.a // 1obj.a // 1objClone.a = 100// 改变复制对象的值类型属性,值类型属性的值不变obj.a // 1objClone.b.c = 200// 改变复制对象的引用类型的属性,引用类型的属性值不变obj.b.c // 2本节参考文章:javascript浅复制与深复制15.apply/call/bindapply 、 call 、bind 三者都是用来改变函数的this对象的指向的; apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文; apply 、 call 、bind 三者都可以利用后续参数传参; bind是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。call apply 的区别是他们指定参数的方式不同。案例function fn(a,b){ console.log(this); console.log(a); console.log(b);}// bind(this,args…)bf = fn.bind(“Bind this”,10); // 没有任何输出,也就是说没有执行这个函数bf(); // “Bind this”,10,undefinedbf(20);// “Bind this”,10,20// 原函数不受影响fn(1,2); //window, 1,2bf2 = fn.bind(“Bind this”,1,2);bf2(); // “Bind this”,1,2// call(this,args…)fn.call(“Call this”,1) // “Call this”,1,undefinedfn.call(“Call this”,1,2) // “Call this”,1,2// apply(this,[args])fn.apply(“Apply this”,[1]) // “Apply this”,1,undefinedfn.apply(“Apply this”,[1,2]) // “Apply this”,1,2 ...

January 13, 2019 · 5 min · jiezi

2019年如何成为一个成熟的前端开发者?

2019年一眨眼就到了,很多想入行前端开发的小白朋友们,不知道在新的一年实现了没有呢?最近有个小伙伴来问,问我怎么样才能成为一名成熟的前端开发?是的,成熟的专业开发工程师现在是越来越吃香了,零基础小白就业越来越难了。如何成为一名成熟前端开发?首先,成为一名成熟的开发者,首先必是一位有扎实的基础开发。所以最基本的一些HTML、CSS、JavaScript这些基础的语法,就不详细说了。最基本的网页布局还是要简单掌握的。除了基础的语法,还有很多需要注重去理解的地方。扎实的JavaScript基础在前端开发里,最讲究的还是在JavaScript里,基础的语法,能运用很简单。但是说成熟开发,那必然是对JavaScript是熟练掌握和有深入的理解了。说到要熟练掌握JavaScript,那必然是要掌握闭包,ES678,原型链,这一系列的了。除了扎实的JS基础,还有就是要掌握符合目前市场需求的技术点了。多终端开发除了基础的PC端,目前移动端可以说是非常火的了。比PC端单一的网页不同,在移动端的技术可以应用到WEB-APP,小程序,Hybrid-App等等。WEBapp,也就是我们常见的浏览器(以及内置浏览器,比如微信)打开的大型移动端网页。比如我们常见的电商网站,功能性网站,管理网站,营销网页等等,在布局和功能上都有APP的效果。做好WEB-APP开发,最基本的很多人肯定会说响应式布局,但是前端开发是又5种布局法的,除了出名的响应式,还有在移动端最重要的弹性布局法,也就是很多人头疼的rem布局。除了布局方法之外,在H5新特性和触屏事件和设备兼容性问题也是需要信手拈来。小程序,这个也不用多说,现在可以说是非常火的,各大平台都有在做自己的小程序,各种砍价,抢票,电商,游戏都有运用。这个以微信小程序为例,主要是微信团队基于前端基础来做的封装语法,主要的还是ES语法。小程序目前很多公司都是招聘前端开发,目前还没有独立的小程序开发工程师,所以小程序可以说是前端工程师高薪就业的加分技能,换句话说就是成熟开发必备了。Hybrid-App,又称混合式APP,可能听说的人很少,但是18年是越来越多人去开发了,这种是能直接产出下载到终端的APP的,在体验感上可以说已经具备传统APP的大部分功能了。这种开发门槛较低,也就是前端开发就可以完成。多数都是大包平台就能做,有很好的前端基础就可以做了。前端主流技术框架前面的都是基础东西,现在去就业前端开发,不是只靠个基础东西,搞个移动端页面就可以算成熟了。前端3大框架,VUE、Angular、React这3个可以说是现在非常火热的了。基础语法都可以写的前端,为什么还要框架?很多小白朋友是不懂什么是框架的,只听过jQuery这些东西,以为就是框架。或者认为框架就是加速开发,觉得这些库、插件就能完成框架的工作了。其实框架的出现,是改变前端地位的重要标志。最重要的表现,就是前后端分离,在前后端分离之前,很多后端开发都是又当爹又当妈的,效果不好效率也不高,我就是在后端出身,深知痛苦。现在的前端项目,比以前是更加复杂化、多样化了。项目复杂了,问题也多了。那框架到底解决了什么问题?解决重复引用外部js,以用jQuery开发为例,很多时候都是不能单一完成一个项目的,还需要引用很多的第三方插件和库,导致会一个项目引入很多外部JS文件。这样不仅让代码变得杂乱,而且很影响打开速度。但是用框架呢,以VUE为例,一般会和构建工具配合,然后就是一个入口文件就可以完成了,在运行时候就在入口引入一次,一劳永逸。使用组件化开发,组件是前端框架里非常强大的功能之一,它可以扩展你的HTML,封装可以重用的代码块,比如你的轮播图、tab切换、页面头部、页面底部等等。这种独立的组件具有了结构(html),表现(css)和行为(js)完整的功能,很大程度的节省了代码量,提高了代码的复用性。特别是团队合作的时候,可以很好的提高使用效率。减少开发周期,如果你觉得jQuery可以减少开发周期了,那其实框架可以比库更快。比如说使用jQuery开发的时候,很多时候是需要频繁去操作DOM,每次效果都要去查找DOM,这样就显得很繁琐了。使用框架的时候,很多功能都得到了封装,比如说很多指令都有数据绑定,数据格式化这些功能。这样更多时候,我们开发的时候只需要关注数据的逻辑就行了。没有真正的成熟你会提出成熟,是因为想给自己一个标准,但是做技术工作,最重要还是市场的标准。前端技术是日新月异的,基本每年都是会有新的概念,新的架构,新的应用产品,新的交互体检。这些都是有不确定性的。做技术没有真正的成熟可言,更多的还是不断学习,持续进步。把技术不断做到专,做到精,才能在当前时代成为“成熟”。送书啦!免费送书!马上扫码来参加吧!

January 9, 2019 · 1 min · jiezi

【连载】前端个人文章整理-从基础到入门

个人前端文章整理从最开始萌生写文章的想法,到着手开始写,再到现在已经一年的时间了,由于工作比较忙,更新缓慢,后面还是会继更新,现将已经写好的文章整理一个目录,方便更多的小伙伴去学习。JavaScript 基础知识 - 入门篇(一)JavaScript 基础知识 - 入门篇(二)JavaScript 基础知识 - DOM篇(一)JavaScript 基础知识 - DOM篇(二)JavaScript 基础知识 - BOM篇JavaScript 进阶知识 - 特效篇(一)JavaScript 进阶知识 - 特效篇(二)JavaScript 进阶知识 - Ajax篇jQuery 入门详解(一)jQuery 入门详解(二)HTML5 入门详解CSS3 入门详解(一)CSS3 入门详解(二)three.js 入门详解(一)three.js 入门详解(二)—————————————- 未完待续—————————————- 1. JS 基础篇1.1 入门基础概念本篇文章主要讲的是js最基础的知识点,从变量说起,到什么是数组,什么是函数…JavaScript 基础知识 - 入门篇(一)JavaScript 基础知识 - 入门篇(二)1. 初识JS 1.1 什么是JS语言 1.2 JS的三个组成部分 1.3 script 标签 1.4 js中输入输出语句 1.5 注释2. 变量 2.1 变量的声明与赋值 2.2 变量的命名规则与规范 2.3 交换两个变量的值3. 数据类型 3.1 如何查看数据类型 3.2 Number 类型 3.3 String 类型 3.4. boolean 类型 3.5 undefined类型与null类型4. 简单数据类型转换 4.1 转字符串类型 4.2 转数值类型 4.3 转布尔类型5. JS小数运算精度丢失 5.1 JS数字精度丢失的一些典型问题 5.2 JS数字丢失精度的原因 5.3 JS数字丢失精度的解决方案6. 运算符 6.1 一元运算符 6.2 逻辑运算符 6.3 运算符的优先级7. 选择语句 7.1 if..else语句 7.2 switch..case 7.3 三元运算符8.循环语句 8.1 while 循环 8.2 do..while 循环 8.3 for 循环 8.4 break 和 continue 8.5 循环语句练习9. 数组 9.1 创建数组 9.2 数组的下标与长度 9.3 数组的赋值与取值 9.4 数组的遍历 9.5 数组综合练习10. 冒泡排序 10.1 冒泡排序的思路 10.2 按性能等级冒泡排序分3个等级11. 函数 11.1 函数的基础知识 11.2 函数的声明与调用 12.3 声明函数的两种方式 11.4 函数的参数 11.5 函数的返回值 11.6 函数三要素 11.7 文档注释 11.8 函数综合练习 11.9 函数的作用域 11.10 预解析 11.11 递归函数 11.12 回调函数12. 对象 12.1 对象的基本概念 12.2 创建对象 12.2.1 通过构造函数创建 12.2.2 通过对象字面量 12.2.3 关于 this 12.3 操作对象的属性 12.3.1 “.” 语法 12.3.2 “[]“语法 12.3.3 两种方法的区别 12.4 遍历对象 12.5 查看对象的类型 12.6 批量创建对象 12.7 值类型与引用类型 12.8 基本包装类型 12.9 伪数组(类数组) 12.10 arguments 对象 12.11 JSON 对象13. 内置对象 13.1 Math 对象 13.2 Date对象 13.2.1 创建一个日期对象 13.2.2 日期格式化 13.2.3 获取日期的指定部分 13.2.4 时间戳 13.3 Array 对象 13.3.1 数组转换成字符串 join() 13.3.2 数组的增删操作 13.3.3 数组的翻转与排序 13.3.4 数组的拼接与截取 13.3.5 数组查找元素 13.3.6 清空数组 13.3.7 数组的综合练习 13.4 String 对象 13.4.1 字符串大小写转换的方法 13.4.2 indexOf 查找指定字符串 13.4.3 trim 去除空白 13.4.4 slice 截取字符串 13.4.5 substring 截取字符串 13.4.6 字符串的 substr方法 13.4.7 match 查找字符串 13.4.8 replace 替换字符串 13.4.9 split 切割字符串转为数组 13.5 Array对象 与 String对象综合练习1.2 DOM操作认识什么是DOM,通过什么样的方法去对页面元素进行增删改查…JavaScript 基础知识 - DOM篇(一)JavaScript 基础知识 - DOM篇(二)1. DOM 基本概念2. 查找 DOM 对象 2.1 根据id获取元素 2.2 根据标签名获取元素3. 注册事件 3.1 事件三要素 3.2 注册事件的两种方式 3.3 鼠标点击事件 3.4 鼠标经过、离开事件 3.5 表单获得、失去焦点事件 3.6 其他触发事件汇总4. 优雅降级和渐进增强5. 属性操作 5.1 普通标签属性 5.2 表单属性操作 5.3 标签自定义属性 attribute系列 5.4 排他思想(tab栏的主要思想) 5.5 tab 栏切换6. 标签内容 6.1 innerHTML 6.2 innerText 6.3 innerText 的兼容性问题7. 节点操作 7.1 节点的属性 7.2 节点层次 7.2.1 孩子节点 7.2.2 兄弟节点 7.2.3 父节点8. 样式操作 8.1 样式操作注意点 8.2 样式操作案例9. 动态创建元素 9.1 克隆节点 9.2 添加节点 9.2.1 appendChild 9.2.2 insertBefore 9.3 创建节点 9.3.1 document.write(基本不用) 9.3.2 innerHTML 9.3.3 createElement 9.4 删除节点 9.5 动态创建元素综合练习1.3 BOM操作本篇最主要的知识点就是“定时器”,后面不管是动画还是轮播图特效都会用到定时器。JavaScript 基础知识 - BOM篇1. BOM 基本概念2. window 对象 2.1 window.onload 2.2 window.open 2.3 window.close3. 定时器 3.1 延时定时器 3.2 间歇定时器 2.3 定时器综合练习4. Location对象 4.1 常用的属性和方法5. Navigator 对象6. Screen 对象7. History 对象8. javascript 弹框9. javascript Cookie2. JS 进阶篇2.1 原生 js 特效通过原生js实现动画,再去拓展一些特效:“轮播图”、“手风琴”…JavaScript 进阶知识 - 特效篇(一)JavaScript 进阶知识 - 特效篇(二)1. offset 系列 1.1 offsetWidth 和 offsetHeight 1.2 offsetParent 1.3 offsetLeft与offsetTop2. 匀速动画框架 2.1 匀速动画初体验 2.2 匀速动画函数封装3. 轮播图 3.1 简单轮播图 3.2 左右焦点轮播图 3.3 无缝轮播图 3.4 完整版轮播图4. 缓动动画框架 4.1 缓动动画初体验 4.2 缓动动画函数封装 4.3 获取元素计算后的样式 4.4 缓动动画修改多个样式 4.5 缓动动画修复定时器bug 4.6 缓动动画兼容其它样式属性 4.7 缓动动画添加回调函数5. 筋斗云案例6. 右下角关闭广告案例7. 手风琴案例8. 旋转木马案例9. 三大系列 9.1 offset 系列 9.2 scroll 系列 9.3 client 系列 9.4 screen 系列 9.5 三大系列的区别10. 事件对象 10.1 事件对象的概述 10.2 获取事件对象 10.3 事件对象的常用属性 10.4 pageX与pageY的兼容性 10.5 案例:鼠标跟随 10.6 案例:拖拽效果 10.7 案例:放大镜11. 注册事件 11.1 on + 事件名称 方式 11.2 addEventListener 方式12. 事件冒泡和事件捕获 12.1 事件冒泡 12.2 阻止事件冒泡 12.3 事件捕获 12.4 事件流 12.5 键盘事件 12.6 案例:弹幕效果13. 瀑布流 14. 正则表达式 14.1 创建正则表达式 14.2 元字符 14.3 正则内部类 14.4 正则边界 14.5 量词 14.6 括号总结 14.7 正则表达式综合案例 14.8 正则补充知识点2.2 深入理解 Ajax简单介绍什么是服务器,并且教你怎么搭建一台本地运行的服务器,最后详细介绍Ajax的操作过程。JavaScript 进阶知识 - Ajax篇1. 服务器端技术基础 1.1 服务器 1.2 客户端 1.3 软件开发架构 1.4 网络基础2. Web 服务器 2.1 Web服务器的作用 2.2 AMP 集成环境 2.3 Web服务器软件的安装 2.4 安装的建议与问题 2.5 Wamp服务器的使用 2.6 Wamp服务器的简单配置3. HTTP传输协议 3.1 请求报文 3.2 响应报文4. Ajax 编程 4.1 Ajax的基本概念 4.2 创建Ajax 4.3 Ajax实现一个简单的聊天室 4.4 复杂的数据格式介绍 4.4.1 XML数据格式 4.4.2 JSON数据格式 4.5 Ajax代码的封装5. jQuery中的Ajax操作6. 模板引擎的使用 6.1 模板引擎的使用步骤 6.2 模板引擎的其他用法 6.3 模板引擎原生语法 6.4 案例:Ajax模拟请求json数据案例 6.5 案例:Ajax提供数据实现瀑布流7. Ajax请求模拟软件8. 同源策略 8.1 什么是同源策略 8.2 同源策略的目的 8.3 限制范围9. 跨域 9.1 JSONP 9.2 WebSocket2.3 js 高级知识本篇涉及知识点比较复杂 一直在寻求一种能讲明白的方法,已经快完结了,敬请期待。2.4 jQuery 使用方法详解虽然说jQuery的黄金时代已经过去了,但是不缺乏一些公司还在使用,本篇作为一篇“速查字典”还是可以的。jQuery 入门详解(一)jQuery 入门详解(二)1. jQuery基本概念 1.1 什么是 jQuery? 1.2 jQuery 的版本 1.3 jQuery 初体验 1.4 jQuery对象 和 DOM对象 1.5 jQuery对象 和 DOM对象相互转换2. jQuery 选择器 2.1 基本选择器 2.2 层级选择器 2.3 过滤选择器 2.4 表单选择器 2.5 筛选选择器 2.6 几个小案例3. jQuery 节点操作 3.1 查找节点 3.2 创建节点 3.3 添加节点 3.4 删除节点 3.5 克隆节点 3.6 替换节点 3.7 包裹节点 3.8 遍历节点 3.9 节点操作案例4. jQuery 属性操作 4.1 attr 操作 4.2 prop 操作 4.3 属性操作案例5. jQuery 样式操作 5.1 css 操作 5.2 class 操作 5.4 常见的样式 5.5 关于元素定位的常用方法 5.6 样式操作案例6. jQuery 设置和获取HTML、文本和值 6.1 html()方法 6.2 text()方法 6.3 val()方法7. jQuery 里的事件机制 7.1 加载 DOM 7.2 事件绑定 7.3 合成事件 7.4 事件冒泡 7.5 事件对象的属性 7.6 移除事件 7.7 模拟操作 7.8 事件委托 7.9 其他用法8. jQuery 动画 8.1 show()方法 和 hide()方法 8.2 fadeIn()方法 和 fadeOut()方法 8.3 slideUp()方法 和 slideDown()方法 8.4 自定义动画方法 animate() 8.5 其他动画方法 8.6 jQuery 动画案例9. jQuery 里的 Ajax 操作 9.1 load()方法 9.2 $.get()方法和$.post()方法 9.3 $.ajax()方法 9.3 jQuery中的serialize和serializeArray方法10. jQuery 插件的使用 10.1 颜色插件-jQuery.color.js 10.2 懒加载插件- jquery.lazyload.js 10.3 jQuery UI 插件 10.4 jQuery自定义插件 10.5 jQuery自定义插件-瀑布流插件3. HTML5 & CSS33.1 HTML5 详解介绍了新增的一些特性,一些操作音频视频的API,以及网络状态、地理位置和WEB存储。HTML5 入门详解1. 认识HTML52. 语法规范3. 语义化标签4. HTML5 浏览器支持5. 表单 5.1 表单控件 5.2 表单元素 5.3 表单属性 5.4 表单事件 5.5 表单样式6. 多媒体标签 6.1 音频 6.2 视频 6.3 音频/视频方法7. DOM 扩展 7.1 获取元素 7.2 类名操作 7.3 自定义属性8. 网络状态9. 地理定位 9.1 获取地理信息方式 9.2 隐私 9.3 使用地理定位 9.4 百度地图的用法10. WEB 存储 10.1 特性 10.2 方法详解 10.3 sessionStorage 10.4 localStorage 10.5 差异性11. 文件读取12. 拖拽3.2 CSS3 详解css2的升级,添加了媒体查询、Flex布局、2D & 3D转换等新特性。CSS3 入门详解(一)CSS3 入门详解(二)1.选择器 1.1 属性选择器 1.2 伪类选择器 1.3 伪元素选择器2. 颜色 2.1 RGBA 2.2 HSLA 2.3 关于 CSS 的透明度3. 文本阴影4. 盒模型5. 边框 5.1 边框圆角 5.2 边框阴影6. 背景 6.1 background-size 6.2 background-origin 6.3 background-clip 6.4 多背景7. 渐变 7.1 线性渐变 7.2 径向渐变8. 过渡 8.1 帧动画 8.2 补间动画9. 2D转换 9.1 位移 9.2 缩放 9.3 旋转 9.4 倾斜 9.5 矩阵10. 3D 转换 10.1 3D 坐标轴 10.2 透视(perspective) 10.3 3D呈现(transform-style) 10.4 3D呈现案例:3D轮播图 10.5 backface-visibility11. 动画 11.1 如何实现动画 11.2 动画关键属性 11.3 动画案例12. 伸缩布局 12.1 什么是伸缩布局 12.2 基本概念 12.3 flex-direction属性 12.4 flex-wrap 属性 12.5 flex-flow 属性 12.6 justify-content 属性 12.7 align-items 属性 12.8 align-content 属性 12.9 Order 属性 12.10 flex-grow 属性 12.11 flex-shrink 属性 12.12 flex-basis 属性 12.13 flex 属性 12.14 align-self 属性4. 前端框架4.1 three.js 框架canvas的升级框架,功能更加强大。three.js 入门详解(一)three.js 入门详解(二)1. 概述 1.1 什么是WebGL? 1.2 初识three.js 1.3 前期准备 1.3.1 下载地址 1.3.2 目录结构 1.3.3 配置开发环境2. 开始使用Three.js 2.1 渲染器(renderer) 2.2 场景(scene) 2.3 照相机(camera) 2.4 创建一个物体 2.5 渲染 2.6 完整代码3. Three.js功能概览4. 照相机 4.1 什么是照相机? 4.2 正交投影和透视投影 4.3 正交投影照相机 4.3.1 参数介绍 4.3.2 示例代码 4.4 透视投影照相机 4.4.1 参数介绍 4.4.2 示例代码5. 点、线、面 5.1 3D世界的组成 5.2 在Three.js中定义一个点 5.3 点的操作 5.4 绘制一条线段 5.5 线条的深度理解 5.6 绘制网格线6. 几何形状 6.1 基本几何形状 6.1.1 立方体 6.1.2 平面 6.1.3 球体 6.1.4 圆形 6.1.5 圆柱体 6.1.6 正四面体、正八面体、正二十面体 6.1.7 圆环面 6.1.8 圆环结 6.2 文字形状 6.2.1 下载使用 6.2.2 参数介绍 6.2.3 示例代码 6.3 自定义形状7. 材质 7.1 基本材质 7.2 Lambert 材质 7.3 Phong材质 7.4 法向材质 7.5 材质的纹理贴图 7.5.1 单张图像应用于长方体 7.5.2 六张图像应用于长方体 7.5.3 棋盘8. 网格 8.1 创建网格 8.2 修改属性 8.2.1 材质 8.2.2 位置、缩放、旋转9. 动画 9.1 实现动画效果 9.1.1 动画原理 9.1.2 setInterval方法 9.1.3 requestAnimationFrame方法 9.2 使用stat.js记录FPS 9.3 弹球案例10. 外部模型 10.1 支持格式 10.2 无材质的模型 10.3 有材质的模型 10.3.1 代码中设置材质 10.3.2 建模软件中设置材质11. 光与影 11.1 环境光(AmbientLight) 11.2 点光源(PointLight) 11.3 平行光(DirectionalLight) 11.4 聚光灯(SpotLight) 11.5 阴影补充问题 本地服务器 ...

December 24, 2018 · 6 min · jiezi

一直在做业务的程序员技术会进步吗?我们该如何跳出舒适圈

我是一个前端程序员,在刚开始工作的时候,在原来的部门,有一段时间一直在做各种活动,比如双十一、双十二、端午节活动等等。这些活动的模式基本差不多,我在做这些活动的过程中,有收获吗?有,当然有,但大吗?并不大。转岗之后,我陆续接触过一些项目,还有的项目很重要,用部门老大的话来说:是我们部门历史性的项目。做这些项目我有收获吗?有,比如说我之前没有用过 Vue,在新项目里我就接触了 Vue。然后呢?然后就没有然后了。在我至今为止做业务的过程中,我越来越意识到【一直做业务,技术进步慢,甚至没有进步】这个问题的严重性。接下来我想说明这个问题存在的原因,以及我想到的解决办法(仅代表个人意见)存在原因1.项目架子已经搭建好了2.业务已经消耗完你的精力轮子已经造好,你只需要填充业务代码进步最好的方式就是造轮子,在轮子已经造好的情况下,做业务的同学只需要把业务代码填进去就行,从项目的发展角度来讲,这些业务代码是项目的核心价值,但从技术上来讲,你做的事情,很有可能就是在一遍遍重复。没有余力关注技术特别是业务发展比较快的时候,每天 PM 排着队找你,在这种情况下,能做完业务就行,具体实现方式好不好,老板在乎这个吗?会导致什么后果工作8、9年,评一个2-3都为难这不是开玩笑,我就见过活生生的例子,前不久,团队在面试时,就遇到了这样的人,对我来说,我是不可能让自己处于这样的境地的。你能看到这里,说明你在工作当中也是在担心自己技术提升的问题,这里跟大家分享一下一套可解决此问题的方案!把简单的事情交给别人如果你能体会到今天的主题【一直做业务,我要怎么进步?】,那你应该已经具备一定的经验,一般的业务需求对你来说是重复的。那这个时候你就可以尝试着把这些需求交给其他人(如果自己无法做主,建议你找下leader),我的意思并不是叫你去甩锅,而是把需求交给那些还不是很熟练的人,对别人来说,做更多的需求能有比较大的进步,对你来说,有空余时间做技术上的事情能有比较大的进步,一举两得。相反,你若一直占着坑,别人也没有空间成长。空出来的时间,可以去研究自己还不熟悉的技术点,也可以去研究研究轮子。一定比你做业务提升快。这一步在实际操作时,可能会遇到一个问题:在以业务为主的团队,接触更多的业务就意味着更大的存在感。控制自己跳出舒适圈舒适区 这个名词所包含的东西,我想大家早就听腻了,就像我。但做出来就很少。但在我意识到【一直做业务,我要怎么进步?】这个问题的严重性的时候,我痛定思痛,最近终于开始付出行动了。比如说:在做二维码相关的项目的时候,我会去了解二维码的生成原理。比如说:在实现一个具体功能的时候,我不再像以前那样用现有的方案,这样更省事,可以直接 Copy,改个参数就行,而是故意去以优化的方式去实现功能。以上就是我总结的两个方法,都是出自自己的实际经验,希望对大家有用感谢阅读前端进阶者学习圈子-q-u-n-731771211-好友都会在里面交流,分享一些学习的方法和需要注意的小细节,每天也会准时的讲一些前端的项目实战,及免费前端直播课程学习

December 8, 2018 · 1 min · jiezi

【人物志】技术十年:美团第一位前端工程师潘魏增

导读潘魏增,2006年毕业于南开大学电子系,2008年加入早期饭否团队。美团第一位前端工程师,现在是X项目组终端研发部的负责人。处女座,INTJ,喜欢Linux和Vim,崇尚开源,相信开源可以让世界变得更美好。从饭否到美团,潘魏增用十年的技术生涯,诠释了“长期有耐心”这句话的含义。在他看来,长期有耐心,其实也是延迟满足感。对从事的行业来讲,我们要把眼光放得更长远一些,十年后才有回报的生意,往往都是大买卖。对个人来讲,不要把职位、职级这些虚的东西看得过重,关键看我们自己在其中承担什么角色,看我们自己的能力是否还有成长的空间。本文系美团技术学院美美对潘魏增的采访内容,希望对大家有所启发。从电子工程转到计算机1. 为什么大学读的是电子系,但是毕业后却选择了互联网行业?潘魏增:高中时,对物理比较感兴趣,学校有一个逸夫图书馆,里面有大量关于物理的课外读物,其中有一本杂志叫《无线电》,特别令我着迷。只需要少量元器件,就可以实现超远距离无线单向通信(收音机),简直太神奇了。于是,我就树立了自己的理想,以后要成为一名电子工程领域的科学家,所以选择了南开大学的电子系。 但是上大学之后突然发现,电子系的课程大部分都是以数学、物理相关的基础理论为主,动手创造的机会很少,特别枯燥。一次偶然的机会,想在电脑上搭建一个HTTP服务器,给各地的高中同学访问,因为不太懂,然后就去学校的BBS请教。当搭建成功的一刹那,我突然感觉到一种“触电”一样的兴奋感,相隔万里的人竟然可以看到我写的网页内容,太不可思议了。于是,我就开始经常泡BBS学习,到后来我就成为了能够回答别人问题的人,再后来,我就成为了南开BBS上WebDevelop版和Linux版的版主。 大学时,互联网逐渐从第一次泡沫中复苏。我在图书馆偶然看到一本讲互联网革命的书,书中那些早期设想的有关互联网的预言,都逐渐在一一实现。我深受作者的鼓舞,不过我觉得互联网革命还尚在早期,未来还将获得更加蓬勃的发展,我应该在行业萌芽的时候,加入到这场浪潮当中去。怎么加入?我不可能去「赤手空拳」地创业,毕竟还要吃饭,于是去互联网公司工作就成了我最佳的实际选择。当时在我们系,去互联网公司工作,其实是一个非常另类的、不被人理解的选择,因为绝大部分同学都去做了跟电路或者芯片等本专业相关的工作。但是,我很喜欢。 今天回头看,我呆过的团队做了很多改变世界的事,整个互联网行业也大大地改变了世界的原貌,信息更透明、公开,社会更加平等。科技革命总是短期被高估,长期被忽视。十多年前,我还用笔给同学写信,在图书馆翻查资料,出门带纸质地图……站回当时看现在,几乎是难以想象的:我们可以通过微信实现实时互动,通过知乎、维基百科和搜索引擎查阅无穷无尽的信息,出门有高德地图,而且现在出门还几乎不用带现金。2. 当时为什么会选择凤凰网?在凤凰网自己收获了哪些?潘魏增:读大学时,比较喜欢看凤凰卫视的节目,而凤凰网是凤凰卫视集团旗下的子公司。凤凰的节目内容在当时来讲是媒体界的一股清流,这是一群有理想、有抱负的人做的媒体,我希望能和这些人一起工作。而且凤凰网也是最早设立前端岗位的公司之一,这和我的职业方向非常匹配。当我收到Offer的时候,就立即过来报道了,甚至薪水给多少,我都没问。在凤凰网时,也学到了很多东西,主要是两点: 第一,完成学生到职业人的转变。加入公司后不久,老板就给机会负责整个网站的重构。迁移新闻系统工作量巨大,连续加班两个多月后,看到自己开发的作品每天有千千万万的网友在使用,非常有成就感。凤凰网是我职业的起点,一直心存感激。 第二,学到做事做人的一些方法。在大学里认为技术人总是特立独行,但在实际工作当中必须依赖团队协作。做事要认真,做人要简单。在凤凰两年,我做过很多次前端技术和用户体验相关的培训,同事们都乐于跟我请教,包括跟编辑、设计、销售等部门关系也特别好,很欣慰。在饭否的那些日子3. 因为什么原因加入的饭否?有什么故事?潘魏增:从大学开始就喜欢自己在网上写点文章,分享自己的成长心得。2008年初,穆荣均(美团联合创始人)在网上看到我写推荐饭否的博客,然后写邮件邀请我出来喝咖啡。我们喝了几次咖啡,有一次还在五道口的办公室见了兴哥(美团创始人王兴)。没过多久,就收到了饭否的工作邀请,这也是我工作之后,第一次正式收到其他团队的邀请,有点“奇遇”的感觉。我认真考虑了一段时间,然后也咨询了几个师哥和朋友,大家都认为饭否是非常靠谱的团队,于是,我就下决心过来了。4. 在饭否几年中主要负责哪些工作?当时你对整个团队的感觉是什么?潘魏增:在饭否时期,我在团队中的主要职责是负责前端开发,偶尔客串后端、运维、设计师、讲师以及客服。 刚加入这个团队的时候,第一印象是感觉这个团队特别酷。第一次开会,工程师直接用Firebug在投影仪上修改代码,直接浏览器上看效果,然后和大家一起现场讨论。平时的各种文档都是在Google Docs上一起协作完成,在同一份文档上,经常看到几个光标来回游走修改,现在感觉都还很科技、梦幻。 其次,团队每一个成员都很优秀。例如有工程师把PHP手册读到烂熟于心,了解这门语言的方方面面,版本升级也只是看看手册的Diff。 最重要的一点,感觉大家都很拼。我到入职之后才知道,我们一周要上6天班,工作时间是早上10点到晚上10点,经常会忙到凌晨,上班也不用打卡,全靠自觉和相互监督。5. 加入饭否时,也正值青春年少,有什么梦想吗?当时有没有考虑过职业规划这些问题吗?潘魏增:青春总是有很多冲动嘛,一心想要去改变世界。在饭否,我们的梦想就是让信息更公开,社会更平等,让信息流动更快。 职业规划方面,想得真的不太多。当时的想法,就是想往前端技术专家的方向努力一下,能对行业产生一些价值,个人能有一些影响力,就很知足了。6. 从饭否到美团这些年,为什么没有考虑过换一个环境?是什么原因让自己坚持下来?潘魏增:在饭否被关闭之后的那半年里,突然没那么忙了。坦白讲那段时间,确实有考虑过是否要换个环境,所以说,闲并不是什么好事,容易滋生各种想法(笑)。我有几个师哥和朋友知道我的事情之后,也给我介绍过几个工作,最后都被我婉拒了。在饭否呆过之后,对团队的要求突然变高了很多,开始知道什么是好的,什么是不好的。在美团的日子,工作更是超级忙,就压根没空去想过这个事情。 我很享受在公司工作的时光,喜欢现在的工作。其实,好的工作,不需要坚持。 在创业团队头两年,闷头写代码,技术每天都有进步(开心)。之后开始建团队、Coach团队,从个人贡献者到团队贡献者,公司给我机会从零开始学管理,从一张白纸开始慢慢明白一些道理(开心)。 然后团队规模越来越大,业务越来越复杂,管理能力迭代更新,我培养过很多个技术Leader(更开心)。 其实,开心的工作基本不需要谈“坚持”,它会给你持续的、正向的激励。不好的工作才需要咬牙坚持,而坚持错误,是一件机会成本很高的事情。工程师眼中的美团7. 在你眼中,我们美团是一家什么样的公司?有哪些特质让你印象深刻?潘魏增:印象最深的,也是最喜欢的特质就是我们美团是一家学习型组织。公司创始人都非常善于去学习、思考和总结,并身体力行去分享、去鼓励大家这么做。 比如兴哥,我觉得他的学习面特别广。记得有一次聚会,兴哥聊天时说到各地的方言,还帮忙给大家各自的方言做归类,聊到兴致起来,还拿出一本厚厚的语言书,证明他说的都有理有据。后来还有一次,兴哥给大家送了一本关于地缘结构的书,他说不错,推荐大家看。我看完之后确实对世界格局有了新的认识,对我帮助很大。 兴哥能从学习中受益,我觉得很多人应该也是如此。学城(美团内部知识库)和互联网+大学,有大量内部学习的资料,有大牛的分享,有行业的判断,有方法论,我自己也从上面学到了不少真东西,大家可以利用一些这些资源。8. 千团大战后,美团又做了电影票(猫眼,已经独立)、外卖业务,现在布局了酒旅、出行和大零售业务,作为其中的一员,最大的感触是什么?潘魏增:最大的感触就是,每天都像在“打仗”。我们美团进入的领域一部分并不是最新的领域,另外一部分可能相对较新,同时有很多人也都看到了这个机会。表面上,美团像是和其他公司在争夺,其实不然,实际上大家都在竞赛,看谁能给用户提供更大的价值,提供更好的产品。听说有些公司,专门针对美团建立了“抗美办公室”,我觉得他们的思路很奇怪,还在用“零和游戏”的思维在做事情。前些天,王慧文也分享了自己对这方面的看法,美团就是一种“尝试”的心态在做事,我们最终是希望给用户带来更大的价值。美团的价值观,第一条也是“以客户为中心”。 因为竞争是全方位的,有时候看到其他公司写的“黑稿”,里面尽是一些没有逻辑的猜测和诬陷。这个时候,我们反而更像是打了“鸡血”一样,想把我们自己的产品做的更好。 当然,这么多年,也经历了美团的很多从零到一的业务,有时候会感觉会比较煎熬,有时候也会很亢奋,就像坐过山车,有时候嗨到顶峰,有时候也会感觉跌到谷底,但尖叫总是持续不断的。在美团的生活,真的很精彩。十年技术生涯9. 对绝大多数青年来说,大学毕业后,应该是人生最好的十年,这十年最大的收获是什么?您怎么理解王兴说的“长期有耐心”这句话?潘魏增:十年的收获有很多,不过我感觉都是人生体验的东西,到这个时间点,到了这个岁数,每个人总会零零散散收获一些东西,包括物质层面的,还有精神层面的。对我而言,最大的收获可能是更了解了自己,找到一些和自己更好相处的方式。十年前,觉得自己什么都能做,什么都可以做得很好,现在大概明白自己的能力范围在哪里。十年前,不明白自己想要什么,现在尽管依然不是那么清楚,但已经相对更清晰一些,还需要迭代。 长期有耐心,我的理解就是延迟满足感。对从事的行业来讲,要把眼光放得更长远一些。做个不是那么恰当的比喻,每天计较得失的大部分都难成气候,十年后才有回报的生意,往往都是大买卖。对个人而言,不要太早着急“变现”,拿得多,往往不如拿得稳,也不要把职位、职级这些虚的东西看得过重。关键看自己在其中承担什么角色,看自己的能力是否还有成长的空间。10. 这十年,有没有对自己影响特别大的人?潘魏增:十年间,我有幸认识了很多非常优秀的人。有老板,有同事,也有人生路上的师哥、朋友等,对我影响都很大,感谢得到了他们的教诲和帮助,也从他们身上学到了不少东西。 坦白讲,我自己受穆荣均的影响比较深。我在公司里最早接触的人就是他,也是因为他,我被吸引加入了早期的饭否。他认为应该坚持做正确的事情,即使遇到阻力,也要不折不挠地推进。 比如,技术团队早期要提升并行开发的效率,版本管理工具要从SVN迁移到Git,这个事情虽然是我主导,但事实上是穆荣均在背后鼓励我这么做。 又比如刚开始的美团技术学院,有很多BootCamp培训、技术交流和组织上的杂事要做,同时会面临业务上的一些压力,穆荣均也是很支持我去展开这方面的工作。我相信对早期工程师文化的建设和团队组织的成长,都是有帮助的。11. 这十年,对前端技术的认知,有哪些改变?潘魏增:虽然十年来,前端技术层出不穷,但我理解的前端是「万变不离其宗」,它是为最终用户界面服务的,承接用户与远端数据的交互。前端的核心是数据的呈现,不管后端给什么数据,前端只负责忠实的展示。前端也可能会做服务端的开发,也可能会做平台化、工程化的工具,但它最根本的目标还是这个,不要偏离这个目标去做事情。 其次前端技术不能脱离业务而存在。前端工程师当中有部分同学很Geek,有的喜欢研究专深的技术,有的喜欢越界做点事情。这些本身也没错,但把更多精力去推动业务,获得成功是回报更高的事情。如果做技术缺乏业务视角,往往是很危险的。爱健身,爱读书,爱思考12. 平时有哪些兴趣爱好?这些兴趣爱好,对自己有什么影响?潘魏增:我基本没有固定的兴趣爱好,不同阶段有不同的兴趣点。以前喜欢研究跑鞋、键盘、Hack电纸书,现在都“退烧”了。喜欢过跑步、游泳、爬山,也都“收山”了。 目前还在坚持的、时间最长的是健身,每周定期活动活动身体。我要争取比同龄人体态更好一些,头发掉得更少一些(笑)。 受家人和朋友的影响,我开始喜欢旅游。我曾经信奉李敖先生所推崇的“读两万卷书,行零里路”,但去过一些地方以后,才发现“知道”和“看见”是两种不同层次的感受。比如在川西,路过四姑娘山时,山就那么横在我面前,让我突然意识到自己的渺小,冲击力特别大,和图片上看到的完全不一样。 还有,自从学会开车上路以后,也喜欢研究汽车知识和汽车文化。互联网是“比特在两点之间的移动”,汽车是“原子在两点间的移动”,这些概念都挺有意思的。13. 读书多吗?哪几本对自己影响比较大?潘魏增:比较惭愧,我读书很慢,所以读书并不是很多。豆瓣上标记想读的书永远比读过的书多很多。 我觉得读书有两个乐趣,一个是了解自己,另外一个是探索世界。内向者的能量大部分来自读书和独处时的思考,就我来说,读书的比重可能更大一些,所以读书还会给我带来力量。这里有几个读书心得跟大家分享:一、读好书。好书会改变一些东西,例如思维方式、生活理念甚至对世界的认知,而烂书只会浪费时间。找好书有三个渠道,豆瓣评分很高的;大牛文章总结的好书;朋友同事推荐。其中我最认朋友们的推荐,他们一般不推荐书,一旦推荐都极其靠谱,所以可以结交一些爱读书、会读书的朋友。二、做笔记。写笔记可以概括重点、理清思路,对于理解书中的内容有很大帮助。即便不一定会再看一次笔记,但做笔记的这个过程可以帮助加深记忆,书中道理也会通过记笔记的形式融入到潜意识当中。这跟抄佛经有点类似,不同的是,做笔记不要摘抄太多原文,那样没有意义,应该去总结、抽象,读书是为了获得思想,而非文字本身。三、回到初心。要回到自己读书的初衷,或乐趣,或好奇,少一些目的性和功利心。读一本书,不要老想它能用来干什么,而是多思考它在表达什么。不要期望每本书读了都有用,马上就能用的书是菜谱。最后给大家推荐几本我觉得不错的书。其中《禅与摩托车维修艺术》、《邓小平时代》和《素书》是大书,有些部分晦涩难懂,但值得反复咀嚼,像好酒,越喝越香;《请理解我》和《断舍离》是小书,实操简单,效果立竿见影,也许能对工作和生活带来一些改变。14. 对做技术的同学们,有哪些建议?潘魏增:有几个建议,也是我个人的一些成长心得,仅供大家参考吧,希望能给大家带来一点帮助。第一个是打好基础。 毕业刚走进职场的同学,一定要打好技术基础。「勿在浮沙筑高台」,把地基打扎实,才能在上面建成高楼大厦。怎么打地基,每个人有自己的方式,我个人比较喜欢的是看官方手册、标准文档以及阅读源代码。 第二个是提升视野。对于有一定经验和技术基础的工程师,建议多走出去,看看公司内其他团队是怎么做,业界是怎么做的。好的技术往往是因为看得足够多。 第三个是思考本质。“老司机”可以多跳出来想想商业的本质、社会的本质,毕竟技术只是这个世界很小的“子集”。我们的社会是一个非常复杂的系统,结构远比技术系统更加复杂。我也是最近几年才开始有这个认识,还在慢慢地摸索、学习。希望大家共同努力吧!

December 7, 2018 · 1 min · jiezi

大三学生想做程序员,自学还是培训?

一位小兄弟联系我说:本科是市场营销的,网上找的学习资料自学的编程。入行半年后我有点后悔了,觉得自己不是开发的料,在技术上存在明显的先天不足,而且一直坐班的工作方式真的很压抑,最关键的是感觉没有什么兴趣再往下学了,相比科班出身的其他人,我对技术越来越不敏感,比如什么框架更新了什么功能,对公司现有架构有什么提升的建议。。一窍不通,半懂不懂的也不好意思拿出来卖弄,只懂的写业务代码,是一个纯粹的码农,后悔当时没去培训班至少可以结实一帮同学,互相的交流,现在都是独来独往,每天同事半年时间也是换了一波又一波。现在他的亲戚家的孩子,读大三了,专业也不是做编程的,想转做程序员,他想让我给他一些意见。那孩子准备去培训班,他考虑是劝他去呢?还是像自己自学呢?IT培训推动了IT行业的发展。IT行业从上世纪90年开始出现在中国,在00年后开始得到迅速发展,到如今已经成为了一个非常成熟的行业。IT行业得到这样的快速的发展,离不开IT培训机构的大量人才输出。从我国高校开始建设IT相关专业以来,虽然培养的大量的IT人才,但是和市场对IT人才的需求来比较,还远远不够,何况高校毕业的大部分IT人才还只是停留在基础理论阶段,离能胜任企业的工作还有一段距离,然而IT培训机构以理论为基础,以实战为主导的培训理念给市场做了很好的补充。随着大量的人员涌入IT行业,人才质量出现参差不齐的现象,这是行业发展得必然结果。记得移动互联网刚火那会,只要会一点Android或者iOS,工资都在一万以上,即便如此,企业还是找不到合适的人才,但是高校也没有这样的课程,于是只能求救于培训班毕业的学生。过了4年多,由于培训班培养的大批量的iOS和andriod工程师,而岗位却有限,市场逐渐出现饱和的现象,很多从培训班毕业的学生开始找不到工作。到了2015后,基本大部分都找不到工作,很多学了Android的转学Java,学iOS的转学前端等等,培训机构也开始停止培训这两个学科。基本上所有在2017年开的机构,都不再培训Android和iOS,主打课程也只培训Java和软件测试这两个目前热门学科,没有Android和iOS。从培训机构的科目变化,我们能知道市场需求情况,反过来,我们也能从企业对人才的需求情况来预计该学什么。如果要说,培训班培训的程序员对IT行业的影响,在我看来,就是加快了行业发展得进程,弥补了高校人才不足,同是也提高了人们进入这个行业的门槛。从轻松的校园走到社会时,多少人面临这巨大的落差,社会需要的,完全不是学校教的,按部就班的学习已经造成了巨大的能力与认知差异,这种差异必须要有坚定的意志,多次的跌打滚爬才能弥补。选择建议:朋友们就经常问我该不该去培训,我就会告诉他们。培训真正的作用是断了你的退路,让你面临死地,真正能站起来的,需要有强烈的战斗力!但是,同样,自学也是需要有坚定的意志力,学习力。你也是需要花费更多的时间去找资料,遇到问题也不能及时解决。当真正开始学习的时候难免不知道从哪入手,导致效率低下影响继续学习的信心。最重要的是不知道哪些技术需要重点掌握,学习时频繁踩坑,最终浪费大量时间。做任何事从零开始的时候都是很难的,程序员更加如此,互联网技术更新迅速,从0到1的过程还不是最艰辛的,最难的是在1+1时候是否等于2,或者更多,你才能在这个IT界生存下去!

December 2, 2018 · 1 min · jiezi

如何告别迷茫,成为优秀的前端开发工程师

成为一名前端开发人员注定是一条充满坎坷的道路,你必须借鉴前人的经验,小心翼翼地前行。如果你也想成为一名开发人员,那么在学习过程中,一定要告别以下这些消极的心理陷阱。1. 告别漫无目的的学习在前端开发的学习过程中,你会从经验丰富的开发人员那里得到很多建议。他们会告诉你什么是最好的编程语言,你需要的技能以及你必须使用的工具。他们的建议是非常实用和可靠的 – 也许这些建议与你昨天刚得到的建议正好相反。但是,千万别在这些好建议中迷失方向,漫无目的地学习。如果你每月都在不停地尝试新的编程语言,经常切换文本编辑器,并疯狂地学习各种开发知识,请立马停下来!这样做只会于事无补,你的能力并没有得到任何提升。对于初学者来说,语言和工具选择在学习过程中是非常重要的。虽然,这种重要性只体现在一些开发的细节上。任何盛行的编程语言都可以你实现想要的东西,重要的是你要选择一套适合自己的编程语言和工具。所以,对于初学者应该如何选择语言和工具呢?建议初学者只选择一种编程语言,学习并精通它。下载最简单的文本编辑器,并结合编程语言一起使用。注意:无论你选择如何学习开发,千万不要把时间浪费在尝试各种各样的编程技术上。2. 学习过程中,怀疑自己是否真的适合编程有些时候,在这个学习过程中,你会怀疑自己是否真的适合编程。在心理学中,这种现象被称为冒名顶替综合征,这对于开发者来说是极大的氪石。在什么情况下会导致你产生冒名顶替综合征?任何小事情都能引起你这种冒充的感觉。这可能是在会议上的旁观者的一瞥,对于你不知道什么是多态性而满脸诧异。也有可能是每次你对某个半成品的应用程序进行开发,却发现它变得更加糟糕。也可能是你对Twitter上自己对令人惊奇的项目感到沾沾自喜时,导致你产生了这种感觉。治疗假冒综合征的第一步是承认自己有问题。如果你向其他初学阶段的开发者承认这一点,你会得到额外的收获。因为当你告诉他们冒名顶替综合征时,他们常常会惊呼: “ 我以为只有我才是这样! ” 你会发现,原来不只你一个人有这种感觉,其实这是不自信的表现!消除假冒综合征的另一个关键是记录,记录你在学习过程中所有的失败和成就。当你再回顾这些记录时,你会发现没有什么比回顾和意识到 “嘿! 三个月前我与之搏斗的概念现在对我来说很简单!”这样的感觉更好!你会对自己学习开发充满信心,消除自我怀疑!3. 别让自己变成一座孤岛想要成为一名成功的软件开发人员,技能只是其中一个要素;运气、咖啡和与其他人的交往技巧也是很重要的因素。通常,有抱负的开发人员认为他们找不到工作是因为自己的专业技能不够强大。事实上,他们的求职技巧往往才是罪魁祸首。为什么这样说呢?我们不妨在这里作一个小小的假设,假设有两个工作经验相同的开发人员同时在同一个城市求职。开发人员A是一位“神童”。 她从10岁开始学习编码,只需通过观察就可以修复程序中的Bug。她准备了一份简历,并在网上投递了数百封求职信。开发者B是一个普通的开发人员。虽然她在这个领域工作时间不长,但在继续发展下去也是非常有前途的。她也准备了一份简历,然后在她每周参加的开发者线下会议中希望获得一些宝贵的意见。她告诉所有人她正在找工作,并且有兴趣和任何在招聘领域工作的人交谈。两者相比,你认为谁会先找到工作?我觉得开发者B更容易成功.开发人员A可能属于某种代码忍者,不爱与人交流。即使无人问津,她也认为不重要。她的简历就会被淹没在上千份的简历中,然后被一些招聘人员根据算法默默地筛选出去,根本没有机会递到面试官的手上。而开发人员B的情况就正好相反,许多公司争着想与她签下工作合约。最终,她会选择与某个在招聘公司工作的熟人先进行交谈,学习一些面试技巧。这个与她交谈的人会亲自递交她的简历,由校对人员帮忙改进后,然后从招聘人员那获得面试的机会。这个熟人会提供她面试过程的内幕消息,她会提前作好面试准备。面试官和招聘经理也会知道她是熟人推荐来的。所以,在她走进门之前,她已经成功了一半。4. 打破“还没准备好”的退缩心理自学的开发人员通常不确定自己应该什么时候开始找工作。因为他们很难判断自己的技能水平,对于初级开发人员应该知道些什么,完全没有明确的指导方针。如何判断自己是否有足够的开发能力被雇佣? 其实,在面试中,能力并不是雇佣的先决条件。只要你能说服别人雇用你,你就能被雇佣。这句话咋一听简单易懂,但再想想它的深层含义呢。这意味着你可以对代码几乎一无所知,但仍然可以找到工作,前提是你与面试官非常“聊得来“。 同时,这也意味着即使你是软件开发的行业百科全书,不会与面试官交流,也仍然会被Pass。学会在精神上区分你的技能和被雇佣的能力。技术技能确实会影响你被雇用的能力,但这种联系并不像你想象的那么直接。雇主不会根据你的实际技能水平对你进行评估,而是他们对你技能水平的认知来评估你。对你的技能的早期印象,基于你的自信程度,衣着的颜色的其他互动。如果你流露出自信,面试官会认为你知道自己在做什么。如果你对自己不自信,他们会怀疑的专业技能。基于这样的面试技巧,你最好先培养自己的自信。每当你走出舒适区去工作或做其他事情,你就可以证明之前低估了自己的能力,从而为自己增加一些信心。经常这样做,你的自信心就会不断增强。最重要的是你要意识到积极或消极的自我对话的涟漪效应,它可能会影响到你开始找工作的时间,以及你最终得到的报酬。那么,到底什么时候才算准备好了?其实很简单,只要你能说服自己,你就准备好了。我的前端学习q.u.n:784783012,欢迎新手,进阶。好友都会在里面交流,分享一些学习的方法和需要注意的小细节,欢迎加入

December 2, 2018 · 1 min · jiezi

动手做个聊天室,前端工程师百无聊赖的人生

本项目服务端基于node.js技术,使用了koa框架,所有数据存储在mongodb中。客户端使用react框架,使用redux和immutable.js管理状态,APP端基于react-native和expo开发。本文需要对JavaScript较为熟悉,讲解核心功能点的设计思路。服务端架构服务端负责两件事:1.提供基于WebSocket的接口2.提供index.html响应服务端使用了koa-socket这个包,它集成了socket.io并实现了socket中间件机制,服务端基于该中间件机制,自己实现了一套接口路由每个接口都是一个async函数,函数名即接口名,同时也是socket事件名async login(ctx) { return ’login success’}然后写了个route中间件,用来完成路由匹配,当判断路由匹配时,以ctx对象作为参数执行路由方法,并将方法返回值作为接口返回值function noop() {}/** * 路由处理 * @param {IO} io koa socket io实例 * @param {Object} routes 路由 /module.exports = function (io, _io, routes) { Object.keys(routes).forEach((route) => { io.on(route, noop); // 注册事件 }); return async (ctx) => { // 判断路由是否存在 if (routes[ctx.event]) { const { event, data, socket } = ctx; // 执行路由并获取返回数据 ctx.res = await routes[ctx.event]({ event, // 事件名 data, // 请求数据 socket, // 用户socket实例 io, // koa-socket实例 _io, // socket.io实例 }); } };};还有一个重要catchError中间件是,它负责捕获全局异常,业务流程中大量使用assert判断业务逻辑,不满足条件时会中断流程并返回错误消息,catchError将捕获业务逻辑异常,并取出错误消息返回给客户端const assert = require(‘assert’);/* * 全局异常捕获 /module.exports = function () { return async (ctx, next) => { try { await next(); } catch (err) { if (err instanceof assert.AssertionError) { ctx.res = err.message; return; } ctx.res = Server Error: ${err.message}; console.error(‘Unhandled Error\n’, err); } };};这些就是服务端的核心逻辑,基于该架构下定义接口组成业务逻辑另外,服务端还负责提供index.html响应,即客户端首页。客户端的其他资源是放在CDN上的,这样可以缓解服务端带宽压力,但是index.html不能使用强缓存,因为会使得客户端更新不可控,因此index.html放在服务端客户端架构客户端使用socket.io-client连接服务端,连接成功后请求接口尝试登录,如果localStorage没有令牌或者接口返回令牌过期,将会以游客身份登录,登录成功会返回用户信息以及群组,好友列表,接着去请求各群组,好友的历史消息客户端需要监听connect / disconnect / message三个消息1.connect:socket连接成功2.disconnect socket连接断开3.message 接收到新消息客户端使用redux管理数据,需要被组件共享的数据放在redux中,只有自身使用的数据还是放在组件的state中,客户端存储的redux数据结构如下:用户用户信息_id用户id用户名用户名linkmans联系人列表,包括群组,好友以及临时会话isAdmin是否是管理员焦点当前聚焦的联系人id,既对话中的目标连接连接状态ui客户端UI相关和功能开关客户端的数据流,主要有两条线路1.用户操作=>请求接口=>返回数据=>更新redux =>视图重新渲染2.监听新消息=>处理数据=>更新redux =>视图重新渲染用户系统用户架构定义:const UserSchema = new Schema({ createTime: { type: Date, default: Date.now }, lastLoginTime: { type: Date, default: Date.now }, username: { type: String, trim: true, unique: true, match: /^([0-9a-zA-Z]{1,2}|[\u4e00-\u9eff]){1,8}$/, index: true, }, salt: String, password: String, avatar: { type: String, },});createTime:创建时间lastLoginTime:最后一次登录时间,用来清理僵尸号用username:用户昵称,同时也是账号salt:加密盐password:用户密码avatar:用户头像URL地址用户注册注册接口需要username/ password两个参数,首先做判空处理const { username, password} = ctx.data;assert(username, ‘用户名不能为空’);assert(password, ‘密码不能为空’);然后判断用户名是否已存在,同时获取默认群组,新注册用户要加入到默认群组const user = await User.findOne({ username });assert(!user, ‘该用户名已存在’);const defaultGroup = await Group.findOne({ isDefault: true });assert(defaultGroup, ‘默认群组不存在’);存密码明文肯定是不行的,生成随机盐,并使用盐加密密码const salt = await bcrypt.genSalt$(saltRounds);const hash = await bcrypt.hash$(password, salt);给用户一个随机默认头像,保存用户信息到数据库let newUser = null;try { newUser = await User.create({ username, salt, password: hash, avatar: getRandomAvatar(), });} catch (err) { if (err.name === ‘ValidationError’) { return ‘用户名包含不支持的字符或者长度超过限制’; } throw err;}将用户添加到默认群组,然后生成用户令牌令是用来免费码登录的凭证,存储在客户端localStorage,令牌里带带用户id,过期时间,客户端信息三个数据,用户id和过期时间容易理解,客户端信息是为了防止令牌盗用,之前也试过验证客户端ip一致性,但是ip可能会有经常改变的情况,搞得用户每次自动登录都被判定为盗用了……defaultGroup.members.push(newUser);await defaultGroup.save();const token = generateToken(newUser._id, environment);将用户id与当前 socket 连接关联, 服务端是以 ctx.socket.user 是否为 undefined 来判断登录态的 更新 Socket 表中当前 socket 连接信息, 后面获取在线用户会取 Socket 表数据ctx.socket.user = newUser._id;await Socket.update({ id: ctx.socket.id }, { user: newUser._id, os, // 客户端系统 browser, // 客户端浏览器 environment, // 客户端环境信息});最后将数据返回客户端return { _id: newUser._id, avatar: newUser.avatar, username: newUser.username, groups: [{ _id: defaultGroup._id, name: defaultGroup.name, avatar: defaultGroup.avatar, creator: defaultGroup.creator, createTime: defaultGroup.createTime, messages: [], }], friends: [], token,}用户登录fiora是不限制多登陆的,每个用户都可以在无限个终端登录登录有三种情况:游客登录令牌登录用户名/密码登录游客登录仅能查看默认群组消息,并且不能发消息,主要是为了降低第一次来的用户的体验成本令牌登录是最常用的,客户端首先从localStorage取令牌,令牌存在就会使用令牌登录首先对令牌解码取出负载数据,判断令牌是否过期以及客户端信息是否匹配let payload = null;try { payload = jwt.decode(token, config.jwtSecret);} catch (err) { return ‘非法token’;}assert(Date.now() < payload.expires, ’token已过期’);assert.equal(environment, payload.environment, ‘非法登录’);从数据库查找用户信息,更新最后登录时间,查找用户所在的群组,并将socket添加到该群组,然后查找用户的好友const user = await User.findOne({ _id: payload.user }, { _id: 1, avatar: 1, username: 1 });assert(user, ‘用户不存在’);user.lastLoginTime = Date.now();await user.save();const groups = await Group.find({ members: user }, { _id: 1, name: 1, avatar: 1, creator: 1, createTime: 1 });groups.forEach((group) => { ctx.socket.socket.join(group._id); return group;});const friends = await Friend .find({ from: user._id }) .populate(’to’, { avatar: 1, username: 1 });更新socket信息,与注册相同ctx.socket.user = user._id;await Socket.update({ id: ctx.socket.id }, { user: user._id, os, browser, environment,});最后返回数据用户名/密码与令牌登录仅一开始的逻辑不同,没有解码令牌验证数据这步先验证用户名是否存在,然后验证密码是否匹配const user = await User.findOne({ username });assert(user, ‘该用户不存在’);const isPasswordCorrect = bcrypt.compareSync(password, user.password);assert(isPasswordCorrect, ‘密码错误’);接下来逻辑就与令牌登录一致了消息系统发送消息sendMessage接口有三个参数:to:发送的对象,群组或者用户type:消息类型content:消息内容因为群聊和私聊共用这一个接口,所以首先需要判断是群聊还是私聊,获取群组id或者用户户ID,群聊/私聊通过参数区分群聊时到是相应的群组id,然后获取群组信息私聊时到是发送者和接收者二人id拼接的结果,去掉发送者id就得到了接收者id,然后获取接收者信息let groupId = ‘’;let userId = ‘’;if (isValid(to)) { const group = await Group.findOne({ _id: to }); assert(group, ‘群组不存在’);} else { userId = to.replace(ctx.socket.user, ‘’); assert(isValid(userId), ‘无效的用户ID’); const user = await User.findOne({ _id: userId }); assert(user, ‘用户不存在’);}部分消息类型需要做些处理,文本消息判断长度并做xss处理,邀请消息判断邀请的群组是否存在,然后将邀请人,群组id,群组名等信息存储到消息体中let messageContent = content;if (type === ’text’) { assert(messageContent.length <= 2048, ‘消息长度过长’); messageContent = xss(content);} else if (type === ‘invite’) { const group = await Group.findOne({ name: content }); assert(group, ‘目标群组不存在’); const user = await User.findOne({ _id: ctx.socket.user }); messageContent = JSON.stringify({ inviter: user.username, groupId: group._id, groupName: group.name, });}将新消息存入数据库let message;try { message = await Message.create({ from: ctx.socket.user, to, type, content: messageContent, });} catch (err) { throw err;}接下来构造一个不包含敏感信息的消息数据, 数据中包含发送者的id、用户名、头像, 其中用户名和头像是比较冗余的数据, 以后考虑会优化成只传一个id, 客户端维护用户信息, 通过id匹配出用户名和头像, 能节约很多流量 如果是群聊消息, 直接把消息推送到对应群组即可 私聊消息更复杂一些, 因为 fiora 是允许多登录的, 首先需要推送给接收者的所有在线 socket, 然后还要推送给自身的其余在线 socketconst user = await User.findOne({ _id: ctx.socket.user }, { username: 1, avatar: 1 });const messageData = { _id: message._id, createTime: message.createTime, from: user.toObject(), to, type, content: messageContent,};if (groupId) { ctx.socket.socket.to(groupId).emit(‘message’, messageData);} else { const sockets = await Socket.find({ user: userId }); sockets.forEach((socket) => { ctx._io.to(socket.id).emit(‘message’, messageData); }); const selfSockets = await Socket.find({ user: ctx.socket.user }); selfSockets.forEach((socket) => { if (socket.id !== ctx.socket.id) { ctx._io.to(socket.id).emit(‘message’, messageData); } });}最后把消息数据返回给客户端,表示消息发送成功。客户端为了优化用户体验,发送消息时会立即在页面上显示新信息,同时请求接口发送消息。如果消息发送失败,就删掉该条消息获取历史消息getLinkmanHistoryMessages接口有两个参数:linkmanId:联系人id,群组或者俩用户id拼接existCount:已有的消息个数详细逻辑比较简单,按创建时间倒序查找已有个数+每次获取个数数量的消息,然后去掉已有个数的消息再反转一下,就是按时间排序的新消息const messages = await Message .find( { to: linkmanId }, { type: 1, content: 1, from: 1, createTime: 1 }, { sort: { createTime: -1 }, limit: EachFetchMessagesCount + existCount }, ) .populate(‘from’, { username: 1, avatar: 1 });const result = messages.slice(existCount).reverse();返回给客户端接收推送消息客户端订阅消息事件接收新消息 socket.on(‘message’)接收到新消息时,先判断状态中是否存在该联系人,如果存在则将消息存到对应的联系人下,如果不存在则是一条临时会话的消息,构造一个临时联系人并获取历史消息,然后将临时联系人添加到州中。如果是来自自己其它终端的消息,则不需要创建联系人const state = store.getState();const isSelfMessage = message.from._id === state.getIn([‘user’, ‘_id’]);const linkman = state.getIn([‘user’, ’linkmans’]).find(l => l.get(’_id’) === message.to);let title = ‘’;if (linkman) { action.addLinkmanMessage(message.to, message); if (linkman.get(’type’) === ‘group’) { title = ${message.from.username} 在 ${linkman.get('name')} 对大家说:; } else { title = ${message.from.username} 对你说:; }} else { // 联系人不存在并且是自己发的消息, 不创建新联系人 if (isSelfMessage) { return; } const newLinkman = { _id: getFriendId( state.getIn([‘user’, ‘_id’]), message.from._id, ), type: ’temporary’, createTime: Date.now(), avatar: message.from.avatar, name: message.from.username, messages: [], unread: 1, }; action.addLinkman(newLinkman); title = ${message.from.username} 对你说:; fetch(‘getLinkmanHistoryMessages’, { linkmanId: newLinkman.id }).then(([err, res]) => { if (!err) { action.addLinkmanMessages(newLinkman.id, res); } });}如果当前聊天页是在后台的,并且打开了消息通知开关,则会弹出桌面提醒if (windowStatus === ‘blur’ && state.getIn([‘ui’, ’notificationSwitch’])) { notification( title, message.from.avatar, message.type === ’text’ ? message.content : [${message.type}], Math.random(), );}如果打开了声音开关,则响一声新消息提示音if (state.getIn([‘ui’, ‘soundSwitch’])) { const soundType = state.getIn([‘ui’, ‘sound’]); sound(soundType);}如果打开了语言播报开关并且是文本消息,将消息内的url和#过滤掉,排除长度大于200的消息,然后推送到消息朗读队列中if (message.type === ’text’ && state.getIn([‘ui’, ‘voiceSwitch’])) { const text = message.content .replace(/https?://(www.)?[-a-zA-Z0-9@:%.+~#=]{2,256}.[a-z]{2,6}\b([-a-zA-Z0-9@:%+.~#?&//=])/g, ‘’) .replace(/#/g, ‘’); // The maximum number of words is 200 if (text.length > 200) { return; } const from = linkman && linkman.get(’type’) === ‘group’ ? ${message.from.username}在${linkman.get('name')}说 : ${message.from.username}对你说; if (text) { voice.push(from !== prevFrom ? from + text : text, message.from.username); } prevFrom = from;}更多中间件限制未登录请求大多数接口是只允许已登录用户访问的,如果接口需要登录且socket连接没有用户信息,则返回“未登录”错误/** * 拦截未登录请求 /module.exports = function () { const noUseLoginEvent = { register: true, login: true, loginByToken: true, guest: true, getDefalutGroupHistoryMessages: true, getDefaultGroupOnlineMembers: true, }; return async (ctx, next) => { if (!noUseLoginEvent[ctx.event] && !ctx.socket.user) { ctx.res = ‘请登录后再试’; return; } await next(); };};限制调用频率为了防止刷接口的情况,减轻服务器压力,限制同一插座连接每分钟内最多请求30次接口const MaxCallPerMinutes = 30;/* * Limiting the frequency of interface calls */module.exports = function () { let callTimes = {}; setInterval(() => callTimes = {}, 60000); // Emptying every 60 seconds return async (ctx, next) => { const socketId = ctx.socket.id; const count = callTimes[socketId] || 0; if (count >= MaxCallPerMinutes) { return ctx.res = ‘接口调用频繁’; } callTimes[socketId] = count + 1; await next(); };};小黑屋管理员账号可以将用户添加到小黑屋,被添加到小黑屋的用户无法请求任何接口,10分钟后自动解禁/ / * Refusing to seal user requests */module.exports = function () { return async (ctx, next) => { const sealList = global.mdb.get(‘sealList’); if (ctx.socket.user && sealList.has(ctx.socket.user.toString())) { return ctx.res = ‘你已经被关进小黑屋中, 请反思后再试’; } await next(); };};其它表情表情是一张雪碧图,点击表情会向输入框插入格式为#(xx)的文本,例如#(滑稽)。在渲染消息时,通过正则匹配将这些文本替换为<img>,并计算出该表情在雪碧图中的位置,然后渲染到页面上不设置src会显示一个边框,需要将src设置为一张透明图function convertExpression(txt) { return txt.replace( /#(([\u4e00-\u9fa5a-z]+))/g, (r, e) => { const index = expressions.default.indexOf(e); if (index !== -1) { return class="expression-baidu" src="${transparentImage}" style="background-position: left ${-30 * index}px;" onerror="this.style.display='none'" alt="${r}"&gt;; } return r; }, );}表情包搜索的爬https://www.doutula.com上的搜…const res = await axios.get(https://www.doutula.com/search?keyword=${encodeURIComponent(keywords)});assert(res.status === 200, ‘搜索表情包失败, 请重试’);const images = res.data.match(/data-original="[^ “]+"/g) || [];return images.map(i => i.substring(15, i.length - 1));桌面消息通知效果如上图,不同系统/浏览器在样式上会有区别经常有人问到这个是怎么实现的,其实是HTML5增加的功能Notification粘贴发图监听paste事件,获取粘贴内容,如果包含Files类型内容,则读取内容并生成Image对象。注意:通过该方式拿到的图片,会比原图片体积大很多,因此最好压缩一下再使用@autobindhandlePaste(e) { const { items, types } = (e.clipboardData || e.originalEvent.clipboardData); // 如果包含文件内容 if (types.indexOf(‘Files’) > -1) { for (let index = 0; index < items.length; index++) { const item = items[index]; if (item.kind === ‘file’) { const file = item.getAsFile(); if (file) { const that = this; const reader = new FileReader(); reader.onloadend = function () { const image = new Image(); image.onload = () => { // 获取到 image 图片对象 }; image.src = this.result; }; reader.readAsDataURL(file); } } } e.preventDefault(); }}后话想把前端学好,js真的真的很重要!!!我的web前端学习q.u.n【731771211】,学习资源免费分享,五年资深前端攻城狮在线课堂讲解实战技术。欢迎新手,进阶点击:加入 ...

November 23, 2018 · 6 min · jiezi

高级 Vue 组件模式 (9)

09 使用 Functional 组件目标到此为止,我们的 toggle 组件已经足够强大以及好用了,因此这篇文章不会再为它增加新的特性。如果你是从第一篇文章一直读到这里的读者,你一定会发现,整篇文章中,我几乎没有对 toggle-on 和 toggle-off 做出任何更改和重构,因此这篇文章着重来重构一下它们。之前一直没有对它们进行任何更改,一个很重要的原因是因为它们足够简单,组件内部没有任何 data 状态,仅靠外部传入的 prop 属性 on 来决定内部渲染逻辑。这听起来似乎有些耳熟啊,没错,它们就是在上一篇文章中所提及的木偶组件(Dump Component)。在 Vue 中,这种类型的组件也可以叫做函数式组件(Functional Component)。仔细观察 app 组件的模板代码,会发现存在一定的冗余性的,比如:<toggle-on :on=“status.on”>{{firstTimes}}</toggle-on><toggle-off :on=“status.on”>{{firstTimes}}</toggle-off>这里两行代码的逻辑几乎一模一样,但我们却要写两次。同时你还会发现一个问题,由于其内部的渲染逻辑是通过 v-if 来描述的,实际上在 Vue 渲染完成后,会渲染两个 dom 节点,在切换时的状态从 devtool 中观察的效果大概是这样子的:未显示的节点是一个注释节点,而显示的节点是一个 div 节点。这篇文章将着重解决这两个问题:将 toggle-on 和 toggle-off 合二为一,减少代码冗余性重构以 v-if 实现的渲染逻辑,改为更好的动态渲染逻辑(仅使用一个 dom 节点)实现转化为函数式组件首先,先将已经存在的 toggle-on 和 toggle-off 组件转化为函数式组件,很简单,只需保留 template 代码块即可,同时在左边的标签上声明 functional 属性,或者在 script 代码块中声明 functional: true 也是可以的。唯一要注意的是,由于函数式组件没有 data 也没有 this,因此所有模板中用到的与 prop 相关的渲染逻辑,都要作出相应更改,比如原先的 on 要改为 props.on的形式,由于这里我们要移除 v-if 的渲染逻辑,因此直接移除即可,详细代码如下:// ToggleOn.vue<template functional> <div class=“toggle-on”><slot></slot></div></template><style>.toggle-on { color: #86d993;}</style>// ToggleOff.vue<template functional> <div class=“toggle-off”><slot></slot></div></template><style>.toggle-off { color: red;}</style>除此之外,还可以发现,我为两个组件增加不同的颜色样式以便于区分当前的开关状态。实现 ToggleStatus 组件接下来实现今天的主角,ToggleStatus 组件,由于我们的目标是将原先的二个函数式组件合二为一,因此这个组件本身应当也是一个函数式组件,不过我们需要使用另外一种写法,如下:<script>import ToggleOn from ‘./ToggleOn’import ToggleOff from ‘./ToggleOff’export default { functional: true, render(createElement, {props, data, children}) { let Comp = ToggleOff if(props.on) Comp = ToggleOn return createElement(Comp, data, children) }}</script>关于这种写法中,render 和 createElement 方法的参数就不赘述了,不熟悉的读者请参考官方文档。可以发现,这里将 toggle-on 和 toggle-off 以模块的形式导入,之后由 props.on 的值进行判定,从而决定哪一个被作为 createElement 方法的第一个参数进行渲染。诸如 data 和 children 参数我们原封不动的传入 createElement 即可,因为这里对于 toggle-status 组件的定位是一个代理组件,对于其他参数以及子元素应当原封不动的传递给被代理的组件中。之后在 app 组件中更改响应的渲染逻辑即可,如下:// controlled toggle<toggle-status :on=“status.on”>{{firstTimes}}</toggle-status>// uncontrolled toggle<toggle-status :on=“status.on”>{{secondTimes}}</toggle-status>成果一切如原先一样,只不过这次我们可以少写一行冗余的代码了。同时打开 devtool 可以发现,两种状态的组件会复用同一个 dom 节点,如下:你可以通过下面的链接来看看这个组件的实现代码以及演示:sandbox: 在线演示github: part-9总结关于函数式组件,我是在 React 中第一次接触,其形式和它的名字一样,就是一个函数。这种组件和普通组件相比的优势主要在于,它是无状态的,这意味着它的可测试性和可读性更好,同时一些情况下,渲染开销也更小。我们在日常工作中,可能会经常遇到动态渲染的需求,一般情况下,我们均会通过 v-if 来解决,在比较简单的情况下,v-if 确实一种很简单且高效的方式,但是随着组件复杂度的上升,很可能会出现面条式的代码,可读性和可测试性都大打折扣,这是不妨换一个角度从渲染机制本身将组件重构为更小的颗粒,并用一个函数式组件动态的代理它们,可能会得到更好的效果,举一个比较常见的例子,比如表单系统中的表单项,一般都具有多种渲染状态,如编辑状态、浏览状态、禁用状态等等,这时利用该模式来抽离不同状态的渲染逻辑就非常不错。目录github gist ...

October 29, 2018 · 1 min · jiezi

高级 Vue 组件模式 (8)

08 使用 Control Props目标在第七篇文章中,我们对 toggle 组件进行了重构,使父组件能够传入开关状态的初始值,同时还可以传入自定义的状态重置逻辑。虽然父组件拥有了改变 toggle 组件内部状态的途径,但是如果进一步思考的话,父组件并没有绝对的控制权。在一些业务场景,我们期望父组件对于子组件的状态,拥有绝对的控制权。熟悉 React 的读者一定不会对智能组件(Smart Component)和木偶组件(Dump Component)感到陌生。对于后者,其父组件一定对其拥有绝对控制权,因为它内部没有状态,渲染逻辑完全取决于父组件所传 props 的值。而对于前者则相反,由于组件内部会有自己的状态,它内部的渲染逻辑由父组件所传 props 与其内部状态共同决定。这篇文章将着重解决这个问题,如果能够使一个智能组件的状态变得可控,即:toggle 组件的开关状态应该完全由 prop 属性 on 的值决定当没有 on 属性时,toggle 组件的开关状态降级为内部管理额外地,我们还将实现一个小需求,toggle 组件的开关状态至多切换四次,如果超过四次,则需点击重置后,才能够重新对开关切换状态进行切换。实现判定组件是否受控由于 toggle 组件为一个智能组件,我们需要提供一个判定它是否受控的方式。很简单,由目标中的第一点可知,当父组件传入了 on 属性后,toggle 处于被控制的状态,否则则没有,于是可以利用 Vue 组件的 computed 特性,声明一个 isOnControlled 计算属性,如下:computed: { isOnControlled() { return this.on !== undefined; }}其内部逻辑很简单,就是判定 prop 属性 on 的值是否为 undefined,如果是,则未被父组件控制,反之,则被父组件控制。更改 on 的声明方式由于要满足目标中提及的第二点,关于 prop 属性 on 的声明,我们要做出一些调整,如下:on: { type: Boolean, default: undefined},就是简单地将默认值,由 false 改为了 undefined,这么做的原因是因为,按照之前的写法,如果 on 未由父组件传入,则默认值为 false,那么 toggle 组件会认为父组件实际传入了一个值为 false 的 on 属性,因此会将其内部的开关状态控制为关,而非降级为内部管理开关状态。实现状态解析逻辑之前的实现中,通过 scope-slot 注入插槽的状态完全取决于组件内部 status 的值,我们需要改变状态的注入逻辑。当组件受控时,其开关状态应该与 prop 属性保持一致,反之,则和原来一样。因此编写一个叫做 controlledStatus 的计算属性:controlledStatus() { return this.isOnControlled ? { on: this.on } : this.status;}这里利用了之前声明的 isOnControlled 属性来判断当前组件是否处于受控状态。之后相应地把模板中开关状态的注入逻辑也进行更改:<slot :status=“controlledStatus” :toggle=“toggle” :reset=“reset”></slot>相应地,除了开关状态的注入逻辑,toggle 方法和 reset 方法的注入逻辑也需要更改,至于为什么,就交由读者自行思考得出答案吧,这里简单罗列实现代码,以供参考:// toggle 方法toggle() { if (this.isOnControlled) { this.$emit(“toggle”, !this.on); } else { this.status.on = !this.status.on; this.$emit(“toggle”, this.status.on); }}// reset 方法reset() { if (this.isOnControlled) { Promise.resolve(this.onReset(!this.on)).then(on => { this.$emit(“reset”, on); }); } else { Promise.resolve(this.onReset(this.status.on)).then(on => { this.status.on = on || false; this.$emit(“reset”, this.status.on); }); }}总体上的思路是,如果组件受控,则传入回调方法中的开关状态参数,是在触发相应事件后,由 prop 属性 on 得出的组件在下一时刻,应当处于的状态。这么说可能有点绕,换句话说就是,当组件状态发生更改时,如果当前的 on 属性为 true(开关状态为开),则组件本该处于关的状态,但由于组件受控,则它内部不能直接将开关状态更改为关,而是依旧保持为开,但是它会将 false(开关状态为关)作为参数传入触发事件,这将告知父组件,当前组件的下一个状态为关,至于父组件是否同意将其状态更改为关则有父组件决定。如果组件不受控,开关状态由组件内部自行管理,那和之前的实现逻辑是一模一样的,保留之前的代码即可。成果当 toggle 组件被改造后,实现这个需求就很容易了。关于实现的代码,这里就不进行罗列了,有兴趣可以通过在线代码链接进行查看,十分简单,这里仅简单附上一个最终的动态效果图:你可以下面的链接来看看这个组件的实现代码以及演示:sandbox: 在线演示github: part-8总结关于 Controlled Component 和 Uncontrolled Component 的概念,我第一次是在 React 中关于表单的介绍中接触到的。实际工作中,大部分对于状态可控的需求也都存在于表单组件中,之所以存在这样的需求,是因为表单系统往往是复杂的,将其实现为智能组件,往往内部状态过于复杂,而如果实现为木偶组件,代码结构或者实现逻辑又过于繁琐,这时如果可以借鉴这种模式的话,往往可以达到事半功倍的效果。目录github gist ...

October 29, 2018 · 1 min · jiezi

高级 Vue 组件模式 (7)

07 使用 State Initializers目标到目前为止,仅从 toggle 组件自身的角度来看,它已经可以满足大多数的业务场景了。但我们会发现一个问题,就是当前 toggle 组件的状态对于调用者来说,完全是黑盒状态,即调用者无法初始化,也无法更改组件的开关状态,这在一些场景无法满足需求。对于无法初始化开关状态的问题,倒是很好解决,我们可以在 toggle 组件声明一个 prop 属性 on 来代表组件的默认开关状态,同时在 mounted 生命周期函数中将这个默认值同步到组件 data 相应的属性中去。对于无法更改开关状态的问题,似乎无法简单通过声明一个 prop 属性的方式来解决,并且如果我们期望的更改逻辑是异步的话,同样无法满足。因此这篇文章着重来解决这两个问题:toggle 组件能够支持开关状态的初始化功能toggle 组件能够提供一个 reset 方法以供重置开关状态重置开关状态可以以异步的方式进行实现初始化开关状态为了使 toggle 组件能够支持默认状态的传入,我们采用声明 prop 属性的方式,如下:on: { type: Boolean, default: false}之后在其 mounted 生命周期对开关状态进行同步,如下:mounted() { this.status.on = this.on; }这样当我们期望 toggle 以开的状态进行渲染时,可以这样调用组件:<toggle :on=“true” @toggle=“onToggle”> …</toggle>重置开关状态为了能够从外部更改 toggle 组件的开关状态,我们可以在组件内部声明一个观测 on prop 属性的监听器,比如:watch: { on(val){ // do something… }}但如果这么做,会存在一个问题,即目标中关于开关状态的更改逻辑的编写者是组件调用者,而 watch 函数的编写者是组件实现者,由于实现者无法预知调用者更改状态的逻辑,所以使用 watch 是无法满足条件的。让我们换一个角度来思考问题,既然实现者无法预知调用者的逻辑,何不把重置开关状态的逻辑全部交由调用者来实现?别忘了 Vue 组件也是可以传入 Function 类型的 prop 属性的,如下:onReset: { type: Function, default: () => this.on},这样就将提供重置状态的逻辑暴露给了组件调用者,当然,如果调用者没有提供相关重置逻辑,组件内部会自动降级为使用 on 属性来作为重置的状态值。组件内部额外声明一个 reset 方法,在其内部重置当前的开关状态,如下:reset(){ this.status.on = this.onReset(this.status.on) this.$emit(“reset”, this.status.on)}这里会首先以当前开关状态为参数,调用 onReset 方法,再将返回值赋值给当前状态,并触发一个 reset 事件以供父组件订阅。之后在 app 组件中,可以按如下方式传入 onReset 函数,并编写具体的重置逻辑:// template<toggle :on=“false” @toggle=“onToggle” :on-reset=“resetToTrue”>…</toggle>// script…resetToTrue(on) { return true;},…运行效果如下:支持异步重置在实现同步重置的基础上,实现异步重置十分简单,通常情况下,处理异步较好的方式是使用 Promise,使用 callback 也可以,使用 Observable 也是不错的选择,这里我们选择 Promise。由于要同时处理同步和异步两种情况,只需把同步情况视为异步情况即可,比如以下两种情况在效果上是等价的:// syncthis.status.on = this.onReset(this.status.on)// asyncPromise.resolve(this.onReset(this.status.on)) .then(on => { this.status.on = on })而 onReset 函数如果返回的是一个 Promise 实例的话,Promise.resolve 也会正确解析到当它为 fullfill 状态的值,这样关于 reset 方法我们改版如下:reset(){ Promise.resolve(this.onReset(this.status.on)) .then(on => { this.status.on = on this.$emit(“reset”, this.status.on) })}在 app 组件中,可以传入一个异步的重置逻辑,这里就不贴代码了,直接上一个运行截图,组件会在点击重置按钮后 1 秒后,重置为开状态:成果你可以下面的链接来看看这个组件的实现代码以及演示:sandbox: 在线演示github: part-7总结Function 类型的 prop 属性在一些情况下非常有用,比如文章中提及的状态初始化,这其实是工厂模式的一种体现,在其他的框架中也有体现,比如 React 中,HOC 中提及的 render props 就是一种比较具体的应用,Angular 在声明具有循环依赖的 Module 时,可以通过 () => Module 的方式进行声明等等。目录github gist ...

October 26, 2018 · 1 min · jiezi

前端周刊第 4 期

周刊是个人本周内看到的有意思的东西,或是技术学习的好文章或好资源,收集分享给大家。开源库&框架动向Java 11 (LTS) 版本正式发布TypeScript 发布 3.1.1 版本Create React App v2.0.0 支持 CSS Modules 等较多新特性Angular 6.1.9 版本发布和 7.0.0-beta.7 发布本周观点中美贸易会影响国内企业投资动向,创业公司资金来源如果不足,拿不到投资或者某投资取消,就会直接面临裁员的情况。年底换工作的同学注意选择新东家。如果你不接受工作是生活的很大的一部分,那找工作的时候就不要加入创业公司;如果加入,那就不要抱怨加班的情况。小技巧 Tips使用Chrome DevTools 查看 CSS 和 JS 代码覆盖率还是 Chrome DevTools 技巧,你可能没用过的小技巧使用Chrome 调试的时候,可以看我们网站引入的 CSS 和 JavaScript 使用 情况,也就是可以看到用户加载、分析和评估的未使用的代码有多少。操作方式,F12打开控制台,windows下 Ctrl+Shit+P ,输入 Coverage ,选择 Show Coverage 打开分析面板,再点击刷新重新加载页面即可得到分析结果。如GIF 操作图片,知识星球的WEB页面,红色为未使用过(未运行)的代码。可想而知,我们加载了很多多余浪费的代码。所以 CodeSplitting 优化是很有必要的。书籍 & 电子书Java_Bookshttps://github.com/zzhi/Java_Books Java 编程书籍分享开源项目/Demogenerator-jhipsterhttps://github.com/jhipster/generator-jhipster一个想法看着不错的解决方案,前后端整站自动生成,数据源等也灵活配置。后端同学可以了解一下。觉得类似的包装日后可以自己做一下,或者基于别人的去修改。实现开箱可用的架构方案,对于一些项目快速开发比较实用。alibaba/easyexcelhttps://github.com/alibaba/easyexcel阿里巴巴团队开源的快速、简单避免OOM的java处理Excel工具graphql-editorhttps://github.com/slothking-online/graphql-editor这个 GraphQL 可视化编辑器工具graphql-apishttps://github.com/APIs-guru/graphql-apis公开的GraphQL APIs列表收集。(平时写前端demo需要用GraphQL API时直接找这种调用,不需要自己搭)converse.jshttps://github.com/conversejs/converse.js用JavaScript编写的基于web的XMPP/Jabber 聊天客户端winxin-app-watch-lifeWordPress版微信小程序https://github.com/iamxjb/win…BGAQRCode-AndroidQRCode 扫描二维码、扫描条形码、相册获取图片后识别、生成带 Logo 二维码、支持微博微信 QQ 二维码扫描样式https://github.com/bingoogola…WechatLuckyMoneyhttps://github.com/veryyoung/…网友实现的微信红包自动领取功能(android版),实现原理大致为监听红包信息,然后触发走腾讯的com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI 红包初始化入库,自动“开”红包。好文章近两万字小程序攻略发布了https://juejin.im/post/5b8fd1…一文读懂前端缓存https://mp.weixin.qq.com/s/kn…盘点 React 16.0 ~ 16.5 主要更新及其应用https://zhuanlan.zhihu.com/p/…RxJS 优质文章翻译https://github.com/RxJS-CN/rx…好产品世上最好用的JavaScript表格——ag-gridhttps://www.ag-grid.com官网demo体验一下就知道多么强大了。功能上,可以说,没有什么满足不了你的。大量数据渲染性能上也是绝对最快的。PixelSnaphttps://getpixelsnap.com/PixelSnap: “The fastest way to measure everything on screen.” 最快的方式测量屏幕上所有东西的尺寸,切图必备(收费,不贵)CodeSandboxhttps://codesandbox.ioThe online code editor for Web ,代码沙箱,前端代码在线编辑器,Web在线编程时代的到来。网友开发了个markdown解析库,将markdown代码解析成运行在codesandbox例子。也可以顺便了解一下:https://github.com/djyde/markbox变色避孕套(非IT业界产品)国外中学生发明了可以病毒检测的避孕套,避孕套会根据不同病毒变成不同颜色,没有性病的时候是透明的,有病就会变色,可以检测艾滋病等常见性病。创新不错,并且还是中学生。欢迎订阅(原周报改名为周刊更合适)这个专栏每周末发布,同步更新在 前端学堂、微信公众号。本篇同步发布于微信公众号:giscafer ...

September 30, 2018 · 1 min · jiezi

前端系列——查找字符串B的字符任意一种组合是否是字符串A的子串

题目要求这道算法题在前端面试中可能遇到,据说某条出过这题。查找字符串B的字符任意一种组合是否是字符串A的子串。例如 A=abc123,B=cba,则B的其中一种组合abc是A的子串,然后返回true。算法思路题目的出处已经无从考究,接下来我们从JavaScript的角度来封装这样一个功能函数。穷举一开始看到这道题,你会想到什么?我想到的是先列举出B的所有排列组合,存到数组里面,然后遍历,判断是否有组合包含在A中,如果有返回true,否则返回false。如果从题目给出的例子来穷举,一共6种组合,很容易穷举出来,但是字符串长度非常大的时候,怎么办呢?所以,穷举的办法被我排除了。标记删除法这名字听起来很奇怪,怎么个思路呢?1、A的排序肯定是不变的,既然可变的我们很难下手,那么可以从不变的地方入手,以不变应万变。 2、看字符串可能不太习惯,我把A和B都转换成数组。let a = A.split(’’) // [a, b, c, 1, 2, 3]let b = B.split(’’) // [c, b, a]3、先过滤数组为空的情况,如果a或者b为空,那么不需要比较,返回false。if (a.length === 0 || b.length === 0) { return false}4、只看数组b,可以有6种排列组合,[c,b,a],[a,b,c],[a,c,b],[b,a,c],[b,c,a],[c,a,b]。还记得第1步说的,我们不管b有多少种组合,都从a入手。// a = [a, b, c, 1, 2, 3]for (let j = 0; j < a.length; j++) { }5、遍历a有什么作用呢?接下来我为大家揭晓何为标记删除法,允许我小小解释一下该方法,分为2个核心,“标记”和“删除”,“标记”是指标记当前数组a遍历的位置,“删除”是指删除数组b中的元素。这样说可能不太懂,先不看代码,我用数组来模拟一下执行过程。初始化的值a = [a, b, c, 1, 2, 3]b = [c, b, a]==================================================当遍历a的时候,j从0开始,遍历到a.length-1结束==================================================j = 0 // 给a里的字符加’’,做个标记,表示当前遍历的下标位置a = [‘a’, b, c, 1, 2, 3]==================================================然后我们发现数组b存在当前的字符’a’,执行删除操作b = [c, b]==================================================j = 1 // 数组a遍历到第二个字符a = [a, ‘b’, c, 1, 2, 3] // 标记b = [b] // 删除==================================================j = 1 // 数组a遍历到第三个字符a = [a, b, ‘c’, 1, 2, 3] // 标记b = [] // 删除==================================================现在我们看到b数组变成空了,则证明b的任意一种排列存在于a中6、上一步描述的情况是最简单的状态,刚好在A字符中存在不间断的字符组合。我们把A改一下,变成 A = a1b2c3abc。即使变复杂了,我们依旧可以使用标记删除发来做,只是稍微做一点处理。初始化的值a = [a, 1, b, 2, c, 3, a, b, c]b = [c, b, a]==================================================当遍历a的时候,j从0开始,遍历到a.length-1结束==================================================j = 0 // 给a里的字符加’’,做个标记,表示当前遍历的下标位置a = [‘a’, 1, b, 2, c, 3, a, b, c]==================================================然后我们发现数组b存在当前的字符’a’,执行删除操作b = [c, b]==================================================j = 1 // 数组a遍历到第二个字符a = [a, ‘1’, b, 2, c, 3, a, b, c] // 标记// 突然发现第2个字符是1,现在该怎么办?我们只需要把数组b恢复初始状态即可b = [c, b, a] // 恢复初始状态 ==================================================接下来继续遍历,重复上面的处理步骤,直到数组b为空或者数组a遍历完成,返回结果7、JavaScript代码实现下面是第6步说明的代码实现,从代码中可以看到,不管B字符有多少排列组合,我们始终只需要遍历A的所有字符即可,内部实现也是用空间换时间。// 遍历数组 a for (let j = 0; j < a.length; j++) { // 数组 b不为空,下一步 if (b.length > 0) { // 数组a存在当前遍历的数组b的元素 if (b.indexOf(a[j]) > -1) { // 删除b数组中匹配到的第一个对应下标的元素 b.splice(b.indexOf(a[j]), 1) if (b.length === 0) { // 如果数组b全部被删除了,则证明b是a的子串 return true } } else { // 数组b不存在当前遍历的数组b的元素,恢复b数组 b = B.split(’’) } } else { // 数组 b为空返回true return true } }总结与其他前端工程师的交流中,我还了解到了其他的解题思路,有些很有趣,比如考虑使用Map或Set、滑块区间比较等,不过我没有去用代码实现过,如果你有其他的方法,可以在下面留言交流。完整源码评论区有人指出不能覆盖某些场景的测试用例,所以我对上面的具体过程做了改进,下面是改进后的源码。增加了2个字段,isBack和isRestart,isRestart用来标记是否重新在当前位置遍历,isBack判断是否对数组遍历的下标进行回退一个单位。var A = ‘abc123’ , B = ‘cba’function interface(A, B) { // 将A和B转成数组 let a = A.split(’’) let b = B.split(’’) if (a.length === 0 || b.length === 0) { return false } let isBack = false, isRestart = 0 // 遍历数组 a for (let j = 0; j < a.length; j++) { // 数组 b不为空,下一步 if (b.length > 0) { isBack = false // 数组a存在当前遍历的数组b的元素 if (b.indexOf(a[j]) > -1) { // 删除b数组中匹配到的第一个对应下标的元素 b.splice(b.indexOf(a[j]), 1) if (b.length === 0) { // 如果数组b全部被删除了,则证明b是a的子串 return true } } else { if (isRestart !== 0) { isBack = false } else { isBack = true } // 数组b不存在当前遍历的数组b的元素,恢复b数组 b = B.split(’’) if (isBack) { j -= 1 isRestart = 0 } isRestart++ } } else { // 数组 b为空返回true return true } } return false}interface(A, B) ...

September 26, 2018 · 2 min · jiezi