阅读 68

深入浅出JS - 作用域

前言

  • 这篇文章其实没什么卵用,作用域谁不会啊,但是作用域的一切你已经全部了解了么?
  • 如果没有不妨跟着笔者再一次回顾和整理一遍吧


JS中的作用域是什么?

作用域是什么呢? 它是指的代码在运行时,变量、函数或者对象的可访问性? 还是一个变量和函数的作用范围?又或是如《Know JS》中所说的 作用域是根据名称查找变量的一套规则呢,又或是指的当前代码的执行环境

在笔者的眼里,作用域所指的是规则,一套用来管理变量和函数的作用范围的规则。

var userInfo = 'a';
// 作用域是约束作用范围的规则
function foo() {   
    var userInfo = 'b';   
    console.log(userInfo); // b
}
foo();复制代码

在作用域的规则之下这串代码运行良好,可是没有作用域时呢?外部的userInfo和内部的userInfo互相冲突,还是互相覆盖?我们不得而知。

// 假设不存在作用域, 我们所有的变量都变得混乱了
var userInfo = 'a'
function foo() {   
    var userInfo = 'b'   
    console.log(userInfo); // ?   
    function baz() {      
        var userInfo = 'c'      
        console.log(userInfo); // ?   
    }   
    function log() {      
        var userInfo = 'd'      
        console.log(userInfo); // ?   
    }
}

foo();
复制代码

作用域限制变量的可见性,解决不同范围内的同名变量命名问题。so它是一套规则。在编程语言里会有作用域其实就是为了限制变量的可见性。


作用域能做什么?

作用域为我们的代码提供了一个安全层级,某个作用域内的变量对外部是不可见的,保证了内部变量的安全性,同时作用域也为JS引擎在编译阶段提供依赖于词法作用域的优化,它还解决了不同范围内的同名变量问题。


欺骗作用域

function foo(str, a) {   
    eval(str);   
    console.log(a, b) // 1 3 遮蔽了外部的b
}
var b = 2;
foo("var b = 3;", 1);

function baz(obj) {   
    with(obj) {       
        a = 2;   
    }
}
var o1 = {    
    a: 3
}
var o2 = {    
    b: 3
}
baz(o1);
console.log(o1.a) // 2

baz(o2);
console.log(o2.a); // undefined
console.log(a); // 2 在全局作用域内创建了一个变量复制代码

在非严格模式下,eval和with都会在运行时,修改或创建新的作用域。使得JS引擎在编译阶段无法预先确定所有变量和函数的定义位置。没法进行依赖于词法分析的优化。


作用域链

嵌套作用域的规则很容易理解,当我们使用(解析)一个变量时,如果没有在当前作用域找到该变量时,就会向上一级作用域继续查找,一直到全局作用域。无论找到还是没找到,查找过程都会停止。这种通过嵌套作用域的关系来查找变量的行为就叫作用域链。

var b = 'leaf';
function foo() {   
    var b = 'leaves';   
    (() => {       
        console.log(b)  // leaves   
    })();
}
foo();

var b = 'leaf';
function foo() {    
    // var b = 'leaves';    
    (() => {        
        console.log(b)  // leaf 向上继续查找    
    })();
}
foo();复制代码


利用作用域能做什么

  • 结合闭包持久化存储变量
  • 私有作用域
  • 模块模式

let num = (function() {    
    let num = 1;    
    return function() {        
        console.log(num++)    
    }
})();
num(); // 1
num(); // 2
num(); // 3        

let Obj = function(){};
(function() {     
    var x = 10;     
    function y() {         
        return x++     
    }    
    Obj.prototype.say = function() {         
        console.log(y());   
    };
})();

var ins = new Obj();

ins.say(); // 10
ins.say(); // 11
ins.say(); // 12

let m1 = (function() {    
    function _p1(){

    }    
    function _p2(){

    }    
    return {       
        _p1,      
        _p2
    }
})();
复制代码


参考资料

伯乐在线(理解JavaScript作用域)

《You Don't Know JS》


文章分类
前端
文章标签