Appearance
老师你好!我语义化标签用得很少,多数用到的是 header、footer、 nav 等语义化标签,想问老师 section 和 div 混合使用,会不会效果不好呢?
答:不会效果不好的,因为本来就是这么用的。遇到不确定的情况,请千万不要乱用标签, 用 div 和 span 就好。
我一直看见闭包这个词,但是一直也没有弄清楚它是什么东西,老师可以简单概括一下什么是闭包吗?
答:你可以这样理解,闭包其实就是函数,还是能访问外面变量的函数。
“事实上,JavaScript 中的“类”仅仅是运行时对象的一个私有属性,而 JavaScript 中是无法自定义类型的。”
- 文中说“类”是私有属性,可以具体表现是什么,不是很能理解具体含义?
答:私有属性当然是你无法访问的属性了,但是具体表现的话,还是有的,那就是 Object.prorotype.toString.call(x) 的行为。
- 无法自定义类型?请问如下编码是属于什么操作,应该怎么理解这个“类”?
function Person(){}
var person = new Person();
答:这个代码是定义类的操作,这里注意一下,你千万不要把类和类型的概念混淆。
请教老师在对象中 name(){} 等同于 name: function() {} ,这两个写法有什么区别呢?
答:这两个写法在使用上基本没什么区别。只有一点区别,就是函数的 name 属性不一样。 可以看下这段代码:
var o = {
myfunc(){}
}
console.log(o.myfunc.name)
我们这里按照你的第一种方法定义了方法,然后输出它的 name 属性,我们看到 name 属性 是"myfunc"。
值得一提的是,如果我们给你的第二种方法添加了名字,行为还是不一样,区别在于能否在 函数内用名字递归,我们看看代码:
var o2 = {
myfunc(){
consoe.log(myfunc); //error
}
}
var o1 = {
myfunc: function myfunc(){
consoe.log(myfunc); //function myfunc
}
}
o1.myfunc();
o2.myfunc();
这段代码中,我们试着在用两种方式定义的方法中输出函数自身的名字变量,结果是不一样 的。
不过现实中,我们几乎不会关心函数的 name 属性,所以不用太在意两种定义方式的区别。
我对于 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,应该是参考了某一版本旧引擎给出来的数据。所以,这类行为我们还是以实 测为准吧,我们不必纠结。
老师您好,下面这个自己练习的例子希望您能帮解答:
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');
答:这个例子挺经典的,虽然我觉得这样设计面试题非常不合适,但是我们可以以它为例, 学习一下分析异步的方法。
首先我们看第一遍同步执行,这是第一个宏任务。
第一个宏任务中,调用了三次 setTimeout(Promise 中的代码也是同步执行的),调用了 一次 resolve,打印了三次。
所以它产生了三个宏任务,一个微任务,两次打印。
那么,首先显示的就是 sync1、promise 和 sync2。这时 ,setTimeout1,setTimeoutPromise,last_setTimeout 在宏任务队列中,pro_then 在微 任务队列中。
接下来,因为微任务队列没空,第一个宏任务没有结束,继续执行微任务队列,所以 pro_then,被显示出来,然后又调用了一次 setTimeout,所以 pro_timeout 进入宏任务队 列,成为第 5 个宏任务。
然后,没有微任务了,执行第二个宏任务,所以接下来顺次执行宏任务,显示 setTimeout1,setTimeoutPromise,last_setTimeout,pro_timeout。
最终显示顺序是这样的。
- 宏任务 1
- 微任务 1
- sync 1
- promise
- sync 2
- 微任务 2
- pro_then
- 微任务 1
- 宏任务 2
- setTimeout1
- 宏任务 3
- setTimeoutPromise
- 宏任务 4
- last_setTimeout
- 宏任务 5
- pro_timeout
什么 promise.then 中的 settimeout 是最后打印的?不用管是宏任务依次执行吗?
答:因为 then 是第一个宏任务中最后执行的微任务,所以它发起的宏任务是最后入队的, 依次执行就是最后。
怎么确定这个微任务属于一个宏任务呢,JavaScript 主线程跑下来,遇到 setTImeout 会放到异步队列宏任务中,那下面的遇到的 promise 怎么判断出它是属于这个宏任务呢?
resolve 在哪个宏任务中调用,对应的 then 里的微任务就属于哪个宏任务。宏任务没有从 异步队列中取出,中间所碰到的所有微任务都属于这个宏任务。
为什么要设计微任务(micro task),我知道这样 JavaScript 引擎可以自主地执行任务,但这样的好处是什么?提高性能吗?
不是,微任务是 JavaScript 引擎内部的一种机制,如果不设计微任务,那么 JavaScript 引擎中就完全没有异步了呀,所以必须要设计微任务。
页面资源的预加载是不是可以用 link 标签实现,还有其他的方式吗?
答:预加载的方法就多啦,还可以用 JavaScript 代码预加载,甚至用本地存储缓存。
“词法环境”和“词法作用域”这两个概念的区别是什么?
答:词法环境是运行时概念,词法作用域是语言概念,就是说,作用域指的是变量生效的那 段代码,而词法环境是指运行起来之后,你这段代码访问的存储变量的内存块。
import 进来的引用为什么可以获取到最新的值,是类似于 getter 的机制吗?
答:这个地方略微有些复杂,我们在运行时并没有讲 import 的运行时机制,这里涉及了一 个叫做 ImportEntry Record 的机制,它比 getter 的实现更底层。
我想这个地方我们没有必要去深究模块的运行时机制,它很复杂而且并不是经常要用到。你 如果想了解的话,可以查阅一下。
浏览器的鼠标事件是怎么识别到的,是碰撞检测的吗?
答:这里的检测方式是从外到内,逐级分配给子元素,所以我们的事件会有捕获过程。
关于 Undefined ,如果一个变量没有赋值后面又赋值,这个过程就是“变量会被篡改”的意思么?而 null 为什么又不会被篡改?一个变量开始定义为 null 然后赋值其他数据这个过程不算篡改吗?
答:undefined 是个全局变量,null 是个关键字,在一些版本比较旧的浏览器上,你可以 试试:
undefined = 1;
但是你在任何版本的浏览器上,都不能这么干:
null = 1;
这样的话,上面这个代码就会报错了。
如何做性能监控呢,如何做页面加载优化呢
前端性能打分可能主要包含几个部分。
- 图片:检查图片数量和图片大小,比如单个超过 50k,总量超过 400k 的图片就要注意了 ,如果检查到小图片,也可以建议用 data uri 内联。
- 请求数:检查请求数,检查是否有独立的 JS、CSS 请求,这些都是潜在的优化点。域名 :检查域名是否有在 http dns 的范围内,检查域名数量是否过多,检查资源文件域名是 否属于 CDN。
- 实际加载时间:如果测试环境加载时间过程,也可能说明一些问题。
- 缓存:检查静态资源是否设置了正确的缓存。
函数调用和函数执行有什么区别? 有没有相应的标准?
答:我们一般讲“A 函数调用了 B 函数”“浏览器执行了 B 函数”,所以你看,两者的区别是 主语不同,你可以感受一下区别。它们对应的标准都是 ECMA262。
为什么 flexible 布局方案不再维护了呢?这个方案本身存在问题吗?
答:不存在问题,但是 rem 计算是个历史方案,现在,我比较推荐大家使用 vw。
喜欢使用 let 和 const,看很多库里面,他们都喜欢使用 const,并且推荐使用 const,比如声明一个数组。
答:性能好一些完全是乱说的,用 const 的话,可以避免你误把数组整个赋值掉,比较有 安全感吧。
最近一直在研究前端性能优化和线上错误收集,收效甚微,老师可以讲解一下大厂是怎么处理的吗?
答:这一部分,首先你需要一个比较通用的日志服务,能接受前端用 HTTP 请求的方式打一 些日志进去,一般公司都会有这样的系统,如果没有,就需要新建一个,这部分比较麻烦, 需要一定的专业知识。
有了这个日志服务,剩下的就是在每个前端页面插入一个 JavaScript 代码,监听 Window.onerror 可以得到错误,取 window.performance 可以得到性能,拿到以后,打日 志就行了。
至于后续怎么去展示,展示了以后又怎么去推动执行,这块就需要你自己根据公司实际情况 去找到解决方案了。