您的当前位置:首页正文

js变量作用域及可访问性的探讨_javascript技巧

2023-12-01 来源:布克知识网

每一种语言都有变量的概念,变量是用来存储信息的一个元素。比如下面这个函数: 代码如下: function Student(name,age,from) { this.name = name; this.age = age; this.from = from; this.ToString = function() { return "my information is name: "+this.name+",age : "+this.age+", from :" +this.from; } } Student类有三个变量,分别为name(名字),age(年龄),from(籍贯),这三个变量构成了描述一个对象的信息。当然,这里还有一个方法用来返回Student的信息。 但是,我们是不是定义了一个变量,它就能一直存在着,并且还有可能在任何地方都能被访问和使用直到其被销毁?仔细想想,上面的需求是比较过分的,因为某些变量在某个功能实现后就不再利用了,但如果这个变量还存在的话,就占用了系统资源了,俗语曰:“站着茅坑不拉#$%”。 于是我们对变量的及时和按需求地销毁有一个探讨的话题了。 好,切入正题吧,就本人所接触过的来讲,js中支持如下几种类型的变量,分别为:局部变量、类变量、私有变量、实例变量、静态变量和全局变量。接下来我们就一一探讨研究下。 局部变量: 局部变量一般指在{}范围内有效变量,也就是语句块内有效的变量,如: 代码如下:function foo(flag) { var sum = 0; if(flag == true) { var index; for(index=0;index<10;index++) { sum +=index; } } document.write("index is :"+index+""); return sum; } //document.write("sum is :" +sum+""); document.write("result is :"+foo(true)+""); 该代码执行后输出的结果为:“index is :undefined” 和 “result is :0”,我们可以看到希望输出的index变量的值为undefined,也就是未定义。因此我们可以发现,index变量在if语句块结束后即被销毁了。那么“sum”变量呢?这个变量在foo()函数段执行完毕后被销毁了,如果您去掉我注释的那条语句,再执行,您将会发现系统将报错。值得注意的是,如果我把上面的foo()函数改成如下: 代码如下:function foo(flag) { var sum = 0; for(var index=0;index<10;index++) { sum +=index; } document.write("index is :"+index+""); return sum; } 您将可以看见可以输出index值("index is :10"),这个是js和其他语言的不同地方,因为index是在for循环的{}外面定义的,因此其作用范围在foo()函数使用完毕后才销毁。 类变量: 类变量,实际上就是类的一个属性或字段或一个方法,该变量在该类的一个实例对象被销毁后自动销毁,比如我们开始时举的Student类。这个我们不多讨论,大家可以自己试一下。 私有变量: 私有变量,值得是某个类自己内部是用的一个属性,外部无法调用,其定义是用 var 来声明的。注意如果不用var 来声明,该变量将是全局变量(我们下面将会讨论),如: 代码如下:function Student(name,age,from) { this.name = FormatIt(name); this.age = age; this.from = from; var origName = name; var FormatIt = function(name) { return name.substr(0,5); } this.ToString = function() { return "my information is name: "+origName+",age : "+this.age+", from :" +this.from; } } 这里,我们分别定义了一个origName和FormatIt()两个私有变量(按面向对象的解释,应该用类的属性来称呼)。 我们把这种情况下的方法也成为变量,因为该情况下的变量是个function类型的变量,而function也属于Object类的继承类。在这种情形下,如果我们定义了 var zfp = new Student("3zfp",100,"ShenZhen")。但无法通过zfp.origName和zfp.FormatIt()方式来访问这两个变量的。 注意以下几点: 1、私有变量是不能用this来指示的。 2、私有方法类型的变量的调用必须是在该方法声明后。如我们将Student类改造如下: 代码如下:function Student(name,age,from) { var origName = name; this.name = FormatName(name); this.age = age; this.from = from; var FormatName = function(name) { return name+".china"; } this.ToString = function() { return "my information is name: "+origName+",age : "+this.age+", from :" +this.from; } } var zfp = new Student("3zfp",100,"ShenZhen"); 代码执行后,将会报"找不到对象"的错误.意思是FormatName()未定义。 3、私有方法无法访问this指示的变量(公开变量),如下: 代码如下:function Student(basicinfo) { this.basicInfo = basicinfo; var FormatInfo = function() { this.basicInfo.name = this.basicInfo.name+".china"; } FormatInfo(); } function BasicInfo(name,age,from) { this.name = name; this.age = age; this.from = from; } var zfp = new Student(new BasicInfo("3zfp",100,"ShenZhen")); 执行代码后,系统将会提示 “this.basicInfo为空或不是对象”的错误。 基本结论是,私有方法只能访问私有属性,私有属性在声明并赋值后可以在类的任何地方访问, 实例变量: 实例变量即某个实例对象所拥有的变量。如: 代码如下:function BasicInfo(name,age,from) { this.name = name; this.age = age; this.from = from; } var basicA = new BasicInfo("3zfp",100,"ShenZhen"); basicA.generalInfo = "is 3zfp owned object"; document.write("basicA's generalInfo is : "+ basicA.generalInfo+""); var basicB = new BasicInfo("zfp",100,"ShenZhen"); document.write("basicB's generalInfo is : "+ basicB.generalInfo+""); 执行该代码后,我们将可以看到如下结果: basicA's generalInfo is : is 3zfp owned object basicB's generalInfo is : undefined 静态变量: 静态变量即为某个类所拥有的属性,通过 类名+"."+静态变量名 的方式访问该属性。如下可以做清晰的解释: 代码如下:function BasicInfo(name,age,from) { this.name = name; this.age = age; this.from = from; } BasicInfo.generalInfo = "is 3zfp owned object"; var basic = new BasicInfo("zfp",100,"ShenZhen"); document.write(basic.generalInfo+""); document.write(BasicInfo.generalInfo+""); BasicInfo.generalInfo = "info is changed"; document.write(BasicInfo.generalInfo+""); 执行以上代码,将会得到如下结果: undefined is 3zfp owned object info is changed 注意以下几点: 1、以 类名+"."+静态变量名 的方式来声明一个静态变量 2、静态变量并不属于类的某个实例对象所独有的属性,为对象的共享. 3、能以实例对象名+"."+静态变量名来访问。 全局变量: 全局变量即整个系统运行期间有效访问控制的变量,通常是在一个js代码开头定义,如: 代码如下:var copyright = "3zfp owned"; var foo =function() { window.alert(copyright); } 注意以下几点: 1、如果一个变量不用var 来声明,则其被视为全局变量。如: var copyright = "3zfp owned"; var foo =function(fooInfo) { _foo = fooInfo; document.write(copyright+""); } new foo("foo test"); document.write(_foo+""); 执行代码,将得到如下结果: 3zfp owned foo test 但是,这个又有一个注意的地方,function是编译期对象,也就是说_foo这个全局变量要在foo对象被实例化后才能被初始化,也就是说如果将 new foo(); document.write(_foo+""); 对调成 document.write(_foo+""); new foo(); 系统将提示 "_foo 未定义"。 2、如果定义了一个和全局变量同名的局部变量属性,如下: 代码如下:var copyright = "3zfp owned"; var foo =function(fooInfo) { var copyright = fooInfo; //同名变量 this.showInfo = function() { document.write(copyright+""); } } new foo("foo test").showInfo(); document.write(copyright+""); 执行代码,将得到如下结果: 3zfp owned foo test 原因是由于function 是在编译期间完成变量的定义,也就是foo内部的copyright的定义是在编译期间完成的,其作用域只在foo对象内有效,而与外部定义的全局变量copyright无关。

