看完这篇文章,你将了解

  • 作用域链是什么
  • 微任务 & 宏任务
  • 三元运算符中 ++ 的执行顺序
  • forEach 方法详细
  • 字节与位数的关系

作用域链

有一个问题

下面哪种方式不能改变作用域链?while, try catch, eval, with

第一反应,作用域链到底是什么

根据一篇博客

所谓作用域链就是:一个函数体中嵌套了多层函数体,并在不同的函数体中定义了同一变量, 当其中一个函数访问这个变量时,便会形成一条作用域链。

红皮书第四章:虽然执行环境的类型总共只有两种:全局和局部(函数),但还是有其他办法来延长作用域链。有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。在两种情况下会发生这种现象:

  • try catch语句的catch块;
  • with语句;

实例

//catch语句
var e = new Error('a');
try {
throw new Error('b');
} catch (e) {
console.log(e.message); //b
}

//with语句
foo = "window";
function first(){
 var foo = "first";
 function second(){
    var foo = "second";
    console.log(foo);
 }
 function third(obj){
    console.log(foo); //first
    with (obj){
        console.log(foo); //obj
    }
    console.log(foo); //first
 }
 var obj = {foo:'obj'};
third(obj);
}
first();

eval 负责把字符串转换为js代码,如果字符串中有新定义函数,那么它就有可能再建一个执行环境。

微任务 & 宏任务

这一块确实是自己的知识盲区。一时半会看不懂,先记录一下

三元运算符中 ++X 的执行顺序

看一段代码

var x = 10;
var y = 10;
var z = x >= y ? x++ : ++y;
console.log(x, y)  // 输出多少

var x = 10;
var y = 10;
var z = x > y ? x++ : ++y;
console.log(x, y)  // 输出多少

第一个结果是:11 10, 第二个结果是 10 11

这说明:三元运算符不是每条语句都会执行,它的执行顺序是

  • 先执行判断语句
  • 再根据情况选择一条语句执行,一条不执行

个人理解

var z
if(x >= y) {
    z = x++
} else {
    z = ++y
}

进一步理解 forEach 类方法

有一道题,如何将集合 A 转化为数组

Array.from(A) // √
[...A] // √
[].slice.apply(A) // x
[].map.call(A, o => o) // x

前两个无需解释,好奇的是后两个在什么条件下才成立

根据控制台试验,结合之前的博客,我的判断是:要将一个对象用后两者转化为数组,需要满足两个条件:

  • 对象有数字键, {“0”: xx, "1": yy} 这样
  • 对象有 length 属性

即该对象必须是伪数组对象

就是长得像数组的对象,拥有0,1,2,3…以及length等key,但是在原型链中没有Array.prototype这一环

伪数组对象没有数组方法,却想调用数组方法。因此采用这两种有点 trick 的方法来实现。而集合 A 不是伪数组对象,因此这两种方法也就对它无效。

细节

  • 如果不设置过期时间,Cookie 默认在关闭浏览器后过期
  • NaN == NaN 是 false
  • JavaScript内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。
  • 字节 === Byte,一个字节/Byte === 8位二进制数