首页 > js关于沿着作用域链或原型链去查找变量

js关于沿着作用域链或原型链去查找变量

我是一个js的初学者,这几天被直接访问标识符和通过this访问标识符搞的头疼,于是大胆的做了一个猜测:
1. 直接访问标识符是通过作用域链进行查找的。
2. 通过this访问标识符是通过原型链来查找的。
然后就开始试了起来!!!!

结合下面的代码来说

var a = "abc";

var obj = {
    a: "def",
    display3: function () {
        var a = "sssss";
        console.log(a);
    },
    display4: function() {
        console.log(this.a);
    }
}

Object.prototype.a = "ghi";

function display1() {
    // var = "hahaha";
    console.log(a)
}

function display2() {
    console.log(this.a);
}

display1(); // "abc"
display2();  // "abc"

obj.display3();
obj.display4();

// display2.call(obj);  // "def"
// display1.call(obj);  // "abc"

首先:
第一个:

调用display1函数,通过作用域链来查找a。此时display1的作用域链为:**display1的活动对象→全局活动对象**,
所以找到了全局活动对象中的"abc",如果在display1中有变量a,那么输出的则是这个变量的值。

第二个

调用diplay2函数,通过原型链来查找a。因为this是基于当前的执行环境绑定的,所以this指向全局变量对象(也就是window),所以找到了"abc"并输出。
**有意思**的是,此时如果我删除window中定义的a="abc", 那么输出结果则是"ghi". 于是回忆了一下自己所学的知识,发现因为window对象是Global对象在浏览器中的表现,然后Global是js中的单体内置对象,那么似乎它也应该继承自Object.prototype, 恩..按照我的猜想,输出结果为"ghi"是情理之中的。

第三个:

通过obj调用display3函数,因为前面没有this,所以是通过作用域链进行查找的,此时display3的作用域链为**display1的活动对象→全局活动对象**,所以输出结果是"abc", 同样,如果我再display3中定义了a,那么输出的则是这个a的值

第四个

通过obj调用display4函数,因为前面有this,所以是通过原型链进行查找的,此时this指向的是obj,所以输出的结果是obj对象中"def",如果我们删除obj中的a属性,那么输出结果则是Object.prototype中的"ghi",如果再删除这个ghi,那么输出结果就是undefined了。

上面这些好像都符合逻辑,可是我又突然发现,当调用display1时,如果删除了作用域链中每个变量对象的a属性,那么输出结果则是"ghi", 这个"ghi"是在Object.prototype中定义的,所以

综合了一下

**1**. 直接访问标识符是通过作用域链和原型链综合进行查找的。
**2**. 通过this访问标识符是通过原型链来查找的。

然后又出现了一个问题:直接访问标识符的查找顺序是 1:先查找作用域链前端的变量对象,然后再查找它的原型,然后再查找作用域链中下一个变量对象,然后再查找它的原型 还是 2: 一直查找作用域链中的变量对象,知道window对象,再查找它的原型呢?

然后又突然发现,在调用display1时,如果display1中没有定义a变量,访问到的则是window中的a = "abc",而不是Object.prototype中的a = "ghi".

所以再综合一下

**1**. 直接访问标识符的顺序是按顺序查找作用域链中的每一个变量对象直至全局变量对象,如果全局变量对象中没有该变量,则沿着window对象的原型链进行查找。
**2**. 通过this访问标识符是通过原型链来查找的。

我去累死了,我也没想到自己写了这么多,大大们如果懒得看就直接看我最终的结论对不对吧。。。!


作用域链是针对函数的,原型链是针对对象的


第一条没啥问题,第二条有问题。this 跟链完全没关系,是执行上下文的一个属性,由caller提供。题主可查更详细信息。

【热门文章】
【热门文章】