你好,我是winter。
我们专栏课程的知识部分已经告一段落了。今天,我来集中解决一下大家在学习中遇到的问题,我争取用快问快答的形式,咱们多回答一些问题。
1. 前端代码单元测试还是非常有必要的,不知道老师这一块是怎么做的,能否分享一下?
答:关于单元测试这件事,虽然在业务代码我没做成功过,但是它在框架和基础库开发中起到了非常积极的作用。
我们平时写代码也肯定写一部分就要运行一下试试,其实这种行为就是单元测试,只是我们把很多自动化的内容,用人肉执行了,并且没有保存和管理case,也没有统计code coverage。
只要选择一个好的单元测试框架,单元测试成本其实不高,尤其是比较复杂的底层库,引入单元测试不但不会消耗时间,还会提高效率。
所以我认为单元测试要实行,有两个关键点你要格外注意:一是出一套好的单元测试方案,二是在基础库和框架开发中引入单元测试。
2. 关于Undefined ,如果一个变量没有赋值后面又赋值,这个过程就是“变量会被篡改”的意思么?而null 为什么又不会被篡改?一个变量开始定义为 null 然后赋值其他数据这个过程不算篡改吗?
答:undefined是个全局变量,null是个关键字,在一些版本比较旧的浏览器上,你可以试试:
undefined = 1;
但是你在任何版本的浏览器上,都不能这么干:
null = 1;
这样的话,上面这个代码就会报错了。
3. winter老师你好,我们公司的前端是Node.js写的,如何做性能监控呢,如何做页面加载优化呢,我对您的页面性能打分系统很感兴趣,能详细讲一讲吗?谢谢了。
答:首先,Node.js写的是服务端代码跟前端性能没有任何关系,Node.js的性能监控比前端性能监控复杂得多,你可以了解下alinode。
前端性能打分可能主要包含几个部分。
- 图片:检查图片数量和图片大小,比如单个超过50k,总量超过400k的图片就要注意了,如果检查到小图片,也可以建议用data uri内联。
- 请求数:检查请求数,检查是否有独立的JS、CSS请求,这些都是潜在的优化点。
域名:检查域名是否有在http dns的范围内,检查域名数量是否过多,检查资源文件域名是否属于CDN。 - 实际加载时间:如果测试环境加载时间过程,也可能说明一些问题。
- 缓存:检查静态资源是否设置了正确的缓存。
你可以自己动手试试。
4. 有一个疑惑是,大小写的两个属性有什么区别呢,比如:
Screen,screen
Event,event
答:这里面大写的是类,小写的是对象。
5. 我还是比较认同,从左往右匹配的规则,这样就像老师讲的可以在构建DOM树的同时来进行匹配CSS规则,相当于同时构建渲染树了,而不必等到DOM构建完毕再进行CSS的规则匹配。
进行构建渲染树,虽然从右向左匹配对于复杂的选择器更优,但是这里面浪费了等待DOM构建完毕,才能使用的CSS匹配规则。而且相对于同为id等单一选择器而言,明显从左向右更具有优势!这是我的一点想法,望老师指正!
答:其实我在之前的分享中做过一个试验,当时的Chrome确实是从右往左,如果#id在最左,速度会更快,但是那个过程是后添加CSS的情况。
6. 程老师你好。我在很多地方看到的说法是:CSS会阻塞DOM渲染,但不会阻塞DOM的解析,且CSS文件的请求是异步请求。
那么如果按照您所说,DOM的构建和CSS属性的计算是同步的话,head中CSS文件的下载以及CSSOM的rule部分的构建,应该会阻塞HTML的解析和DOM的构建。好像这两种说法之间就有了冲突。麻烦程老师有空的时候可以帮忙解释一下,万分感谢。
答:其实你误解了我的意思,DOM构建的结果到CSS属性计算是个流水线,所以CSS会阻塞CSS计算,不会阻塞DOM构建。
7. 老师,我记得有的书上或者是资料上说超过五次的if else 就最好用 switch case来替换。这样效率更好。您这里为什么说不用这个呢?
答:我在性能部分讲了,“凡是不做profiling的性能优化都是耍流氓”。
具体的话,你可以看一看“43 | 性能:前端的性能到底对业务数据有多大的影响”这一篇。
8. 函数调用和函数执行有什么区别? 有没有相应的标准?
答:我们一般讲“A函数调用了B函数”“浏览器执行了B函数”,所以你看,两者的区别是主语不同,你可以感受一下区别。它们对应的标准都是ECMA262。
9. 请问下老师,为什么flexible布局方案不再维护了呢?这个方案本身存在问题吗?
答:不存在问题,但是rem计算是个历史方案,现在,我比较推荐大家使用vw。
10. 有的工业软件,3D建模的也可以用浏览器来实现了,用的是ThreeJS WebGL,老师了解这些嘛?怎么看待这个发展前景。
答:挺好的,但是我觉得这件事由本来做3D的工程师转型更方便。
11. 最近出于好奇,我clone了github上chrome的源码仓库,发现竟然有12G多,貌似比linux内核的源码还多。个人特别想探索一下浏览器源码,但面对如此庞大的代码,不禁望而生畏,也不知从何下手。
请问老师,浏览器内核源码该如何去研究,skia渲染引擎是最先进吗,svg,canvas,WebGL该如何选择,怎样深入地学习和掌握它们呢?望老师拨冗答疑,谢谢!
答:你先编译通过吧,然后试着跑起来打断点这样子,其实这件事没有捷径,多花些时间就可以。
skia引擎是不是最先进,这事我也不好说,其实在工程领域我们一般不追求“最先进”,我们只需要它“足够先进”。
关于如何选择,我收到了很多问题,不过我其实都不做回答,毕竟我没法替你决定你自己的职业发展道路,这个责任实在是有些重大了。
12.看完老师列出的表格更迷茫了,比如,为什么transform属于level 1,transform不是CSS3里的属性么?level4是什么?是CSS4么?为什么color这种常用属性属于level4?不应该属于level1么?好迷茫哦。
答:我先解释一下你的问题,一方面,level4里有不等于level3里没有,另一个是,W3C定level并不是十分严谨,有从1开始,也有从3开始的。
除此之外,我想提醒一下,这个表格并不是给你去看level的,而是告诉你标准在哪里,让你去读标准的。
13. 请问老师,我后台用的是Tomcat服务器,前端用ajax请求静态资源时会间隔会报412,也就是一次成功进入后台,一次报412,这该怎么解决呢?
答:理论上412意思是你浏览器的问题。从你提供的信息我没法给你解决方案,建议你可以搞一个最小复现环境去Tomcat社区问。
14.老师好,有个疑问: WHATWG 和 W3C 标准以哪个为准,这两个标准有什么区别?是不是相互不认可的。
答:这个问题比较复杂,WHATWG最初是几家不满W3C,出走搞出来的,后来被招安了把HTML5带回了W3C,不过两边出标准的思路还是不太一样,WHATWG是living standard,就是随时更新标准,没有版本的概念,我是个人会倾向于WHATWG版本,因为比较新,而且Chrome跟得比较紧。
15. winter老师好,可以给我讲一下那个presentational attributes ,有些看不懂。
function showThis(){
console.log(this);
}
var o = {
showThis: showThis
}
showThis(); // global
o.showThis(); // o
我知道函数中的this是由调用函数的对象决定的,但这种理解总感觉是由结论推原因;老师能不能讲解下。
答:this是由调用函数的对象决定,这完全是个规定,没有什么原因。(你后面的问题我节选掉了,我其实没太理解到你想表述的意思,你看到了可以再给我留言)。
16. 喜欢使用let和const,看很多库里面,他们都喜欢使用const,并且推荐使用const,比如声明一个数组。
老师能讲解下声明一个数组用let和const有什么区别吗?在操作数组时,都是往数组中push值,原先的变量并物理地址并没有发生变化,如果用let,和用const有什么区别,为什么const的性能会好一点?
答:性能好一些完全是乱说的,用const的话,可以避免你误把数组整个赋值掉,比较有安全感吧。
- 老师我有几个问题希望你回答:
老师讲到:“注意,我们这里讲的渲染过程,是不会把子元素绘制到渲染的位图上的,这样,当父子元素的相对位置发生变化时,可以保证渲染的结果能够最大程度被缓存,减少重新渲染。”
- 缓存的是什么东西,位图吗?如何减少重新渲染的?
- 是不是所有的元素都有对应的位图?
文中你举了两个例子,说如果只有一个位图,任何改变都会引起所有重新渲染。这个好理解,一个大位图就是一个单元,任何的改动相当于这个单元被变了,所以要重新创建这个,这样理解对吗?
但是你下面又说如果不合并,每次还是所有的重新渲染。感觉说的很矛盾啊。希望老师能回答一下我的疑问。
答:缓存的是位图,父子元素位置变化时,因为子元素的位图被缓存,子元素不需要重新渲染,因为父元素的位图也被缓存,父元素也不需要重新渲染,只有父子元素合成起来的位图需要被渲染。
你这样理解是对的,如果不合并,每次改点什么东西,都要重新逐级合成最终的大位图,也相当于重新渲染。
18. 老师,“当没有强制指定文字书写方向时,在左到右文字中插入右到左向文字,会形成一个双向文字盒,反之亦然。”这个能不能给个例子,不明白什么意思。
答:比如你在中文中插入几个阿拉伯语字符,阿拉伯语字符就会形成一个双向文字盒。
19. 看了您的流式数据的解释,是不是可以理解当看到页面渲染的时候,DOM是不是有可能都还没构建完成呢?即使是理论上,有这种可能吗?
答:渲染不但发生在DOM构建之前,甚至可能发生在你下载网页完成之前,比如你上个XX软件下载站,是不是下载链接还没见到,就看到广告了(你提到的网上的那段是别人写错了。我节选掉了)。
20. footer 也可以和 aside,nav,section 相关联(header不存在关联问题),不存在关联问题是什么意思啊,不应该在header中使用吗?下面又说header中可以使用nav,老师的“关联”是什么意思啊?
答:因为footer有自己的语义,footer必须要指明是谁的footer,这样footer中的作者、地址才有意义,所谓的关联就是这个意思了。
21. 子元素的事件委托给父元素时,添加事件监听的第三个参数直接设置为true,在捕获过程就判断父元素上的事件目标会比冒泡好些嘛?
答:对,但是你需要在捕获阶段想办法知道事件具体发生在哪个子元素上。
22. 老师 如果我想更深入的了解移动端的兼容问题,有没有好的学习路线呢?
答:兼容问题不是学出来的,你想在山中苦修,自出洞来无敌手?手机早就更新好几代了。所以兼容问题必须靠实践,在一个需要兼容性的业务上,不断积累和更新兼容性知识。
23. 老师,我在理解SICP这本书的过程抽象和数据抽象的时候,代入到前端,比如生命周期、事件处理等更多是过程的抽象,能提出一些公用的过程,而数据抽象更多指的是组件内的数据定义、api的设计、高阶组件等。
请问我这样理解对吗?或者说老师对过程抽象和数据抽象在前端中怎么理解的?如果理解得不对,有什么好的书或者文章帮助理解?
答:SICP讲的是很实在的编程技巧,在前端中对应的是变量、循环、条件这些东西,SICP是一本好书,你应该更认真地去阅读它。
24. 通过这个课程老师对于前端的划分为JavaScript、HTML和CSS、浏览器、工程实践几个部分。
- 疑问1:现在前端基本把Node也包括进来了,对于Node的知识应该怎么定位?
- 疑问2:Node属于后端的范畴了,是否应该去学习下java相关的后端体系?学习了后端的体系是否会反过来促进前端知识的学习呢。
winter老师对这两个问题怎么看呢?谢谢。
答:Node属于后端,electron属于客户端,不论你学哪个体系,肯定对前端都有促进作用。
但是,你不能认为懂了Node就懂了后端,懂了electron就懂了客户端,每个领域都可以很深入,知识本来就是学不完的,你能掌握多少只跟投入的时间有关,这道理是很简单的,与其困惑,不如把困惑的时间拿来学习,相信你会有所收获的。
25. 老师,CSS是如何依附在DOM树上的?是通过前面讲得Node实例来实现的?
答:在Node实例上添加属性,我在“12 | 浏览器:一个浏览器是如何工作的(阶段三)”讲到了,你可以返回去看看。
26.清楚为什么要使用语义化标签,是否有必要使用之前,很难让自己有动机去应用每个标签。另外标签新推出如何保持实时掌握最新的标签呢,如何解决浏览器兼容的问题?
答:对语义化标签,我是建议不必追求全部掌握,现有需求再找标签即可。
27. 老师您好,有个疑问想请教一下,为啥基于对象关联风格的面向对象并不是像模拟类的行为的面向对象那么流行呢?原型委托这种的不是应该更符合JavaScript语言本身的设计嘛?类似这种:
var father = {
a: 1,
fn(): {
return 123;
}
}
var child = Object.create(father);
child.fn(); // 123
答:大部分人在学校学的都是C++和Java,我就没见过教原型的,这是现实,没办法。
28. 老师,可否稍加解释一下执行上下文的分类? 网络上的文章说“ JavaScript 中可执行的代码可分为三种类型:全局代码、函数代码、eval 代码,对应三种执行上下文(全局执行上下文、函数执行上下文、eval 执行上下文)。
在 ECMAScript 2018 中没有找到这种说法的依据。我的意思是,我不太清楚这些文章的说法是否正确,是否不够全面。
答:这个说法倒不能说不正确,但是严重过时了。
现在ECMAScript 2018里面执行上下文非常复杂,你可以看看各种Record,重学前端课程里面也没有讲全。
29. 老师,在ES5之前版本规范中,会提及JavaScript的可执行代码分为全局、函数、Eval。但是在ES6之后版本规范中,再也不提及可执行代码的概念了,这是为什么呢?
答:其实这里是重构了一下表达方式,新加入了模块什么的。
30. 试过好多次,找了很多方法flex兼容IE9以下,每次都失败,有什么好的解决办法吗?
答:如果真有IE9兼容需求,我想只能单独写一份CSS了。
31. 请问大佬,如何冻结对象,一般什么样的场景可以用到?
答:Object.freeze函数可以冻结对象。一般都是写底层库,希望避免篡改。
32.
new Promise(function(resovle, reject) {
setTimeout(resovle, duration);
})
setTimeout(resovle, duration);和setTimeout(() => {resovle()}, duration);
两者到底有什么区别,想不明白,求教。
答:这个区别不大的,第二种写法一般都是为了给resolve传参数,不过如果你不想给resolve传特定参数,为什么还要多写一个函数呢。
33. 我听JavaScript像听天书,怎么办,是不是要从0重新学起呀?
答:理论上,我的课程是把JavaScript的内容重新组织了一下,如果平时就在用JavaScript,我认为问题不大。如果这部分完全听不懂,可能说明确实基础薄弱,建议你从0学起。
好了,本期的答疑告一段落,如果你还有其他的问题,或者还是没有弄清楚,你可以继续给我留言,我会继续解答大家的问题,并一起讨论。