小编还为您整理了以下内容,可能对您也有帮助:

如何更好的理解javascript变量类型以及变量作用域


变量的类型
Javascript和Java、C这些语言不同,它是一种无类型、弱检测的语言。它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量。例如:
i=100;//Number类型
i="variable";//String类型
i={x:4};//Object类型
i=[1,2,3];//Array类型JS的这种特性虽然让我们的编码更加灵活,但也带来了一个弊端,不利于Debug,编译器的弱检测让我们维护冗长的代码时相当痛苦。

全局变量和局部变量
当JS解析器执行时,首先就会在执行环境里构建一个全局对象,我们定义的全局属性就是做为该对象的属性读取,在顶层代码中我们使用this关键字和window对象都可以访问到它。而函数体中的局部变量只在函数执行时生成的调用对象中存在,函数执行完毕时局部变量即刻销毁。因此在程序设计中我们需要考虑如何合理声明变量,这样既减小了不必要的内存开销,同时能很大程度地避免变量重复定义而覆盖先前定义的变量所造成的Debug麻烦。
变量作用域
任何程序语言中变量的作用域都是一个很关键的细节。JS中变量的作用域相对与JAVA、C这类语言显得更自由,一个很大的特征就是JS变量没有块级作用域,函数中的变量在整个函数都中有效,运行下面代码:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定义一个输出函数
function outPut(s){
document.writeln(s)
}
//全局变量
var i=0;
//定义外部函数
function outer(){
//访问全局变量
outPut(i); // 0
//定义一个类部函数
function inner(){
//定义局部变量
var i = 1;
// i=1; 如果用隐式申明那么就覆盖了全局变量i
outPut(i); //1
}
inner();
outPut(i); //0
}
outer();
</SCRIPT>输出结果为0 1 0,从上面就可以证明JS如果用var在函数体中声明变量,那么此变量在且只在该函数体内有效,函数运行结束时,本地变量即可销毁了。
由于上面的这个JS特性,还有一个关键的问题需要注意。此前一直使用ActionScript,虽然它和JS都是基于ECMA标准的,但在这里还是略有不同的。例如下面代码:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定义一个输出函数
function outPut(s){
document.writeln(s)
}
//全局变量
var i=0;
//定义外部函数
function outer(){
//访问全局变量
outPut(i); // 0
//定义一个类部函数
function inner(){
outPut(i); //undefiend
var i=1;
outPut(i); //1
}
inner();
outPut(i); //0
}
outer();
</SCRIPT>JS变量作用域
<script language ="javascript" type ="text/javascript" >
var a = "change";
function fun() {
alert(a);//输出undefined
var a = "改变了";
alert(a);//输出改变了
}
alert(a);//输出change
fun();
</script>var定义的是一个作用域上的变量,在第一次输出a之前,JS在预编译分析中已经将a赋值为change,所以第一次输出change,当调用到fun()函数的时候,JS创建一个新的作用域,在输出a之前,初始化所有var变量的值为undefined,所以fun()中第一次输出的是undefined,第二次输出已经给a赋值了,所以输出新的值;两个a在函数里面和外面是不同的两个变量,如:
<script language ="javascript" type ="text/javascript" >
var b;
function fun() {
b = "change";
}
alert(b);//输出undefined
</script>变量b在函数外面已经定义了,在函数中有给b赋值,但输出的却是undefined。

