自检:前端知识清单——作用域和闭包

前言

题目来自ConardLi的blog
写的是自己的题解,水平有限,所以仅供参考
代码会整合在github,觉得有帮助就给个star吧~

正文

一、Javascript基础

作用域和闭包

三、作用域和闭包

1、理解词法作用域和动态作用域

只有词法作用域,没有真正的动态作用域

2、理解JavaScript的作用域和作用域链

  • 作用域是某个变量,函数,对象的可访问性。
  • 作用域就是一个地盘。
  • 作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6的到来,为我们提供了‘块级作用域’,可通过新增命令let和const来体现。

沿着作用域一层一层往上查找的过程就叫做作用域链

3、理解JavaScript的执行上下文栈,可以应用堆栈信息快速定位问题

一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。

4、this的原理以及几种不同使用场景的取值

this 的取值是函数执行上下文(context)的一部分
严格模式下,禁止this指向全局对象

1、全局&调用普通函数

全局

console.log(this === window)  //true

调用普通函数

var x = 10
function foo(){
  console.log(this === window)  //true
  console.log(this.x);   //10
}

2、构造函数
如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象

function foo(){
  this.x = 10
  console.log(this)        //Foo {x:10}
}
const demo = new foo()
console.log(foo.x);      //10

3、对象的方法
如果函数作为对象的方法时,方法中的 this 指向该对象。

const obj = {
  x: 10,
  foo: function(){
    console.log(this) //obj
    console.log(this.x) //10
  }
}
obj.foo();

有一个比较特殊的情况,就是在对象的方法里面定义方法,就像这样

const obj = {
  x: 10,
  foo: function(){
    console.log(this)
    function f(){
        console.log(this);      //Window
        console.log(this.x);    //undefined
    }
    f()
  }
}

函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window

4、构造函数 prototype 属性

在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。

function Foo(){
    this.x = 10;
}
Foo.prototype.getX = function () {
    console.log(this);        //Foo {x: 10, getX: function}
    console.log(this.x);      //10
}
const foo = new Foo();
foo.getX();

5、函数用 call、apply或者 bind 调用。

var obj = {
    x: 10
}
function foo(){
    console.log(this);     //{x: 10}
    console.log(this.x);   //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();

6、DOM event this

function Listener(){   
    document.getElementById('foo').addEventListener('click', this.handleClick);     //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
}
Listener.prototype.handleClick = function (event) {
    console.log(this);    //
} const listener = new Listener(); document.getElementById('foo').click();

7、箭头函数,this穿透

5、闭包的实现原理和作用,可以列举几个开发中闭包的实际应用

  • 闭包的概念:指有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一个函数。

  • 闭包的作用:访问函数内部变量、保持函数在环境中一直存在,不会被垃圾回收机制处理。

在实际开发中,闭包主要是用来封装变量,收敛权限。

6、理解堆栈溢出和内存泄漏的原理,如何防止

内存泄露:是指申请的内存执行完后没有及时的清理或者销毁,占用空闲内存,内存泄露过多的话,就会导致后面的程序申请不到内存。因此内存泄露会导致内部内存溢出

堆栈溢出:是指内存空间已经被申请完,没有足够的内存提供了

常见的手段是将一个变量置为null,该变量就会被下一轮垃圾回收机制回收。

常见的内存泄露的原因:

  • 全局变量引起的内存泄露
  • 闭包
  • 没有被清除的计时器

解决方法:

  • 减少不必要的全局变量
  • 严格使用闭包(因为闭包会导致内存泄露)
  • 避免死循环的发生

7、如何处理循环的异步操作

async await
递归
设置标记位

8、理解模块化解决的实际问题,可列举几个模块化方案并理解其中原理

解决的问题:

  • Common.js
    引入模块化编程

  • AMD
    1、多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器;
    2、js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长。

  • CMD
    模块定义方式和模块加载(可以说运行、解析)时机上有所不同。

  • ES6 import
    尽量的静态化、使得编译时就能确定模块的依赖关系,以及输入和输出的变量。(CommonJS和AMD模块,都只能在运行时确定这些东西)。

你可能感兴趣的:(自检:前端知识清单——作用域和闭包)