JS作用域
作用域就是变量与函数的可访问范围,控制着变量与函数的可见性和生命周期。分为全局和局部作用域链。
- 全局作用域(Global Scope)
(1)最外层函数和在最外层函数外面定义的变量拥有全局作用域链。
(2)所有未定义直接赋值的变量自动声明为拥有全局变量。
(3)所有window对象的属性 拥有全局作用域。
一般,window对象的内置属性都拥有,例window.name、window.location、window.top等等。
2.局部作用域(Local Scope)
局部作用域一般只在固定的代码片段内可访问到,例如函数内部。
var name = 'zjh'; //全局
function echo() {
blogname = 'MyBlog'; //全局
var authorname = 'zzzz'; //局部
}
JS作用域链
JS权威指南中描述:“javascript中的函数运行在他们被定义的作用域里,而不是它们执行的作用域里。” “一切皆对象,函数也是。
函数对象和其他对象一样,拥有可以通过代码访问的属性和仅供Javascript引擎访问的内部属性,其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合称为函数的作用域链。
当一个函数被创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。
(函数所有的局部变量、命名参数、参数集合以及this)
例:
var name = "zjh";
function echo() {
alert(name);
var name = "eve";
alert(name);
alert(age);
}
echo();
运行结果
underfiend
eve
[脚本出错]
当echo函数被调用的时候,echo的活动对象已经被预编译过程创建
[[scope chain]] = [
{
this : window,
arguments : [],
name : underfined
}
]
作用域链和代码优化
从作用域链的结构可以看出,标识符所在的位置越深,读写速度越慢。因为全局变量总是存在于作用域链的最末端。所以,在编写代码时应尽量少使用全局变量,尽可能使用局部变量。经验法则:如果一个跨作用域的对象被引用了一次以上,则先把它存储在dc局部变量里再使用。
例:
function changeColor(){
document.getElementById("btnChange").onclick=function(){
document.getElementById("targetCanvas").style.backgroundColor="red";
};
}
引用两次document,重写如下:
function changeColor(){
var doc=document;
doc.getElementById("btnChange").onclick=function(){
doc.getElementById("targetCanvas").style.backgroundColor="red";
};
}
Javascript的预编译
<script>
alert(typeof eve); //function
function eve() {
alert('I am Zach');
}
</script>
JS在执行每一段JS代码之前,都会先处理var关键字和function定义时(函数定义式和函数表达式).
在跳用函数之前,首先会创建一个活动对象,然后搜寻这个函数中的局部变量定义和函数定义,将变量名和函数名都做为这个活动对象的同名属性,变量的值会在真正执行的时候才计算,此时只是简单地赋为underfiend.
而对于函数定义式,是一个要注意的地方.
<script>
alert(typeof eve); //function
alert(typeof walle); //underfiend
function eve() { //函数定义式或函数申明
alert('I am Zach');
}
var walle = function() {} //函数表达式
</script>