假如你没去过天安门、故宫、长城相当于你没到过北京。假如你搞不懂JS变量的作用域,相当于你没学过JS。关于JS变量作用域的重要性自己好好悟吧!提示:查看本文章记得看注释哦!
JS是一门弱类型(松散型)的语言,这也就是说其天生就与众不同,独领风骚! 在讲解变量作用域之前,我们先来了解一下JS中的变量。JS中的变量与其它语言有很大的不同,由于JS变量拥有松散(不强制)的本质,从而决定了其只是一个在特定阶段保持特定类型值的名字。
基本数据类型的值保存在栈内存中。而引用数据类型的值则保存在堆内存中,在栈内存中只保留引用类型的指针地址。 基本类型值有以下五种:undefined,Null,Boolean,Number和String。基本数据类型的值保存在栈内存中。
//在栈内存中开辟一块空间存储值为"laotie"的变量name
var name="laotie";
//在栈内存中开辟一块空间存储值为"laotie"的变量name2
var name2=name;
//name与name2是相对独立的,所以改变name2的值为"xiaozhang",而name的值不会受到影响
var name2="xiaozhang";
console.log(name);//laotie
console.log(name2);//xiaozhang
再来看一下引用类型:
/*在栈内存中存放 obj的地址
* 其值存放在堆内存中。
* 栈内存的地址的指向堆内存中的值。*/
var obj={
name:"zhangpeiyue"
}
/*将obj的地址赋值给obj2
所以在栈内存中存储的地址与obj的地址相同,
obj与obj2共享同一个值。
*/
var obj2=obj;
obj2.name="xiaozhang";
//因为obj与obj2共享同一个值,所以上行代码改变的是同一个值
console.log(obj.name);//xiaozhang
//你也可以认为obj即为obj2,引用类型比较的是地址,因此为true
console.log(obj==obj2);//true
//基本数据类型比较的是值,只要值相等比较结果即为true
var a=1;
var b=1;
console.log(a==b);//true
var c=2;
var d=c;
console.log(c==d);//true
var obj={
age:12
}
var obj2={
age:12
}
//引用类型比较的是地址,而不是值。
//由于每次创建的引用类型地址都不同,所以结果为false
console.log(obj==obj2);//false
var obj3={
age:12
}
//将obj3的地址赋值给obj4。所以地址相同
var obj4=obj3;
//由于比较的是地址,且obj3与obj4的地址相同,所以结果为true
console.log(obj3==obj4);
/*接收的所有基本数据类型,接收的是其值。
接收的参数都是函数体中的局部变量。
在函数体内改变值,对外部不会产生任何影响*/
function fn(a){
a+=1;
console.log(a);//14
}
var a=13;
fn(a);
console.log(a);//13
/*引用数据类型传递的是引用地址,
因此函数体中的obj与函数外的obj的引用地址相同。
所以函数体中的obj与函数外的obj共享同一值,
改变其中一个值,其它的也会随之改变
*/
function fn(obj){
obj.name="laowang"
console.log(obj.name);//laowang
}
var obj={
name:"laotie"
}
fn(obj);
console.log(obj.name);//laowang
全局作用域是最外围定义的作用域,在web浏览器中全局作用域指的是window对象。因此在全局作用域定义的变量和函数,你可以认为是window对象的属性与方法!
var color="red";//定义一个全局color
function fn(){
color="blue";//全局函数可以在函数内访问
}
fn();
console.log(color);//blue
var color="red";//定义一个全局color
function fn(){
color="blue";//全局函数可以在函数内访问
}
window.fn();
console.log(window.color);//blue
var color="yellow";//定义全局变量color
function fn(){
//在函数体内如果拥有指定的变量,就不会去外层查找
var color="red";//这里是局部变量color,外面是访问不到的哦
console.log(color);//red
}
fn();
console.log(color);//yellow
var color="green";
function fn(){
//子函数是建议以下划线开头
function _fn2(){
var color2="orange";
console.log(color);//green
console.log(color2);//orange
}
_fn2();//_fn2()的作用域在fn()内
}
fn();
_fn2();//在此处调用fn2()是调取不到的
注意:当在一个作用域内执行代码时,就会有一个被称为作用域链的东西。它的作用是保证对变量与方法访问的有序性。也就是当前执行环境中存在指定的变量或方法就不会去外围查找,如果没有则会向外围查找,直到找到为止!如果找不到会报错!一层层向外寻找指定变量和方法的行为,形成了一个作链条。这个链条就是作用域链。访问局部变量要比全局变量快许多,因为不需要向外围查找(向上查找)指定的变量。
if(true){
var name="zhang";
}
console.log(name);//zhang
当你在函数中声明一个没有带上var关键字的变量时,这个变量就会成为全局变量。不过这种行为很容易造成命名冲突,所以非常不推荐大家使用!
function fn(){
//此处a=12相当于window.a=12。
a=12;//声明一个不带var关键字的变量
}
fn();
console.log(a);//12
这是因为fn函数是在window环境下运行的,由此函数体内的a=12相当于执行了window.a=12。而window是JS的顶级对象。也可以认为我们为顶级对象增加了值为12的a属性。所以变量a就成为了全局变量。 另外如果函数体内的变量是通过var关键字声明的,则该变量为局部变量,只能在该函数体内进行访问,函数体外是访问不到的。
function fn(){
var a=12;
console.log(a);//12
}
fn();
console.log(a);//报错:a is not defined
var obj = {
b: 2
};
var fn = function () {};
fn.c = 3;
function test(x, y, z) {
x = 4;
y.b = 5;
z.c = 6;
return z;
}
test(a, obj, fn);
console.log(a + obj.b + fn.c);//12
所谓变量的生命周期指的是变量由声明到销毁。 对于全局变量来讲,其生命周期是永久的,除非我们主动去销毁这个全局变量。而在函数体内声明的局部变量,当函数运行完以后,局部变量就失去了任何价值,它们也会随着函数的执行完毕而销毁。
var fn=function(){
var a=1;//退出函数后,局部变量a会销毁
console.log(a);
}
fn();