如何更好的理解javascript变量类型以及变量作用域


变量的类型
Javascript和Java、C这些语言不同,它是一种无类型、弱检测的语言。它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量。例如:
i=100;//Number类型
i="variable";//String类型
i={x:4};//Object类型
i=[1,2,3];//Array类型JS的这种特性虽然让我们的编码更加灵活,但也带来了一个弊端,不利于Debug,编译器的弱检测让我们维护冗长的代码时相当痛苦。

全局变量和局部变量
当JS解析器执行时,首先就会在执行环境里构建一个全局对象,我们定义的全局属性就是做为该对象的属性读取,在顶层代码中我们使用this关键字和window对象都可以访问到它。而函数体中的局部变量只在函数执行时生成的调用对象中存在,函数执行完毕时局部变量即刻销毁。因此在程序设计中我们需要考虑如何合理声明变量,这样既减小了不必要的内存开销,同时能很大程度地避免变量重复定义而覆盖先前定义的变量所造成的Debug麻烦。
变量作用域
任何程序语言中变量的作用域都是一个很关键的细节。JS中变量的作用域相对与JAVA、C这类语言显得更自由,一个很大的特征就是JS变量没有块级作用域,函数中的变量在整个函数都中有效,运行下面代码:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定义一个输出函数
function outPut(s){
document.writeln(s)
}
//全局变量
var i=0;
//定义外部函数
function outer(){
//访问全局变量
outPut(i); // 0
//定义一个类部函数
function inner(){
//定义局部变量
var i = 1;
// i=1; 如果用隐式申明那么就覆盖了全局变量i
outPut(i); //1
}
inner();
outPut(i); //0
}
outer();
</SCRIPT>输出结果为0 1 0,从上面就可以证明JS如果用var在函数体中声明变量,那么此变量在且只在该函数体内有效,函数运行结束时,本地变量即可销毁了。
由于上面的这个JS特性,还有一个关键的问题需要注意。此前一直使用ActionScript,虽然它和JS都是基于ECMA标准的,但在这里还是略有不同的。例如下面代码:
<SCRIPT LANGUAGE="JavaScript" type="text/javascript">
//定义一个输出函数
function outPut(s){
document.writeln(s)
}
//全局变量
var i=0;
//定义外部函数
function outer(){
//访问全局变量
outPut(i); // 0
//定义一个类部函数
function inner(){
outPut(i); //undefiend
var i=1;
outPut(i); //1
}
inner();
outPut(i); //0
}
outer();
</SCRIPT>JS变量作用域
<script language ="javascript" type ="text/javascript" >
var a = "change";
function fun() {
alert(a);//输出undefined
var a = "改变了";
alert(a);//输出改变了
}
alert(a);//输出change
fun();
</script>var定义的是一个作用域上的变量,在第一次输出a之前,JS在预编译分析中已经将a赋值为change,所以第一次输出change,当调用到fun()函数的时候,JS创建一个新的作用域,在输出a之前,初始化所有var变量的值为undefined,所以fun()中第一次输出的是undefined,第二次输出已经给a赋值了,所以输出新的值;两个a在函数里面和外面是不同的两个变量,如:
<script language ="javascript" type ="text/javascript" >
var b;
function fun() {
b = "change";
}
alert(b);//输出undefined
</script>变量b在函数外面已经定义了,在函数中有给b赋值,但输出的却是undefined。

