1.作用域
全局作用域
函数作用域
没有块块级作用域(ES6之前)
栗子:
if(true){
var a = 3
}
console.log(a) //3
2.作用域的作用:隔离变量,使每个作用域中的同名变量不会相互影响(如,一个函数A中的的a,和函数B中的a相互独立,互不影响)
var a = 10
b = 20
function fn(x) {
var a = 100
c = 300
console.log('fn',a,b,c,x) // fn 100 20 300 10
console.log(d) // 报错
function bar(x) {
var a = 100
d = 200
console.log('bar',a,b,c,d,x)
}
bar(100) // bar 100 20 300 200 100
bar(200) // bar 100 20 300 200 200
}
fn(10)
// 以上例子产生N+1个作用域(N为定义的函数的个数)
//打印的变量时,寻找变量的过程就形成了一条作用于链:现在自身中查找-->若无,往包裹它的外面一层找-->若无,以此类推继续往上找,直到在全局作用域中找,找不到就报错(不可逆向寻找)
3.作用域与执行上下文的对比
联系:执行上下文从属于所在的作用域
(1)全局执行上下文从属于全局作用域
(2)函数执行上下文从属于函数(局部)作用域
区别:
(1)函数的作用域在定义时已经确定,而函数执行上下文则在函数调用时,在即将调用的时候才产生
(2)全局执行上下文是在全局作用域确定之后才产生的
(3)作用域是静态的,在创建后就不会改变;而执行上下文是动态的,比如,函数执行上下文,函数执行结束后就自动释放,函数执行上下文也就不存在了,但是函数的作用域仍然不变
面试题:
题目1:
var x = 10
function fn() {
console.log(x)
}
function test(f) {
var x = 20
f()
}
test(fn) // 10
//或者
var x = 10
function fn() {
console.log(this.x) //因为函数定义时已经确定this,所以在test中调用也不会改变它的this,能改变this的有apply、call、with语句等
}
function test(f) {
var x = 20
f()
}
test(fn) // 10
解析:即使fn是在test中调用的,但是fn在定义时就确定了它的作用域,它内部访问不到x时,直接会去全局作用域中找,而不会去test中找
题目2:
var fn = function () { // fn用var声明,会被放到全局中
console.log(fn)
}
fn() // 输出fn函数体,因为打印语句中的fn在函数自身没有找到,但是在全局中能找到fn
var obj = {
fn1: function () {
console.log(fn1)
// console.log(this.fn1) 因为this指向obj,而obj对象中有属性有fn1,其值是一个函数
}
}
obj.fn1() // 报错,因为打印语句中的fn在函数自身没有找到,在全局中也没有找到