这么多年来,大家都会出一些,关于作用域、作用域链、 原型对象、 原型链相关的问题。 那么大家有没有想过, javascript为啥要有这些东西? 有人会说,为了函数编程, 为了继承,为了面向对象... ; 我也觉得他们说的都对,但是没有找到它的本质?
作用域链、原型链的本质就是为了实现JavaScript的局部变量
作用域链
在js中, 一个变量是如何找到它的值? 答案可以理解为就近原则.
debugger;
var a = 123
function foo() {
console.log(a) // undefined
var a = 666
console.log(a) // 666
}
foo()
console.log(a) // 123
作用域
那么你觉得哪些手段能产生作用域呢? 大家动动手看一看?
- 函数作用域? (√)
- 大括号?
- try catch ?
- eval?
- with? (√)
// 大括号
debugger;
var a = 1
{
var a = 2
console.log(a) // 2
}
console.log(a) // 2
// try catch
debugger;
var a = 2
try {
var a = 3
console.log(a) // 3
throw Error()
} catch (e) {
var a = 4
console.log(a) // 4
}
console.log(a) // 4
// eval
debugger;
function foo(str, a) {
eval(str)
console.log(a, b)
}
var b = 2
foo('var b = 3;', 1) // 1,3
通过chrome调试工具可以发现eval其实并不会产生一个作用域, 而是重新启动了个虚拟机,然后把它放置在当前的作用域里
debugger;
var obj = {a:1, b:2}
with(obj) {
a = 'a'
b = 'b'
}
with可以产生一个With Block的作用域
闭包
闭包是啥? 函数就是保留了之前的作用域,作用域你可以理解为是一个对象。那么变量就沿着这个作用域链进行访问
debugger;
var a = -1
function foo() {
var a = 0
return function (str) {
a++
console.log(a)
}
}
var b = foo()
b() // 1
b() // 2
console.log(a) // -1
let,const
debugger;
let a = 'let'
const b = 'const'
console.log(window.a, window.b) // undefined undefined
console.log(a, b) // let const
debugger
var arr = [];
for (var i = 0; i < 3; i++) {
arr[i] = function () {
console.log(i);
};
}
arr.forEach(fn=>fn()) // 3 3 3;
此时访问的是都是window.i
debugger
var arr = [];
for (let i = 0; i < 3; i++) {
arr[i] = function () {
console.log(i);
};
}
arr.forEach(fn=>fn()) // 0 1 2;
看来只有function能够保存之前产生的作用域, 保存了就会产生闭包; 不愧是一等公民!
箭头函数
debugger;
var a = 1
var foo = () => {
console.log(a) // undefined
var a = 666
console.log(a) // 666
}
foo()
console.log(a) // 1
原型链
debugger
function A(name = '') {
if (name) {
this.foo = name
}
}
A.prototype.foo = 'foo'
var a = new A('a')
var b = new A()
console.log(a.foo) // a
console.log(b.foo) // 'foo'
[对象.属性] 是不是跟作用域链类似; 验证原型链去查找局部变量?
小结
- js变量查找的规则就是由近及远
- js局部变量 靠着两条链子, 作用域链(function)、原型链(object)
- 能够产生作用域的有
函数作用域,let/const和with [with一般禁用] 闭包就是保留了之前的作用域, 所以每次都可以访问到
参考
- 你不知道的JavaScript系列