Js基础27:作用域

函数和变量的有效范围就是作用域

1、作用域的概念

这是因为js中存在作用域的概念。

作用域:

作用域就是指定一个变量或者一个函数的作用范围。

能在页面的任何位置都可以访问,称为 全局作用域

只能在局部(函数内)访问,称为为 局部作用域

上述代码中,a是全局变量,b是局部变量

ES5中只有函数才有作用域,所谓是局部作用域也可以叫函数作用域。

作用域的作用就是为了把数据进行保护,不让外部的数据对我们的数据进行污染

以下①②③④打印什么?

但是结果却大出所料,这里得到的结果是undefined。

③处的结果也和我们最初的认识是不一样的,结果为f对应的函数对象。

造成这个结果是因为变量和函数的作用域提升的原因,什么意思呢?

JS是解释性语言,JS引擎对代码的处理分为两步:

4、作用域链和访问规则

在JavaScript里面,函数内部是可以包含另一个函数的

此时函数b就被函数a包含越来了,这样就形成了两层作用域。

如果有以下代码:三个同名变量放在三个作用域内

会依次输出:10,20,30

虽然多个变量x同名,但是不同作用域内优先使用自己内部作用域的变量x。

如果代码做一下修改:删除函数b的局部变量x

依次输出:10,20,20

