• js最基础的作用域问题


    1、什么是作用域?

    每个变量和函数,都有其作用的范围,超出这个范围,就不能使用了,这个范围就叫做“作用域”,我们举个例子,一个文件中的变,在另一个文件中直接访问,是访问不到的,两个文件是两个“域”,两个文件中的私有量,另一个文件无法访问,因为超出了“域”。

    2、我们想用另一个文件中的变量,怎么办?把两个文件合并到一起吧,是不是就可以用了?我们可以把两个文件称为“局部作用域”,把合并后的文件称为“全局作用域”。如果在函数内部,我们直接使用一个量,例如下面的例子,在test中直接使用a,程序会先在test中查找,不管是在使用a前,还是在使用a后,函数内部只要定义了a,那么程序就认为,a现在是局部作用的,不用再“提升”到全局去查找了,由于这个例子实在后面定义的,这时alert(a) // undefined。如果,test函数内部从前到后,并没有定义变量a,这时程序在test内找不到var a = xxxx,才会把查找a定义的过程放大到全局,发现全局定义了var a = 'aa',这时alert(a) // aa。这个查找的过程的顺序,叫做“作用域链”。

    函数可以自动“预解析”,即便是在使用函数的语句后面定义,也可以把函数定义先解析,再使用。

    var a = "aa"
    function test() {
        alert(a) // undefined, 在函数内部,找到了定义,所以不会往上层去找,但是还没有执行到,所以undefined
        var a = 'bb'
        alert(a) // 找到局部作用域,且有值,返回“bb”
    }
    test()
    alert(a) // 在全局作用下找到的a = "aa", 直接返回
    test() // 和上次执行的结果一致,不受第一次执行的影响

    //相当于这样写:
    var a = "aa"
    function test() {
       var a //定义提前
    alert(a)
        var a = 'bb' //赋值不变
        alert(a)
    }
    test()
    alert(a)
     
    function test2() {
        b() // 函数可以“预解析”,正确执行
        var a = 1
        function b() {
            console.log(1)
            console.log(a) // undefined,找到了定义在下面的a,不再往外层找
            var a = 2 // 内层函数的a定义
        }
        console.log(a) // 外层函数的a
    }
    test2() // 1   undefined    1

    再来看一个例子:(内部可以访问外部,但外部的不能访问内部的 

    var a=10; 
    function aaa(){ 
       alert(a);
    };            
    function bbb(){
      var a=20;
      aaa();
    }
    bbb(); //结果为10,在bbb中执行aaa,相当于aaa自己直接调用,此时调用aaa的this指向window
    // 所以无法往下层去找变量,访问不到bbb()里面的局部变量,所以访问到的是全局的a=10。不要被写在bbb中迷惑了

    继续上例子:(只要不是用var (ES6-),就会定义成全局变量)

    function aaa(){
       a=10; 
    }
    aaa();
    alert(a); //结果为10; 
    //等价于:
    var a;
    function aaa(){
       a=10;
    };
    aaa();
    alert(a);

     再来一个:

    function aaa(){
        a=10; 
    }
    alert(a); // 报错,虽说不写var,可以成为全局变量,但是要先调用函数,经过aaa的使用,才可以成为全局的,否则aaa不使用,外面的谁也别想用

    // 改成这样,就成为全局变量了:
    function aaa(){
        a=10; 
    }
    aaa() alert(a);

     更上一层楼:

    var i = 10 // 全局变量
    function a() {
        i = 20 // 局部变量
        console.log(i) // 20
        for (var i = 0; i < 6; i++) {
            console.log(i) // 0-5
        }
        console.log(this.i) // 执行a(),相当于window.a(),当前this指向window,所以是全局变量10
        console.log(i) // 6: 0-5之后,i++ => 6
    }
    a()
    console.log(i) // 全局变量10

     高级点的:

    var x = 1
    function a() {
        console.log(x)
        setTimeout(() => {
            console.log(x, "SetTimeut")
        })
        new Promise(resolve => {
            console.log(x, "Promise")
            resolve()
            console.log(2)
        }).then(() => {
            console.log(x, 'then')
        })
        var x = 'hello world'
        console.log(x)
    }
    a() 

    // undefined , undefinde "Promise", 2, hello word,
    // hello word "then", hello world 'setTimeout'

    再高级一点: with语句作用域分析:MDN中给出with的解释是:扩展一个语句的作用域链。JavaScript查找某个未使用命名空间(可以理解为未定义)的变量时,会通过作用域链来查找,作用域链是跟执行代码的context(当前作用域)或者包含这个变量的函数有关。'with'语句將某个对象添加到作用域链的顶部,如果在statement(with内部语句)中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出ReferenceError异常。

    with (expression) {
        statement
    }
    function f(x, o) {
      with (o) 
        print(x);
    }

    f被调用时,x有可能能取到值,也可能是undefined,如果能取到, 有可能是在o上取的值,如果o中没有这个属性的话,就去取函数的第一个参数x的值。如果你忘记在作为第二个参数的对象o中定义x这个属性,程序并不会报错,只是取到另一个值而已。

    function f(foo, values) {
        with (foo) {
            console.log(values)
        }
    }

    如果是在ECMAScript 5环境调用f([1,2,3], obj),则with语句中变量values将指向函数的第二个参数values。但是,ECMAScript 6标准给Array.prototype添加了一个新属性values,所有数组实例将继承这个属性。所以在ECMAScript 6环境中,with语句中变量values将指向[1,2,3].values

    看个例子:

    var a = 1
    function f() {
        var o = {a: 3}
        with (o) {
            console.log(a); // 现在a在函数内部未定义,但是with依然可以去参数中查找,发现o中有a属性,不再去全局查找,所以要取o.a = 3
            var a = 2 // 因为o中有a,所以 这里的a 指向 o.a
            console.log(o.a) // 2
            console.log(a) // 这里的a 也是指o.a
        }
    }
    f()
  • 相关阅读:
    剑指offer--2.替换空格
    剑指offer--1.二维数组中的查找
    poj-1426-Find The Multiple(打表水过)
    hdoj-3791-二叉搜索树(二叉搜索树模板题)
    hdoj-1276-士兵队列训练问题(队列模拟)
    HihoCoder
    CodeForces-831A-Unimodal Array (水题)
    hdoj-1046-Gridland(规律题)
    hdoj-1038-Biker's Trip Odometer(水题)
    hdoj-1037-Keep on Truckin'(水题)
  • 原文地址:https://www.cnblogs.com/whq920729/p/10763375.html
Copyright © 2020-2023  润新知