在JavaScript中,用var申明的变量实际上是有作用域的
如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量,(这点跟c一样)
function foo(){var x=1;};//在foo内定义了变量x
x=x+2;
ReferenceError: x is not defined
如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响
function foo(){var x=1;};
function bar() { var x = 'A'; }
两个函数内都定义了x,但不会冲突
由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行
function foo() {
var x = 1;
function bar() { var y = x + 1; }//bar可以访问外部变量x
var z = y + 1;//foo无法访问内部的y
}
foo()
ReferenceError: y is not defined
如果内部函数和外部函数的变量名重名
function foo()
{
var x = 1;
function bar() { var x = 'A'; alert('x in bar() = ' + x); }
alert('x in foo() = ' + x);
bar();
}
//x in foo()=1,x in bar()='A'
JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部
function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob'; }
foo();//Hello, undefined
语句var x = 'Hello, ’ + y;并不报错,原因是变量y在稍后申明了,在执行的时候变量被提升到了顶部,所以不会报错没有定义
但是alert显示Hello, undefined,说明变量y的值undefined
这关系到JavaScript原理
因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值,所以不会报错未定义,但只会显示y为undefined
不在任何函数内定义的变量就具有全局作用域
实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性
javascript直接调用的函数,定义好的变量,其实都是window这个对象的属性,window是javascript最大的对象
var course = 'Learn JavaScript';
alert(course);
alert(window.course);
window.course===course;//true
直接访问全局变量course和访问window.course是完全一样的
由于函数定义有两种方式,以变量方式var foo = function () {}定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象
function foo() { alert('foo'); }
foo()
window.foo()
window.foo()===foo()
true
window.foo===foo
true
我们每次直接调用的系统函数比如说alert()函数其实也是window的一个变量(属性)
window.alert('调用window.alert()');
window.alert===alert
true
把alert保存到另一个变量
var old_alert = window.alert; //把alert赋值给一个新的变量
old_alert('我是老的alert');
window.alert = console.log;//把alert变成终端显示
window.alert('我坏了');//变成了终端显示,我坏了
alert('我也出问题了');//我也出问题了 ,别忘记啦window.alert===alert
window.alert = old_alert; //修复alert
alert('又可以用alert()了!');
这说明JavaScript实际上只有一个全局作用域
任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError错误
全局变量会绑定到window上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都 会造成命名冲突,并且很难被发现。 减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中
var Mywindow={};//定义了我们自己使用的window全局变量,避免冲突
Mywindow.name='我自己的window';//定义了我们window下的一个变量name
name;//""因为我们name绑定的不是window,所以这里显示为空
Mywindow;//对象下面有name变量Object { name: "我自己的window" }
Mywindow.name;//"我自己的window"
注意在我们定义的对象里面定义变量,不能用var,用.就行,否则会报错
var Mywindow.name='我自己的window'
SyntaxError: unexpected token: '.'
当然啦,也可以在对象下面定义函数
Mywindow.foo=function (){console.log('哈哈')}
foo
ReferenceError: foo is not defined
Mywindow.foo()
哈哈
把自己的代码全部放入唯一的名字空间对象中,会大大减少全局变量冲突的可能
由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的
function foo() {
for (var i=0; i<100; i++) {}
i += 100;
console.log(i);}
foo()
200
本来我们只想让i在for里面使用,但是外部仍然可以引用变量i
为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量
function foo() { for (let i=0; i<100; i++) { }i += 1; }
foo()
ReferenceError: i is not defined
如果要申明一个常量,ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域
const PI = 3.14;
PI = 3;//TypeError: invalid assignment to const `PI'
PI;//3.14