函数b内部没有变量b,会向自己的外面的作用域查找x变量,函数a内的x变量离函数b最近,会优先得到函数a的变量x

代码再做修改:再删除a的局部变量x

会依次输出:10,10,10

函数b内部没有x变量,会向函数a的作用域查找,但是函数a内部也没有x变量,会向函数a的上一层作用域再查找,直到查找到了全局作用域。

代码再次变化:全局的变量x也删除

函数b内部没有变量x,会顺着上层作用域一层一层地查找,直到全局作用域也没有,就会报错。

总结:

本文如未解决您的问题请添加抖音号:51dongshi(抖音搜索懂视),直接咨询即可。

相关资讯

热门话题

热门图文

  • 予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋全文

    《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》高士谈全文:我本麋鹿姿,强服冠与簪。束缚二十年,梦寐游山林。朅来古晋国,官舍南城阴。凿壁取棘豁,开窗舒滞淫。山光射几席,野色供登临。怡颜盼庭柯,明目增遥岑。草木递荣落,云烟自浮沈。玩彼物色变,感此岁月侵。兀坐独无人,窥檐啭幽禽。谁知城市中,阒若郊居深。巷陋颜子乐,地偏陶令心。一室亦何有,狼藉书与琴。晴晖朝徙倚,皎月夜相寻。欲赋畔牢愁,先为梁父吟。诗成辄自和,酒熟时孤斟。结茅会有期,种竹当及今。日来官更忙,尘埃满衣襟。暮归唯惫卧,筋力殊不任。常思返丘壑,岂愿纡朱金。遥知北山处,猿鹤馀清音。

  • 予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的朝代是什么

    《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》高士谈朝代:元代。《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》年代:元代。作者:高士谈。出生地:燕(今河北)人。去世时间:公元1146年。主要作品:《村行·墟落依林莽》《不眠·不眠披短褐》《减字木兰花·西湖睡起》《朝中措·琅琊山色最清雄》《玉楼春·少年人物江山秀》等。我们为您从以下几个方面提供予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的详细介绍。一、《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的全文 点此查看《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的详细内容。我本麋鹿姿,强服冠与簪。

  • 予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的朝代

    《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》高士谈朝代:元代。《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》年代:元代。作者:高士谈。出生地:燕(今河北)人。去世时间:公元1146年。主要作品:《村行·墟落依林莽》《不眠·不眠披短褐》《减字木兰花·西湖睡起》《朝中措·琅琊山色最清雄》《玉楼春·少年人物江山秀》等。我们为您从以下几个方面提供予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的详细介绍。一、《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的全文 点此查看《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的详细内容。我本麋鹿姿,强服冠与簪。

  • 予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋朝代

    《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》高士谈朝代:元代。《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》年代:元代。作者:高士谈。出生地:燕(今河北)人。去世时间:公元1146年。主要作品:《村行·墟落依林莽》《不眠·不眠披短褐》《减字木兰花·西湖睡起》《朝中措·琅琊山色最清雄》《玉楼春·少年人物江山秀》等。我们为您从以下几个方面提供予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的详细介绍。一、《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的全文 点此查看《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的详细内容。我本麋鹿姿,强服冠与簪。

  • 予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的作者 予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的作者是什么]

    《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》高士谈作者:高士谈。《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》作者:高士谈。年代:元代。出生地:燕(今河北)人。去世时间:公元1146年。主要作品:《村行·墟落依林莽》《不眠·不眠披短褐》《减字木兰花·西湖睡起》《朝中措·琅琊山色最清雄》《玉楼春·少年人物江山秀》等。我们为您从以下几个方面提供予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋的详细介绍。一、《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的全文 点此查看《予所居之南下临短壑因凿壁开窗规为书室坐获山林之趣榜曰野斋且作诗约诸友同赋》的详细内容。我本麋鹿姿,强服冠与簪。

Top