作用域是指程序源代码中定义变量的区域。
实际上描述的就是查找变量的范围,作用域必须有的两个功能就是存储变量以及查找变量,作用域就是发挥这两个作用以及更多作用的规则。
作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。
JavaScript采用的是词法作用域
在代码中任何地方都能访问到的对象拥有全局作用域
全局变量:
- 生命周期将存在于整个程序之内。
- 能被程序中任何函数或者方法访问。
- 在 JavaScript 内默认是可以被修改的。
JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。
带有关键字 var 的声明
var winValue = 10;
console.log(window.winValue); // 10
不带有声明关键字的变量,JS 会默认帮你声明一个全局变量
function foo(value) {
result = value + 1; // 没有用 var 声明
return result;
};
foo(1);
console.log(window.result); // 2 <= 挂在了 window全局对象上
函数作用域内,对外是封闭的,从外层的作用域无法直接访问函数内部的作用域。
在函数内部的变量权限称为函数作用域,有以下特点:
function bar() {
var foo = 'test';
}
console.log(foo); // Uncaught ReferenceError: foo is not defined
凡是由{}符号包裹起来的都是块作用域
for(let i = 0; i < 5; i++) {
// ...
}
console.log(i); // Uncaught ReferenceError: i is not defined
在 for 循环执行完毕之后 i 变量就被释放了
作用域链:当访问一个变量时,解释器会首先在当前作用域查找,如果没有找到,就去父作用域找,直到找到该变量或者不在父作用域中,这就是作用域链。
var a = 1
function foo () {
var b = 2
console.log(a)
}
foo() // 1
console.log(b) // Uncaught ReferenceError: b is not defined
从上面代码的执行结果可以看出,foo 函数取到了它外部的变量 a, 而最外层的 console.log(b) 操作并没能取得 foo 函数里面的变量 b。
如果去查找一个普通对象的属性,但是在当前对象和其原型中都找不到时,会返回undefined;但查找的属性在作用域链中不存在的话就会抛出ReferenceError。
闭包是指有权访问另外一个函数作用域中的变量的函数
在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成"定义在一个函数内部的函数"。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
之所以出现闭包是因为JS的垃圾回收机制,JS本身为了避免解释器过量消耗内存,造成系统崩溃,自带有一套垃圾回收机制,垃圾回收机制能够检测到一个对象是不是无用的。检测到之后,就会把它占用的内存释放掉。但是实际工作中,我们也会需要一些变量不那么及时的被清理,所以就出现了闭包,用来达成这个效果。
function getOuter(){
var name = 'jacky';
function getName(str){
console.log(str + name); // 可以访问getName函数外部的name
}
return getName('名字是:');
}
getOuter(); // 名字是:jacky
再来看下面一段代码:
function bar() {
var x = 1;
return function () {
var y = 2;
return x + y;
}
}
var foo = bar(); // 这一句执行完,变量x并没有被回收,因为要内部函数还需要引用
console.log(foo()) // 3 执行内部函数,引用外部变量x
上面代码中,在全局执行上下文中定义了一个函数bar和变量foo,函数bar内部返回一个匿名函数,所以此刻匿名函数的作用域链初始化为包含了全局变量对象和bar中的变量对象。
当执行var foo = bar()时,把函数bar的执行上下文压入栈,当bar执行完后,其执行上下文应该弹出栈,但是因为bar内部的匿名函数作用域链还引用这bar函数内的变量x,所以bar的执行上下文得不到释放,这样就形成了闭包。
var counter = (function(){
var privateCounter = 0; //私有变量
function change(val){
privateCounter += val;
}
return {
increment:function(){
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return privateCounter;
}
};
})();
var objEvent = objEvent || {};
(function() {
var addEvent = function() {
// some code
}
function removeEvent() {
// some code
}
objEvent.addEvent = addEvent
objEvent.removeEvent = removeEvent
})()
addEvent 和 removeEvent 都是局部变量,但我们可以通过全局变量 objEvent 使用它
javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
即释放对闭包的引用,使引用变量为null。
优点:
缺点:
形成闭包即要把一个函数当成值传递,而且该函数还引用这另一个函数的作用域链使得被引用的函数不能被回收,使用不当容易造成内存泄漏;
作用域是指程序源代码中定义变量的区域。
实际上描述的就是查找变量的范围,作用域必须有的两个功能就是存储变量以及查找变量,作用域就是发挥这两个作用以及更多作用的规则。
作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。
JavaScript采用的是词法作用域
在代码中任何地方都能访问到的对象拥有全局作用域
全局变量:
- 生命周期将存在于整个程序之内。
- 能被程序中任何函数或者方法访问。
- 在 JavaScript 内默认是可以被修改的。
JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。
带有关键字 var 的声明
var winValue = 10;
console.log(window.winValue); // 10
不带有声明关键字的变量,JS 会默认帮你声明一个全局变量
function foo(value) {
result = value + 1; // 没有用 var 声明
return result;
};
foo(1);
console.log(window.result); // 2 <= 挂在了 window全局对象上
函数作用域内,对外是封闭的,从外层的作用域无法直接访问函数内部的作用域。
在函数内部的变量权限称为函数作用域,有以下特点:
function bar() {
var foo = 'test';
}
console.log(foo); // Uncaught ReferenceError: foo is not defined
凡是由{}符号包裹起来的都是块作用域
for(let i = 0; i < 5; i++) {
// ...
}
console.log(i); // Uncaught ReferenceError: i is not defined
在 for 循环执行完毕之后 i 变量就被释放了
作用域链:当访问一个变量时,解释器会首先在当前作用域查找,如果没有找到,就去父作用域找,直到找到该变量或者不在父作用域中,这就是作用域链。
var a = 1
function foo () {
var b = 2
console.log(a)
}
foo() // 1
console.log(b) // Uncaught ReferenceError: b is not defined
从上面代码的执行结果可以看出,foo 函数取到了它外部的变量 a, 而最外层的 console.log(b) 操作并没能取得 foo 函数里面的变量 b。
如果去查找一个普通对象的属性,但是在当前对象和其原型中都找不到时,会返回undefined;但查找的属性在作用域链中不存在的话就会抛出ReferenceError。
闭包是指有权访问另外一个函数作用域中的变量的函数
在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成"定义在一个函数内部的函数"。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
之所以出现闭包是因为JS的垃圾回收机制,JS本身为了避免解释器过量消耗内存,造成系统崩溃,自带有一套垃圾回收机制,垃圾回收机制能够检测到一个对象是不是无用的。检测到之后,就会把它占用的内存释放掉。但是实际工作中,我们也会需要一些变量不那么及时的被清理,所以就出现了闭包,用来达成这个效果。
function getOuter(){
var name = 'jacky';
function getName(str){
console.log(str + name); // 可以访问getName函数外部的name
}
return getName('名字是:');
}
getOuter(); // 名字是:jacky
再来看下面一段代码:
function bar() {
var x = 1;
return function () {
var y = 2;
return x + y;
}
}
var foo = bar(); // 这一句执行完,变量x并没有被回收,因为要内部函数还需要引用
console.log(foo()) // 3 执行内部函数,引用外部变量x
上面代码中,在全局执行上下文中定义了一个函数bar和变量foo,函数bar内部返回一个匿名函数,所以此刻匿名函数的作用域链初始化为包含了全局变量对象和bar中的变量对象。
当执行var foo = bar()时,把函数bar的执行上下文压入栈,当bar执行完后,其执行上下文应该弹出栈,但是因为bar内部的匿名函数作用域链还引用这bar函数内的变量x,所以bar的执行上下文得不到释放,这样就形成了闭包。
var counter = (function(){
var privateCounter = 0; //私有变量
function change(val){
privateCounter += val;
}
return {
increment:function(){
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return privateCounter;
}
};
})();
var objEvent = objEvent || {};
(function() {
var addEvent = function() {
// some code
}
function removeEvent() {
// some code
}
objEvent.addEvent = addEvent
objEvent.removeEvent = removeEvent
})()
addEvent 和 removeEvent 都是局部变量,但我们可以通过全局变量 objEvent 使用它
javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
即释放对闭包的引用,使引用变量为null。
优点:
缺点:
形成闭包即要把一个函数当成值传递,而且该函数还引用这另一个函数的作用域链使得被引用的函数不能被回收,使用不当容易造成内存泄漏;