JavaScript必知必会,JavaScript变量的效果域全分析
分类:计算机网络

变量作用域是程序中定义这个变量的区域。
先来看一段示例:

function

/*  代码1  */

函数格式

var scope = "global ";
function checkScope() {
 var scope = "local ";
 function childCheck() {
  var scope = "childLocal ";
  document.write(scope);
 }
 function childUndefined() {
  document.write(scope);
  var scope;
 }
 function childOverride() {
  scope = "childOverride ";
  document.write(scope);
 }
 document.write(scope); //输出"local"
 childCheck();   //输出"childLocal"
 childUndefined();  //输出"undefined"
 childOverride();  //输出"childOverride"
 document.write(scope); //输出"childOverride"
}
checkScope();    //输出"local childLocal undefinedchildOverride childOverride"
document.write(scope);  //输出"global "
function getPrototyNames(o,/*optional*/ a)
{
a = a || [];
for(var p in o)
{
a.push(p);
}
return a;
} 

全局作用域与局部作用域 全局(global)变量的作用域是全局的,在Javascript中处处有定义;而函数内部声明的变量是局部(local)变量,其作用域是局部性的,只在函数体内部有定义。对于下面的输出读者应不会感到意外。
/*  代码2  */

caller

var scope = "global";
function checkScope() {
 var scope = "local";
 document.write(scope);
}
checkScope();   //输出"local"
document.write(scope); //输出"global"

func.caller 返回函数调用者

全局变量作用域中使用变量可以不用var语句,但在声明局部变量是一定要使用var语句,否则会视为对全局变量的引用。看下面代码:
/*  代码3  */

function callfunc()
{
if(callfunc.caller)
{
alert(callfunc.caller.toString());
}else
{
alert("没有函数调用");
}
}
function handleCaller()
{
callfunc();
}
handleCaller();//返回 handler
callfunc();//没有函数调用,返回null,执行了《没有函数调用》 
var scope = "global";
function checkScope() {
 scope = "local";
 document.write(scope);
}
checkScope();   //输出"local"
document.write(scope); //输出"local"

callee

没有块作用域 Javascript没有块级作用域,函数中声明的变量在整个函数中都是有定义的。对于下面的代码对于生疏的读者可能颇感意外:
/*  代码4  */

匿名方法递归调用

var scope = "global";
function checkScope() {
 document.write(scope); //语句4.1
 var scope = "local"; //语句4.2
 document.write(scope);
}
checkScope();   //输出"undefinedlocal"
alert( (function (x) {
if (x <= ) return ;
return x * arguments.callee(x - );
}()));// 

由于语句4.1(var scope = "local";)声明的变量在整个checkScope函数作用域内都有效,因此在语句4.2(document.write(scope); )执行的时scope引用的是局部变量,而此时局部变量scope尚未定义,所以输出”undefined”。因此一个好的编程习惯是将所有的变量声明集中起来放在函数的开头。

scope

在了解了上述内容之后,读者再看看代码1应该不会感到困惑了。
对象的属性变量 对象的属性变量比较容易理解,看一下下面的代码读者应该不会感到疑惑。
/*  代码5  */

作用域大家都不陌生,今天就来说说闭包问题,深刻吃透闭包问题。

var scope = "global ";
var obj = new Object();
obj.scope = "object ";
obj.checkScope = function () {
 var scope = "loacl ";
 document.write(scope);   //输出"loacl"
 document.write(this.scope);  //输出"object"
 document.write(window.scope); //输出"global"
}
obj.checkScope(); //输出"loacl object global"
<script>
var global = "global scope";//这个是全局的作用域
function scope()
{
var scope = "local scope";//这个是局部的作用域
return scope;//返回的scope,是局部的变量
}
</script> 

所谓作用域,就是说这个变量在代码块中的有效范围。如果不理解 JavaScript 作用域,调试代码的时候可能会比较困难。

  1、:定义的全局变量也能在函数内部访问。当定义的局部变量和全局变量名字相同时,局部变量的就会隐藏全局变量,不会破坏全局变量的值。

