整理前端小知识(还须补充)

88 阅读4分钟

1.js的执行

单线程

主要是event loop 事件循环执行

js---宏任务

先执行同步再执行异步任务

先执行宏任务,在看微任务是否有微任务,有就执行,执行有再执行宏任务,再看是否有微任务,没有就执行宏认为,一直到任务执行

闭包 --如何访问变量

定义

什么是闭包?《JavaScript高级程序设计》是这样定义的:

闭包是指有权访问另一个函数作用域中变量的函数。

我们来看下下面这段代码:

function a () {
  var x = 12;
  return function () {
    var y = 10;
    return x + y;
  }
}

var b = a();
b(); // 22复制代码

上面代码中,在全局执行上下文中定义了一个函数a和变量b,函数a内部返回一个匿名函数,所以此刻匿名函数的作用域链初始化为包含了全局变量对象和a中的变量对象,当执行var b = a()时,把函数a的执行上下文压栈,当a执行完后按理a的执行上下文应该出栈,但是因为a内部的匿名函数作用域链还引用这a的变量x,所以a的执行上下文得不到释放,这样就形成了闭包,当执行到b()时把a中的匿名函数的执行上下文入栈,此时栈中有三个执行上下文。

作用域链指向的变量对象

上面讲过作用域链就是指向变量对象的指针,所以闭包只能取得包含函数中任何变量的最后一个值,如下代码:

function a () {
  var arr = [];

  for (var i = 0; i <= 10; i++) {
    arr[i] = function () {
      return i;
    } 
  }

  return arr;  // [10,10,...,10]
}

上面代码返回10个10,因为里面的每个匿名函数的作用域链上的变量对象i是指向同一个变量i,所以它们的值都相等,我们可以修改代码如下:

function a () {
  var arr = [];

  for (var i = 0; i < 12; i++) {
    arr[i] = function (num) {
      return num;
    }(i); 
  }

  return arr;
}

这种方法把当前i的值传递给匿名函数的参数num,然后立即执行(IIFE)返回给数组的相应项;

执行上下文

简而言之,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行。

从他的类型上来分,我们可以将其分为三类:

全局执行上下文、函数执行上下文、Eval 函数执行上下文。

全局执行上下文是是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中,它只有一个。它做了两件事:

  • 1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。
  • 2. 将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文

函数执行上下文是指在每次调用函数时,都会为该函数创建一个新的执行上下文,这就是函数执行上下文,他可以有无数个。有多少个函数就有多少个函数执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤。

Eval 函数执行上下文:是指运行在 eval 函数中的代码创建的自己的执行上下文。eval并不推荐使用,基本上可以算作是一个作废的东西,在这里简单说一下为什么不用他,首先就是他破坏代码结构不利于阅读,而且很多人会用错他,既然经常用错了,那还不如不用;然后就是麻烦,在其中运行的代码没办法调试。我们都习惯了chrome进行断点调试功能,可以方便快捷的定位错误原因,但是他没办法调试,所以还是不要用了;还有就是性能问题,在旧的浏览器中如果你使用了eval,性能会下降10倍。在现代浏览器中有两种编译模式:fast path和slow path。fast path是编译那些稳定和可预测(stable and predictable)的代码。而明显的,eval不可预测,所以将会使用slow path ,所以会慢。还有一个是,在使用类似于Closure Compiler等压缩(混淆)代码时,使用eval会报错,又慢有报错的东西干嘛还要用呢,对吧。

原型链

在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做 __proto__ 的内置属性,用于指向创建它的函数对象的原型对象 prototype。以上面的例子为例:

console.log(person.__proto__ === Person.prototype)  // true