前言
- 这篇文章其实没什么卵用,作用域谁不会啊,但是作用域的一切你已经全部了解了么?
- 如果没有不妨跟着笔者再一次回顾和整理一遍吧
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
}
})();
复制代码