美文网首页
深入JavaScript之Scope(作用域)以及Context

深入JavaScript之Scope(作用域)以及Context

作者: cab240f6e992 | 来源:发表于2017-10-27 09:39 被阅读0次

Scope和Context: 咱俩不是一个东西

我是Scope(作用域),那是隔壁邻居Context(执行上下文)。总有人以为咱俩是一个东西,但是真的不是啊!记住啊,他是隔壁老C!我先介绍我自己吧。

Scope(作用域)借锤子

对于我Scope, 我先给自己贴个标签——和变量的可见性相关

(╯﹏╰)这么文绉绉的话是不是很不好理解,不好理解就对啦。要不然也不用举个栗子了:

        function community() {
            var hammer = 'The community owns a hammer';

            function myHome() {
                var wifi = 'This is my wifi, you cannot connect!'
                alert(hammer);
            }
            myHome();
            alert(wifi);
        }

        community();

这个栗子会报错,不用慌,让我给你解释解释:
首先呢,社区(community)里有个锤子(hammer),我家(myHome)呢,开着wifi。今天啊,我起了个早,寻思着找个锤子把我家门给钉死咯,以防隔壁家那谁谁谁来串门。在我家找了一圈,发现我家没有锤子,那咋办呢,我就顺着作用域链(Scope chain)爬啊爬,爬到社区。社区老大哥,你家有没有锤子啊,有的话借我使使啊。社区老大哥果然有锤子,而且社区老大哥的锤子的作用域(Scope)覆盖面积贼大,我赶紧拿着就溜回家把门给钉死咯。所以alert(hammer);成功的得到:

alert个锤子
这我刚把门给钉死,社区老大哥就来alert(wifi);他自己又没有wifi,以为能把我内部定义的wifi给alert出来。门都没有!你忘了我把门给钉死了啊?我的wifi的作用域根本出不去!社区老大哥灰头土脸的走了,还在控制台里留下一抹伤心的报错: wifi is not defined

不知道我这么一说,你是不是稍微理解了我给自己加的标签了——和变量的可见性相关
1.wifi呢,是我(myHome)这个函数内部定义的,对于我自己来说那肯定是可见的,也就是说wifi的作用域是在myHome函数内部的,我如果想用wifi那是随便用。
2.锤子呢,虽然是社区老大哥里定义的,但是因为他把我包起来了,那我就可以通过作用域链爬上去借他的锤子使使,所以锤子对于我(myHome)来说,也是可以用的。
3.我的wifi对于社区老大哥来说,那是不可见的,我可以顺着作用域链向上爬拿社区老大哥里的变量,但是他不能往下爬拿我的,这是规则。

你可能要问了,要是你自己也有锤子,社区老大哥那里也有锤子,你拿哪一个呢?
那当然是用我自己的了啊, 吃饱了撑得还爬绳子去拿别人的啊?是想累死我是么!

Context(执行上下文)拿this

这隔壁老C,看名字就贼难理解,还执行上下文?你当这是上语文课呢。算了算了,不调侃他那奇奇怪怪的名字了,等你理解了就会发现这名字取得还挺棒棒棒。接下来让他自己介绍一下吧。

我是Context, 我也给自己打个标签——我和我媳妇this形影不离。

为啥这么说呢,因为好多人一开始并不知道我,是因为想搞懂我媳妇this, 然后听到好多人说要搞懂this, 先要搞懂Context,所以才开始了解我。不是有好多人面试的时候看到各种关于this的面试题吗?看的头都大了,其实搞懂我Context之后,这些就全明白了。

一句话介绍自己Context——函数在被调用时的上下文环境,被调用函数中的this指向该上下文环境。先记住两个字调用!

那么怎么理解函数在被调用时的上下文环境呢?接下来又到了举栗子的时候了,真是百文不如十行代码啊:

  var myName = '温浪';
  function sayName (){
    alert(this.myName);
  }
  sayName();

函数sayName被调用了,那么你想过函数是在哪个环境下被调用吗?在这里函数是在全局环境下被调用的,因此函数中的this指向全局对象——window。因此alert(this.myName);可以输出:

我的名字

上面这个栗子实在来太简单啦,那咱们来点难的加深一下理解:

var name = 'window';
var me = {
  name: '温浪',
  sayName: function() {
    alert(this.name);
  }
}

var myFunction = me.sayName;
myFunction();

输出的不是温浪而是window

window

由此我们得出结论:

函数被调用时,this的指向与函数定义无关,而只与函数被调用时的上下文环境有关!再次强调!调用!

结合DOM事件的Context

通过上面的描述,你理解了函数调用时,this的指向由函数被调用时的我Context决定。那咱们再加点难度,结合DOM事件!
假设有以下代码:

<!DOCTYPE html>
<html>
<head>
    <title>easyTest</title>
</head>
<body>
    <button id="myButton" onClick="testContext()" name="dom">click me</button>
    <script>
        var name = 'window';
        var me = {
            name: '温浪',
            sayName: function() {
                alert(this.name);
            }
        }

        var testContext = me.sayName;
    </script>
</body>
</html>

代码中分别在dom节点对象,window对象和me对象中都定义了name属性,我们的目标是输出me对象中的温浪,那么点击这个button到底会输出哪个name呢?答案是:

如果事件是直接通过inline的方式写在html中,那么this指向window对象。所以输出为window.

window

如果将代码改成下面这样:

<html>
<head>
    <title>easyTest</title>
</head>
<body>
    <button id="myButton" name="dom">click me</button>
    <script>
        var name = 'window';
        var me = {
            name: '温浪',
            sayName: function() {
                alert(this.name);
            }
        }

        var testContext = me.sayName;
        document.getElementById('myButton').addEventListener('click', testContext);
    </script>
</body>
</html>

即通过js添加事件处理,那么会输出什么呢?答案是:

如果通过js添加事件处理,this指向该dom节点,在本例中也就是button节点。所以在点击的时候会alert出button节点上的name。

DOM

绕了一圈还是没有解决问题,现在我们的目标是显示me对象中的name。该怎么办呢, 其实很简单啊,要是你理解了我Context,就知道下面的代码可以解决这个问题:

<!DOCTYPE html>
<html>
<head>
    <title>easyTest</title>
</head>
<body>
    <button id="myButton" name="dom" onclick="me.sayName()">click me</button>
    <script>
        var name = 'window';
        var me = {
            name: '温浪',
            sayName: function() {
                alert(this.name);
            }
        }
    </script>
</body>
</html>

哦!点击button的时候,让me去执行sayName,那么sayName的this就指向了me!成功解决问题!(虽然看上去这个例子很傻,但是希望能加深对Context的理解啦(╯﹏╰))

最后的最后

Scope和Context这两个家伙真是让人头大的不行,键盘都砸烂了!最后的最后,介绍另外两个兄弟,call和apply, 他俩就厉害了,可以手动指定方法被调用时this的指向!戳我去观光call和apply

相关文章

网友评论

      本文标题:深入JavaScript之Scope(作用域)以及Context

      本文链接:https://www.haomeiwen.com/subject/hlvqpxtx.html