作用域、闭包、原型链,到底怎么理解?

理解

  • 作用域
    • 全局作用域
    • 函数作用域
    • 块作用域
    • 作用域链
  • 闭包
  • 原型链
    • 原型
    • 原型链

作用域

作用域基本可以分为三种:全局作用域,函数作用域,块作用域
下面我们一个一个的进行理解,按等级划分来理解。

全局作用域

全局作用域就是在你写的代码里,哪里都可以访问,哪里都可以使用。
作用域、闭包、原型链,到底怎么理解?_第1张图片
a是在全局作用域的变量,所以不管是在函数内部或者任何一个位置,都可以对他进行引用、更改。但b不是全局作用域变量,只能在特定的位置被访问,也就有了局限性。而fun()函数也是在全局作用域中的,所以他在人和地方也可以被访问。

我们把全局作用域等级划分为1,等级最低,任何人都可以对它进行操作。
只要没被函数包裹,等级都是1.

函数作用域

函数作用域顾名思义,也就是只能在函数代码块中起作用的。

我们把函数作用域等级划分为2,等级比1高,可以对1进行操作,但1却不可以
对它操作。但函数作用域自己本身也会有等级的高低之分,比如函数的嵌套,越嵌
套等级越高。

作用域、闭包、原型链,到底怎么理解?_第2张图片

为什么等级2是从fun里面开始划分的?

因为fun()函数是在全局作用域中的,里面的代码才是在函数作用域的。
fun2()是在fun()的作用域中,fun2()的作用域要比fun()等级高,等级高的作用域可以使用等级低的作用域里的变量、函数,反过来不行。


块作用域

块作用域使用let 和const命令进行声明,所声明的变量在指定块的作用域外无法被访问。

作用域、闭包、原型链,到底怎么理解?_第3张图片

什么是块作用域?它只能在函数内部或花括号内部被访问。
块作用域好像和函数作用域没有什么区别,但块作用域多了个代码块(花括号)内部。函数作用域仅仅指函数内部,块作用域=函数作用域+if/else/switch/for…这种的花括号。
let声明的变量不会被变量提升,就算我在fun2()中重新声明了b=2,但输出还是5 。如果使用var 定义b,在fun2()中会把b=2提升到最前面,首先执行,输出为2 。
我把带有let/const声明的代码块也设为一个等级。


作用域链

拿我说的等级来说,作用域链就是等级链,等级高的在上层,全局作用域是最下层。
当我们想要访问一个变量,首先在他所在的等级(作用域)中寻找,如果没有,就找他的父层作用域,即向下寻找等级低的看看有没有,直到最下层。

闭包

闭包就是能够读取其他函数内部变量的函数。
作用域、闭包、原型链,到底怎么理解?_第4张图片
inner()函数就是一个闭包,因为它要访问变量a,但在他的作用域中没有找到a,它的等级是3,去等级为2的作用域中找,找到了变量a,而a是不属于它的函数的内部变量,属于outer()函数,所以它读取了其他函数内部的变量。


原型链

原型

作用域、闭包、原型链,到底怎么理解?_第5张图片

  • 每个对象都有_proto_属性,并且指向它的原型对象
  • 每个构造函数都有它的prototype原型对象
  • prototype原型对象里的constructor指向它的构造函数
  • new一个构造函数会形成它的实例对象

原型对象就是一个公共容器,把一些常用的属性和方法储存起来,而构造函数的实例会继承原型对象中的所有属性和方法。

function Cat(name){
    this.name = name;
}
Cat.sex = '女';
Cat.prototype.age = '12';
var cat = new Cat('大黄');
alert(cat.age);//12
alert(cat.sex);//undefine 也就是说明实例只能继承构造函数原型上的属性和方法

原型链

当我们查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去原型对象的原型对象里去寻找… 这个操作就是被委托在整个原型链上。

参考:https://blog.csdn.net/zhang5476499/article/details/90273226

话说原型这里总让我想起之前学java的时候,讲的多态,感觉有点相似。
不过JavaScript也是比较简单的轻量的java,有兴趣的可以再去看看:
java多态

你可能感兴趣的:(js)