在函数中,如果用var来声明一个变量,那么该变量的作用域就只限于该函数内部,函数外的代码无法访问该变量。如果在该函数中再声明一个函数,那么这个内部的函数也可以访问这个变量。

var scope = "global scope";
function f()
{
var scope = "local scope";
return scope;
}
alert(f());//local scope
alert(scope);//global scope; 

反过来,如果声明变量的时候没有用var,那么此变量的作用域就不局限于这个函数了。JavaScript 引擎会再全局范围中检查该变量是否被定义过。如果该变量没有被定义过,那么它就会被定义为一个全局变量。

  上面确实是很容易理解,对吧。

函数可以访问相同作用域中的变量:

2、 全局变量可以不用var声明,但是局部变量必须使用var声明,如果局部变量不使用var声明,编译器会默认这个是个全局变量。

var foo = 'hello';

var sayHello = function() {
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // also logs 'hello'
   
scope = "global scope";
function f()
{
scope = "local scope";
return scope;
}
alert(f());//local scope
alert(scope);//local scope

变量作用域之外的代码不能访问该变量:

  但是全局变量不使用var声明,也仅限非严格模式,如果使用严格模式的话,会报错误

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // doesn't log anything
<script>
"use strict";
scope = "global scope";
function f()
{
scope = "local scope";
return scope;
}
alert(f());//local scope
alert(scope);//local scope
</script>

不用作用域中名称相同的变量,有不同的值:

图片 1

var foo = 'world';

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // logs 'world'

所以建议大家声明变量时,千万不要省略var,可以避免不必要的麻烦。

函数定以后可以看到函数内变量值的改变:

3、 声明提前,也是可以滴。什么叫什么提前。

var myFunction = function() {
 var foo = 'hello';

 var myFn = function() {
  console.log(foo);
 };

 foo = 'world';

 return myFn;
};

var f = myFunction();
f(); // logs 'world' -- haha

图片 2

作用域也会穿越 — 闭包

<script>
"use strict";
scope;
console.log(scope);
var scope = "global scope";
console.log(scope);
</script> 
// 一个自执行的匿名函数
(function() {
 var baz = 1;
 var bim = function() { alert(baz); };
 bar = function() { alert(baz); };
})();

console.log(baz); // 在函数外面不能访问 baz

bar(); // 声明 bar 的时候并没有用 var
  // 所以 bar 是一个全局变量; 但是,
  // bar 和 baz 在相同的作用域内被定义,
  // 所以 bar 可以访问 baz
  // 其实 bar 是个闭包函数

bim(); // bim 的作用域只限于匿名函数内部,
  // 所以这里不能调用

这个可能大家看出第一个打印undefined ,是呀还没有给他赋值, 下面赋值可定打印global scope了。

综合

这样理解并没有错,但是为什么会这样的呢,一个变量不是应该先定义才可以使用的吗?

所谓作用域,就是说这个变量在代码块中的有效范围。如果不理解 JavaScript 作用域,调试代码的时候可能会比较困难。

这里给大家说下作用域链,JavaScript是基于词法作用域的语言。

在函数中,如果用var来声明一个变量,那么该变量的作用域就只限于该函数内部,函数外的代码无法访问该变量。如果在该函数中再声明一个函数,那么这个内部的函数也可以访问这个变量。

1、作用域链是一个对象或者链表,这组代码中定义了这段代码"作用域中“的变量。当JavaScript需要查找变量scope时,就会从链中的第一个对象开发查找,如果第一个对象为scope,则会直接返回这个对象的值,如果不存在继续第二对象开始查找,直到找到。如果在作用域链上未查到该变量,则会抛出一个错误。

反过来,如果声明变量的时候没有用var,那么此变量的作用域就不局限于这个函数了。JavaScript 引擎会再全局范围中检查该变量是否被定义过。如果该变量没有被定义过,那么它就会被定义为一个全局变量。

我们可以这个作用链可以这样表示:查找 scope->window(全局对象)很显然后面是有定义scope的。但是并没有做赋值操作,后面才做赋值操作,所以此时值为undefined.

函数可以访问相同作用域中的变量:

4、这个比较具有迷惑性了,大家猜想下打印的值是什么?

var foo = 'hello';

var sayHello = function() {
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // also logs 'hello'
<script>
"use strict";
var scope = "global scope";
function f() {
console.log(scope);
var scope = "local scope";
console.log(scope);
}
f();
</script>

变量作用域之外的代码不能访问该变量:

看到这段代码:如果你粗心大意的话,很有可能会写出错误的答案:

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // doesn't log anything

1、gobal scope

不用作用域中名称相同的变量,有不同的值:

2、local scope

var foo = 'world';

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // logs 'world'

分析: 声明了全局变量,在函数体中时,第一个表示全局变量,所以打印global,第二定义了局部的变量,覆盖掉了全局的scope,所以打印local scope。

函数定以后可以看到函数内变量值的改变:

这样的分析在C# java ,完全正确。但是这里分析确实错误的。

 

这说明这个问题前,我们先看一个问题。

var myFunction = function() {
 var foo = 'hello';

 var myFn = function() {
  console.log(foo);
 };

 foo = 'world';

 return myFn;
};

var f = myFunction();
f(); // logs 'world' -- haha

这句话很重要:全局变量在程序中始终都是有定义的。局部变量在声明它的函数体以及其所嵌套的函数内始终是定义的。

作用域也会穿越 — 闭包

如果你是从事高级语言工作开始接触JavaScript 有点不适应其作用域的定义。我也是这样的。我们来看一个例子:

// 一个自执行的匿名函数
(function() {
 var baz = 1;
 var bim = function() { alert(baz); };
 bar = function() { alert(baz); };
})();

console.log(baz); // 在函数外面不能访问 baz

bar(); // 声明 bar 的时候并没有用 var
  // 所以 bar 是一个全局变量; 但是,
  // bar 和 baz 在相同的作用域内被定义,
  // 所以 bar 可以访问 baz
  // 其实 bar 是个闭包函数

bim(); // bim 的作用域只限于匿名函数内部,
  // 所以这里不能调用
<script>
var g = "global scope";
function f()
{
for(var i=;i<;i++)
{
for(var j=;j<;j++)
{
;
}
console.log(j);
}
console.log(i);
}
console.log(g);
f();
</script>

您可能感兴趣的文章:

  • 深入理解javascript作用域第二篇之词法作用域和动态作用域
  • 深入浅析javascript中的作用域(推荐)
  • 轻松5句话解决JavaScript的作用域
  • 聊一聊JavaScript作用域和作用域链
  • 谈一谈js中的执行环境及作用域
  • 浅析JavaScript作用域链、执行上下文与闭包
  • js函数内变量的作用域分析
  • JavaScript 作用域链解析
  • 只需五句话搞定JavaScript作用域(经典)

  打印的结果是什么?

大家看到{} 表示语句块,语句块在一块作用域,所以大家可能猜想,j、i值已经在内存释放掉了,所以结果肯定是undefined.

真实的结果可能令你失望,

图片 3

结果为什么会是这样,我开始的表情和你一样。

图片 4

这时查看我让你记住的那句话。。。全局变量在程序中始终都是有定义的。局部变量在声明它的函数体以及其所嵌套的函数内始终是定义的。

确切的说函数的参数 也是属于局部变量的范畴。这句话也很重要!!!

那句话大概意思说,只要是在函数内部定义的变量,在整个函数内都是有效的。所以结果也就不难理解了。在回过头看我们的那个问题,你理解了吗?

作用链还有以下定义:

1、作用链是有一个全局对象组成。

2、在不包含嵌套的函数体内,作用链上有两个对象,第一个定义了函数参数和局部变量的对象,第二个是全局对象。

3、在一个嵌套的函数体内,作用链上至少包含三个对象。

当定以一个函数的时候,就会保存一个作用域链。

当调用这个函数时,它就会创建一个新的对象来存储它的局部变量,并将这个对象添加到保存的作用链上。同时创建一个新的更长的表示函数调用的作用链。

对于嵌套的函数,当调用外部函数时,内部函数又会重新定义一遍。因为每次调用外部函数的时候,作用链都是不同的。内部函数在每次定义的时候都有微妙的差别,每次调用的外部函数时,内部函数的代码都是相同的,而且关联的代码的作用域也是不同的。

闭包

搞了这么久终于要讲了,但是再将之前我们在来分析下作用域。

<script>
var nameg="global"
var g = function f() {
console.log(name);
function demo()
{
console.log("demo="+name);
}
var name = "";
function demo() {
var name = "";
console.log("demo=" + name);
}
function demo() {
console.log("demo=" + nameg);
}
demo();
demo();
demo();
};
g();
</script>

  我们按照作用链来分析:

调用demo0, demo0()->查找name,未找到->f()查找,返回

调用demo1,demo1()->查找name,找到,返回

调用demo2,demo2()->查找nameg,未找到->f()查找nameg,未找到->window查找nameg找到,返回。

看这个例子:

<script>
function f()
{
var count = ;
return { counter:function() {
return count++;
},reset:
function()
{
return count = ;
}
}
}
var d = f();
var c = f();
console.log("d第一次调用:"+ d.counter());//
console.log("c第一次调用:"+ c.counter());// 互不影响
console.log("d第一次调用:"+ d.reset());//
console.log("c第二次调调用"+ c.counter());//
</script>

  这个例子上大家可以看到,我做了一个计数和置零的操作。

创建了两个f的对象实例d c,各有自己的作用域链,所以其值互不影响。当c第二次调用时,count值被保存了,因为c对象并未被销毁。明白这个例子后,后面的例子才比较好懂。

这个过程,大家应该十分明了了。那么现在我们来看闭包问题。我设置四个按钮,点击每个按钮就返回响应的名字。

<body>
<script>
function btnInit()
{
for(var i=;i<;i++)
{
var btn = document.getElementById("btn" + i);
btn.addEventListener("click",function() {
alert("btn" + i);
});
}
}
window.onload= btnInit;
</script>
<div>
<button id="btn">Btn</button>
<button id="btn">Btn</button>
<button id="btn">Btn</button>
<button id="btn">Btn</button>
</div>
</body>

  点击运行,结果却是都是btn5;

我们用刚才的分析在坐下,首先要调用匿名函数->查找i,未找到->btnInit(),找到i在for循环中。找到。我们知道只有函数调用结束才释放,for中的i总是可见的,所以保留了最后的i值。那么如何解决呢。

解决i值在函数中不是总是可见的,那么我们就要使用函数的嵌套了,然后把i值传进去。

function btnInit()
{
for(var i=;i<;i++)
{
(function (data_i) {
var btn = document.getElementById("btn" + data_i);
btn.addEventListener("click", function () {
alert("btn" + data_i);
});
}(i));
}
}

  看修改后的代码,首先执行第一次for,创建了一个对象,我们首先是执行匿名函数->data_i,未找到->function(data_i)找到,然后再次执行for有创建一个对象,闭包规则说的互不影响。所以能得出正确的结果。

以上所述是小编给大家介绍的 JavaScript必知必会(九)function 说起 闭包问题的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

您可能感兴趣的文章:

  • 深入解析JavaScript的闭包机制
  • 理解和运用JavaScript的闭包机制
  • javascript使用闭包模拟对象的私有属性和方法
  • JavaScript 闭包详细介绍
  • 几句话带你理解JS中的this、闭包、原型链
  • 学习Javascript闭包(Closure)知识
  • JavaScript中闭包的写法和作用详解
  • Javascript闭包与函数柯里化浅析
  • JS工作中的小贴士之”闭包“与事件委托的”阻止冒泡“
  • JavaScript闭包实例详解
  • JS闭包、作用域链、垃圾回收、内存泄露相关知识小结
  • JavaScript 闭包机制详解及实例代码

本文由正版必中一肖图发布于计算机网络,转载请注明出处:JavaScript必知必会,JavaScript变量的效果域全分析

上一篇:ajax提交表单完整实例,ajax举办即时证实实例详解 下一篇:没有了
猜你喜欢
热门排行
精彩图文