You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
13 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 期中答疑 | name(){}与name: function() {},两种写法有什么区别吗?
你好我是winter。
随着专栏进度过半,我们专栏的评论区留言量也日渐上涨。除了大家的小作业和学习心得,我还看见很多同学们在学习过程中提出了不少问题。
这其实是一种很好的学习方式,通过问题,我们可以对这部分知识记得更为牢固。
所以,我鼓励你在阅读文章之外,多思考,多提问,把自己不懂的地方暴露出来,及时查缺补漏,这样可以更好地吸收知识。同时,你也可以通过回答别人的问题来检验自己对知识的掌握情况。
我们一起来看看,大家都提出什么问题。
* * *
**1.老师你好我语义化标签用得很少多数用到的是header、footer、 nav等语义化标签想问老师section和div混合使用会不会效果不好呢**
不会效果不好的因为本来就是这么用的。遇到不确定的情况请千万不要乱用标签用div和span就好。
**2.我一直看见闭包这个词,但是一直也没有弄清楚它是什么东西,老师可以简单概括一下什么是闭包吗?**
答:你可以这样理解,闭包其实就是函数,还是能访问外面变量的函数。
**3.“事实上JavaScript 中的“类”仅仅是运行时对象的一个私有属性,而 JavaScript 中是无法自定义类型的。”**
* **文中说“类”是私有属性,可以具体表现是什么,不是很能理解具体含义?**
私有属性当然是你无法访问的属性了但是具体表现的话还是有的那就是Object.prorotype.toString.call(x) 的行为。
* **无法自定义类型?请问如下编码是属于什么操作,应该怎么理解这个“类”?**
```
function Person
var person = new Person
```
答:这个代码是定义类的操作,这里注意一下,你千万不要把类和类型的概念混淆。
**4.请教老师在对象中`name(){}` 等同于`name: function() {}` ,这两个写法有什么区别呢?**
这两个写法在使用上基本没什么区别。只有一点区别就是函数的name属性不一样。可以看下这段代码
```JavaScript
var o = {
myfunc(){}
}
console.log(o.myfunc.name)
```
我们这里按照你的第一种方法定义了方法然后输出它的name属性我们看到name属性是"myfunc"。
值得一提的是,如果我们给你的第二种方法添加了名字,行为还是不一样,区别在于能否在函数内用名字递归,我们看看代码:
```JavaScript
var o2 = {
myfunc(){
consoe.log(myfunc); //error
}
}
var o1 = {
myfunc: function myfunc(){
consoe.log(myfunc); //function myfunc
}
}
o1.myfunc();
o2.myfunc();
```
这段代码中,我们试着在用两种方式定义的方法中输出函数自身的名字变量,结果是不一样的。
不过现实中我们几乎不会关心函数的name属性所以不用太在意两种定义方式的区别。
**5.我对于JavaScript中Number安全整数有个疑问。**
**MDN中是-(2^53-1)~(2^53-1), 犀牛书中是(-2^53~2^53感觉都有道理。**
**JavaScript中采用IEEE754浮点数标准进行存储 1个符号位11位指数位 52位尾数位。**
**按照分析不考虑符号位尾数位取值52个1就是表示的最大值了不会有精度损失此时指数位代表数值是52+1023=1075此时即为(-(2^53-1)~(2^53-1))。**
**但是2^53这个值存储的时候尾数是52个0 指数位为53+1023=1076这个值也是刚好没有精度损失的这时表示的就是-2^53~2^53。**
**用Math.isSafeInteger()判断安全数范围和MDN中描述一样。****所以被问到这个的时候, 感觉两个都是有道理的吧!老师你说对吗?**
你分析得非常好我觉得我都没啥可补充的了。这个地方JavaScript标准写得也非常模糊我简单瞄了一下似乎是用实验的方式来给出的安全数范围。考虑到犀牛书的时效性肯定不如MDN应该是参考了某一版本旧引擎给出来的数据。
所以,这类行为我们还是以实测为准吧,我们不必纠结。
**6.老师您好,下面这个自己练习的例子希望您能帮解答:**
```
console.log('sync1');
setTimeout(function () {
console.log('setTimeout1')
}, 0);
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('setTimeoutPromise')
}, 0);
console.log('promise');
resolve();
});
promise.then(() => {
console.log('pro_then');
setTimeout(() => {
console.log('pro_timeout');
}, 0)
})
setTimeout(function () {
console.log('last_setTimeout')
}, 0);
console.log('sync2');
```
答:这个例子挺经典的,虽然我觉得这样设计面试题非常不合适,但是我们可以以它为例,学习一下分析异步的方法。
首先我们看第一遍同步执行,这是第一个宏任务。
第一个宏任务中调用了三次setTimeoutPromise中的代码也是同步执行的调用了一次resolve打印了三次。
所以它产生了三个宏任务,一个微任务,两次打印。
那么,首先显示的就是 sync1、promise 和 sync2。这时setTimeout1setTimeoutPromiselast\_setTimeout在宏任务队列中pro\_then在微任务队列中。
接下来因为微任务队列没空第一个宏任务没有结束继续执行微任务队列所以pro\_then被显示出来然后又调用了一次setTimeout所以pro\_timeout进入宏任务队列成为第5个宏任务。
然后没有微任务了执行第二个宏任务所以接下来顺次执行宏任务显示setTimeout1setTimeoutPromiselast\_setTimeoutpro\_timeout。
最终显示顺序是这样的。
* **宏任务1**
* 微任务1
* sync 1
* promise
* sync 2
* 微任务2
* pro\_then
* **宏任务2**
* setTimeout1
* **宏任务3**
* setTimeoutPromise
* **宏任务4**
* last\_setTimeout
* **宏任务5**
* pro\_timeout
**7.为什么 promise.then中的settimeout是最后打印的不用管是宏任务依次执行吗**
因为then是第一个宏任务中最后执行的微任务所以它发起的宏任务是最后入队的依次执行就是最后。
**8.怎么确定这个微任务属于一个宏任务呢JavaScript主线程跑下来遇到setTImeout会放到异步队列宏任务中那下面的遇到的promise怎么判断出它是属于这个宏任务呢**
resolve在哪个宏任务中调用对应的then里的微任务就属于哪个宏任务。宏任务没有从异步队列中取出中间所碰到的所有微任务都属于这个宏任务。
**9.为什么要设计微任务micro task我知道这样JavaScript引擎可以自主地执行任务但这样的好处是什么提高性能吗**
不是微任务是JavaScript引擎内部的一种机制如果不设计微任务那么JavaScript引擎中就完全没有异步了呀所以必须要设计微任务。
**10.现在浏览器多数实现是从右往左匹配的,那么无法保证选择器在 DOM 树构建到当前节点时已经可以准确判断当前节点是否被选中。现在浏览器又是怎么实现在生成DOM树同时进行CSS属性计算**
答:其实现代浏览器已经为`:empty`、`:last`等伪元素写了很多例外了,不过你说的从右往左匹配,左边的要么是当前节点的父元素,要么是前置元素,所以是可以保证准确判断的呀。
**11.请问老师页面资源的预加载是不是可以用link标签实现还有其他的方式吗**
预加载的方法就多啦还可以用JavaScript代码预加载甚至用本地存储缓存。
**12.老师,我有一个疑问:“词法环境”和“词法作用域”这两个概念的区别是什么?希望你能帮我解惑。**
答:词法环境是运行时概念,词法作用域是语言概念,就是说,作用域指的是变量生效的那段代码,而词法环境是指运行起来之后,你这段代码访问的存储变量的内存块。
**13.想问一个问题import 进来的引用为什么可以获取到最新的值,是类似于 getter 的机制吗?**
这个地方略微有些复杂我们在运行时并没有讲import的运行时机制这里涉及了一个叫做ImportEntry Record的机制它比getter的实现更底层。
我想这个地方我们没有必要去深究模块的运行时机制,它很复杂而且并不是经常要用到。你如果想了解的话,可以查阅一下。
**14.请问老师JavaScript 的call stack size是多少这个size的单位是啥是调用栈中函数的个数还是一个存储单位比如MB之类的。如果调用栈中就一个函数这个函数的参数有100万个浏览器端依然会溢出看起来是存储单位但是没得到验证。**
这个似乎并没有什么特别规定我知道JSC里面这个东西是可以用C++代码来调整的至于浏览器调用JavaScript引擎的时候会怎么做还真不好说。
不过从编码风格上建议不要把这种事情用函数解决啦真要干这样的事数组可能都不合适了请老老实实写ArrayBuffer吧。
**15.老师您好,我一直有一个困惑,浏览器的鼠标事件是怎么识别到的,是碰撞检测的吗?**
这个问题很不错我后面在浏览器API的事件部分会详细讲可以先简单说一下这里的检测方式是从外到内逐级分配给子元素所以我们的事件会有捕获过程。
**16.有个问题如果我javaScript代码改变了DOM树元素的位置需要启动重新排版位置改变的元素只会影响其他部分元素的位置甚至不影响其他元素的位置。这时会导致这棵DOM树的所有元素都需要重新排版、绘制和渲染吗**
答:排版应该是会重新排的,但是如果有些元素的尺寸没有改变,那么它内部不需要重排,当然也就更不需要重新渲染了,但是绘制应该是要重绘的,目前来看,浏览器还没有那么智能。
**17.老师我是12年左右踏进半只脚到前端领域的后来考研就放弃了觉得前端不够高深和传统工程师来说觉得门槛低很多甚至前期我都觉得自己不是个程序员。**
**直到研究生毕业,才又选择前端,这是三大框架风靡,我却有点迷惘,感觉和自己认知的前端不一样,直到现在工作了差不多两年,才悟出了点道道。**
**作为工程师,我始终觉得前端也应该熟练算法和数据结构、数据库这些所谓的后端知识,但是平时工作场景中用到又少,不知如何学习?**
答:算法和数据结构可不是什么后端知识呀,是所有程序员的基本技能。
算法主要是靠大量练习提高,数据结构可以一个一个学习,不要指望工作中用到恰巧就学了,毕竟学习要教学费而工作是领工资的,哪里会有这样的好事呢,所以还是自己多多练习呀。
**18.重学前端是夯实前端基础,那前端进阶方向在哪里?还是一定要修一门后端语言扩展服务端,希望老师可以指点迷津。**
答:我觉得任何编程相关岗位的进阶方式都是做出某某东西,而不是学会某某东西。我会在专栏课程的第四模块会讲到一些进阶可能的方向,你可以关注一下。
**19.我主业是后端工作中也会带着做前端自认还是能完美还原设计师的设计。但是现在感觉很多时候提前端就是vue等而我还是在用jQuery想请老师说说看我是不是落伍了**
答:落伍的问题不是你用什么框架,而是你在做什么东西,学什么东西。
框架不是赶时髦,追潮流,每个框架都有解决的问题,我觉得你该焦虑的不是你用的框架为什么这么老,而是你该知道这些新框架要解决什么问题,以及这些问题为什么在你的工作中不存在。
**最后我们来看看我在JavaScript类型那一篇中给你留的实践问题。**
**如果我们不用原生的Number和parselnt用JavaScript代码实践String到Number该怎么做呢**
答:其实这个问题我在后台没看到特别满意的答案,好像大家都很喜欢偷懒啊。
我这里给你留个例子,处理十进制整数。
```
function atoi(a){
let chars = a.split("").map(e => e.charCodeAt(0) - "0".charCodeAt(0));
let n = 0;
for(var char of chars) {
n *= 10;
n += char;
}
return n;
}
atoi("1001")
```
我比较期待大家有人能写出来带小数,甚至带科学计数法的代码,你可以尝试一下。
好了,今天的答疑环节就进行到这里,你也可以把自己想要解答的问题留言。