作用域
1.javascript局部作用域
变量在函数内部声明,变量为局部作用域.
//局部变量:只能在函数内部访问
function test(){
var name='zdb'
}
console.log(name) //undefined
2.javascript全局变量
//全局变量:函数内部外部都可以访问
var name='zdb'
function test(){
console.log(name) //zdb
}
test()
3.隐式声明
//函数内部没有使用var 声明的变量 会默认认为是全局变量
function test(){
name='zdb'
}
console.log(name) //zdb
[[scope]]作用域
每个javascript函数都是一个对象,对象中有的属性可以访问,有的属性仅供javascript引擎存取[[scope]]就是其中一个,指的是作用域,其中存储了运行期上下文集合.
运行期上下文
当函数执行时,会创建一个称为执行期上下文的内部对象.一个执行期上下文定义了一个执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的上下文被销毁.
- 代码示例
var glob=1000
function test(){
console.log('test')
}
1.test函数声明时,scope[0]里指向全局GO对象
var glob=1000
function test(){
var b=123
console.log(b) //123
}
test()
2.test函数执行时会创建一个独一无二的执行期上下文AO,形成作用域链,AO会默认排到作用域链的最顶端.
- test执行完毕会默认销毁自己的执行上下文AO,回到初始定义状态.
- 代码示例
function a(){
function b(){
var bb=234
aa=0
}
var aa=123;
b();
console.log(aa) //0
}
a()
1.a定义状态,scope[0]里指向全局GO对象
2.a函数执行创建自己的AO,会将自己的AO排到作用域链的最顶端,a执行的时候,定义b函数,b函数定义会自带a函数的AO、GO ,b函数与a函数,指向的是同一个AO.
3.a函数执行过程中,b函数定义被执行,b函数执行创建自己的AO,执行完毕销毁自己的AO,b函数里面查找aa变量统一在作用域链依次由上向下查找,自己的AO里没有找到aa变量,修改的变量aa是a函数AO对象的值.这时aa已被改为0,再次读取aa变量 值为0.
4.b函数执行完毕会销毁自己的AO回到初始状态,其次a函数执行完毕会销毁自己的AO回到初始状态.
- 闭包
一个内层函数中访问到其外层函数的作用域.
- 代码示例
function a(){
function b(){
var bbb=234;
console.log(aaa) //123
}
var aaa=123;
return b;
}
var glob=100;
var demo=a();
demo()
1.a被执行,b被定义时 并将b保存出到函数外部.
2.b函数执行时a函数已执行完毕,a函数会取消指向自己AO的引用,但是b函数还指向a函数的AO引用,b函数在自己执行时会创建自己的AO会默认排到作用域链的最顶端[0]位,b函数读取aaa变量默认会从作用域顶端依次向下查找,这时自己AO没有aaa,a函数的AO里有aaa所以查找结果为123
- 立即执行函数
可以让函数在创建后立即执行.
- 写法一
(function(){
console.log(1)
}())
- 写法二
(function(){
console.log(2)
})()
- 被执行符号执行的表达式,函数名没有意义
//此处函数名没有意义
(function test(){console.log(1)}())
console.log(test) // test is not defined
let test=function demo(){
console.log(11111)
}()
console.log(demo)// demo is not defined
- 只有执行表达式才能被执行符号执行
function test(){
console.log(1111)
}() //error:Unexpected token ')'
//执行符号 * /例外
+ function test(){
console.log(1111)
}() //1111
- function test(){
console.log(1111)
}() //1111
! function test(){
console.log(1111)
}() //1111
- 如果调用传参不会执行,也不会报错
function test(a,b){
console.log(a+b)
}(1,4)
//系统会识别成
function test(a,b){
console.log(a+b)
}
(1,4)
- 立即执行函数应用场景
//可以套用作用域链,梳理逻辑
function test(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=function(){
console.log(i) //10个10
}
}
return arr
}
let myArr=test();
for(var i=0;i<myArr.length;i++){
myArr[i]()
}
//利用自执行函数,生成作用域链
function test(){
var arr=[];
for(var i=0;i<10;i++){
arr[i]=(function(j){
return function (){
console.log(j) //0,1,2,3,4,5,6,7,8,9
}
}(i))
}
return arr
}
let myArr=test();
for(var i=0;i<myArr.length;i++){
myArr[i]()
}