JS中的“水花兄弟”--作用域链和原型链

790 阅读4分钟

作用域链

什么是作用域?

  首先我们要知道在ES6之前JS是没有块级作用域的。那时只能通过函数来创建局部作用域,那么作用域到底是什么呢?首先我们需要了解的是作用域做什么的?当JavaScript引擎在某一作用域中遇见变量和函数的时候,需要能够明确变量和函数所对应的值是什么,所以就需要作用域来对变量和函数进行查找,并且还需要确定当前代码是否对该变量具有访问权限。说白了所谓作用域,就是变量或者是函数能作用的范围。

那么JavaScript中有哪些作用域呢?

  • 全局作用域和局部作用域

我们所定义的除了函数里的变量以外的所有变量都在全局作用域内。

    var str ="hello world"
    var arr =[1,2,3]
    var obj ={name:"cxk"}
    var a=1;
    function f(){
        var b=2;
    }

上面定义的所有变量只有b不在全局作用域里,因为b被定义在f函数内,与此同时b所在的作用域就叫做局部作用域。

  • 块级作用域

ES6之后出现了let和const可以定义变量,而它们所定义的变量就存在着块级作用域。

    let a=1;
}
consloe.log(a)

运行代码会报错:a is not defined 代码中的{}就是一个由于let定义变量而形成的块级作用域,a这个变量只有在{}中才能访问。

什么是作用域链?

  变量随着作用长辈函数一级一级往上搜索,直到找到为止,找不到就报错,这个过程就是作用域链起的作用。我们也可以从执行上下文这个角度来理解作用域链这个概念。

  • 全局执行上下文:当我们开始运行代码后,就会形成一个全局执行上下文,这里面包括了全局变量以及没有在任何函数内部的全局函数。全局执行上下文只会在代码运行时创建一次。
  • 函数执行上下文:当我们的代码运行到函数时就会产生一个函数执行上下文,这里面包括了自己函数内部定义的局部变量以及父函数的执行上下文。每调用一次函数就会形成一个函数执行上下文,所以函数执行上下文可以有很多个。
function Outer(){
    var outer = 'outer';
    Inner();
    function Inner(){
        var inner = 'inner';
        console.log(outer,inner) // outer inner
    }
}

当我们调用Inner函数时它会在自己的函数执行上下文找outer和inner变量,结果只找到了inner。那么这时它就去自己的父函数Outer中找outer变量,找到了就返回给Inner函数。所以这种逐级去自己的父函数的执行上下文中搜索变量的方式就是作用域链。

图解:

那么到此作用域和作用域链就介绍完毕了。

原型链

什么是原型?

  在JavaScript中一切皆对象,那么函数也是一个对象。所以这函数里也有很多属性,这其中必然有一个prototype属性

这里的prototype指向的是一个对象(原型对象),原型对象中的方法和属性都可以被函数的实例所共享。所谓的函数实例是指以函数作为构造函数创建的对象,这些对象实例都可以共享构造函数的原型的方法。

什么是原型链?

   var Person = function(name){
    this.name = name;
}
Person.prototype.say = function(){
    console.log( this.name)
};

var person = new Person('cxk');
person.say();//cxk

上面的例子中,对象person是new Person创建的实例,在使用new操作符调用函数时主要执行以下几个步骤:

1,创建新的对象,并将函数的this指向新创建的对象

2,执行函数

3,返回新创建的对象

4,将自己的__proto__(隐式原型对象)指向构造函数的原型对象

与此同时原型对象中的constructor也指向了构造器

由于原型对象也是一个对象,所以它也有一个__proto__指向它的构造器Object,同样的Object也有一个__proto__指向Null。

所以当我们想使用对象的某些方法时例如obj.a()会先到自己的__proto__对象中找,如果没有就会去它的原型对象的原型对象中找,也就是__proto__.proto 。以此类推...

这种搜索的轨迹,形似一条长链,又因prototype在这个游戏规则中充当链接的作用,于是我们把这种实例与原型的链条称作 原型链 。

至此作用域链和原型链介绍完了,如有错误还望指正,谢谢。