Nodejs JavaScript 闭包的理解
Nodejs JavaScript 闭包的理解
关于闭包,阮一峰的这篇文章 写得比较清晰易懂。 不过需要注意的是闭包不是函数,而是函数的作用域。由于 JavaScript 的作用域不是由 block 符号 {} 来界定,而是函数,所以两者容易混淆。阮一峰说闭包是函数估计是帮助大家理解吧。
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());
以上是他最后的思考题。因为闭包内的函数只能访问闭包内的变量,所以 this 必须要赋给 that 才能引用。
作用域
JavaScript 的闭包其实是一个作用域(scope),而这个作用域就是闭包内部的函数可以访问和修改变量的范围(注意因为闭包是外部函数的 {} 划定的作用域,所以提到函数时一般是指 {} 大括号内部申明的函数)。换句话说,闭包允许一个函数访问内部的所有变量和其他函数,只要这个函数是在这个闭包的作用域内申明的。
一个函数可以访问含有自身申明的闭包的原始作用域。
闭包作用域:
- 函数的参数在函数的闭包作用域内。
- 所有在函数自身作用域(函数的{})外的变量,甚至那些在函数申明之后申明的变量,都可以在函数内引用。
使用时注意闭包的开销,可能会影响性能。阮的文章有解释。
闭包的一个常用功能就是封装变量,类似其他语言的私有变量,来限制变量的作用域,不污染全局作用域。
我们也可以通过闭包内的函数来修改闭包内的变量值。所以,闭包不是一个简单的固定状态,而是可以随时改变的封装。
函数的偏应用(Partially Applying Function)
偏应用就是为一个多元函数(接受多个参数的函数)在调用前指定部分参数,从而在调用时可以省略这些参数。实际上,偏应用化一个函数就是返回一个预定义参数的新函数。 这种使用返回函数预先提供前几个参数的的技术叫做科里化(currying)。
立即被执行的函数
(function(){console.log("ran!");})();
这个函数会被立即执行,而不仅仅是定义。
在这个 <code>(…)()</code> 立即执行函数里,第一对括号只是分隔号,就像 <code>(3+2) * 4</code> 的括号功能一样。不过第二对括号是操作符,类似 <code>var sum = add(1,2);</code> 的括号。
this
在对象中,调用变量必须使用 this,不然会调用到对象外的全局同名变量。 在函数中,this 是函数所属的对象。如果使用 ‘use strict’, 函数里的 this 会变为 undefined。一般只有在初始函数(Constructor) 里才使用 this。
注意:闭包里没有 this 参数,因为每个函数调用有自己的 this。
在阮的思考题里,我们可以使用 bind 来达到目的。
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
}.bind(this);
}
};
console.log(object.getNameFunc()());
‘use strict’
尽量在 js 文件开始处使用 ‘use strict’ 来减少陷入 JavaScript 里暗藏的坑。比如下面的代码就在 strict 模式下不允许。
function func(){
this.a = 100;
a = 33;
};
this.a = 200;
console.log(this.a); // 非 strict 输出 200
func();
console.log(this.a); // 非 strict 输出 33
在闭包里使用循环
需要注意的一点: 闭包和循环如果同时使用的话有时会有问题,因为闭包内的变量是保存变化的,如果创建闭包之后再使用函数的话,循环里的 i 可能会一直是最后一个值(比如最大值)。
Nodejs JavaScript 闭包的理解
闭包是JavaScript中一个非常重要的概念,它涉及到函数的作用域链和变量的访问权限。闭包并不是一个新的函数,而是一种机制,使得一个函数能够访问其外部函数的变量。
闭包的基本概念
闭包使一个函数可以访问并操作其外部函数的变量。即使外部函数已经执行完毕,闭包仍然可以让内部函数访问这些变量。这种机制使得闭包非常适合用于封装变量和实现数据的私有性。
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
};
}
};
console.log(object.getNameFunc()()); // 输出 "My Object"
在这段代码中,getNameFunc
返回了一个内部函数,该内部函数可以访问 object
对象中的 name
属性。尽管 getNameFunc
已经执行完毕,但内部函数依然可以通过闭包访问 object.name
。
使用 this
关键字
在对象方法中,this
关键字通常指向当前对象。但在闭包中,this
并不能直接传递给内部函数,因此需要使用 that
进行引用。
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}.bind(this);
}
};
console.log(object.getNameFunc()()); // 输出 "My Object"
这里使用了 .bind(this)
方法,确保内部函数中的 this
指向 object
对象。
偏应用(Partial Application)
偏应用是指预先绑定函数的部分参数,从而生成新的函数。这在某些场景下非常有用,可以简化代码。
function multiply(x, y) {
return x * y;
}
// 偏应用:预先绑定 x=2
const double = multiply.bind(null, 2);
console.log(double(5)); // 输出 10
立即执行函数表达式 (IIFE)
立即执行函数表达式是一种常见的模式,用于创建独立的作用域,避免全局命名空间污染。
(function () {
console.log("ran!");
})();
use strict
模式
使用 "use strict";
可以启用严格模式,防止一些潜在的错误,并提高代码的可维护性。
"use strict";
function func() {
this.a = 100;
a = 33; // 在严格模式下会报错
}
this.a = 200;
console.log(this.a); // 输出 200
func();
console.log(this.a); // 输出 200
闭包与循环
在循环中使用闭包时需要注意,闭包可能会捕获循环变量的最终值,而不是每次迭代的值。
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
上面的代码会输出 5 5 5 5 5
,而不是 0 1 2 3 4
。为了避免这种情况,可以使用 let
替代 var
,或者在每次迭代中创建一个新的闭包。
通过上述例子,我们可以看到闭包在JavaScript中的强大之处以及如何正确地使用它们。希望这些示例能帮助你更好地理解和使用闭包。
那js中为什么有闭包呢?你有没有你考虑过?
看不懂,有点高深
this是不是用做指定作用域的
说的太复杂了
刚遇到的一个闭包使用 $(e).on(“click”,dismiss,function(){ var $this = $(this),$e = $("#e"); $e.unbind(“click”); $e.bind(“click”,function(){ return function(){ var text = $("#fomuDIVContent").text(); $this.data(“fomu”,text) } }($this)) });
在《javascript高级程序设计》书中,闭包章节讲的非常清楚,看过的所有解释中最浅显易懂的
PS LZ例子中的 getNameFunc : function(){ var that = this; return function(){ return that.name; }; } 返回的是一个匿名函数,匿名函数的this是会绑定到window的,所以需要用that指定回object。
闭包可以用在实现私有变量,以及需要局部变量常驻内存的场景。
其实我很纳闷,为什么一直流传JS简单……我觉得一旦涉及对象和原型,JS一点都不简单。至少网络上都没有一个能够很简明简单回答这些基本概念的帖子。于是这个简单的语言,大家一直在围绕着一些基础的概念在争论。。。。每个人都解释的很有道理的样子……但是到底是啥。。
js一点都不简单~~~
Node.js 中 JavaScript 闭包的理解
闭包是一个常见的概念,尤其是在 JavaScript 中。闭包不仅是一个函数,而是一个函数和它周围状态(词法环境)的组合。这意味着,函数可以访问其自身作用域内的变量、外部函数的变量,以及全局变量。
示例代码
首先,让我们来看一个简单的闭包示例:
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
}
}
const counter = createCounter();
counter(); // 输出 1
counter(); // 输出 2
在这个例子中,createCounter
函数返回了一个匿名函数,该匿名函数访问了 createCounter
函数内部定义的变量 count
。每次调用 counter()
时,count
的值都会增加并输出,这表明闭包使得 count
变量在多次调用中保持其状态。
闭包的作用
闭包的主要用途之一是封装变量。例如,你可以使用闭包来模拟类中的私有变量:
function Counter() {
let count = 0;
this.increment = function() {
count++;
console.log(count);
}
this.decrement = function() {
count--;
console.log(count);
}
}
const myCounter = new Counter();
myCounter.increment(); // 输出 1
myCounter.increment(); // 输出 2
myCounter.decrement(); // 输出 1
这里,count
变量只能在 Counter
对象的方法中访问,不能从外部直接访问。
this
关键字
this
关键字在闭包中通常用于引用当前对象。如果不使用 bind
或箭头函数,this
在回调函数中可能会指向全局对象或 undefined
(在严格模式下)。
var object = {
name: "My Object",
getNameFunc: function() {
return () => {
console.log(this.name);
};
}
};
console.log(object.getNameFunc()()); // 输出 "My Object"
在这个例子中,使用箭头函数确保 this
指向 object
对象。
立即执行函数 (IIFE)
立即执行函数表达式 (IIFE) 是另一种常见的闭包用法,它可以避免变量泄露到全局作用域:
(function() {
console.log('ran!');
})();
这段代码定义了一个匿名函数,并立即执行它。这样可以创建一个新的作用域,不会污染全局命名空间。
总结
闭包是 JavaScript 中一个强大且有用的特性。它不仅可以用来封装变量,还可以控制变量的作用域,防止全局污染。然而,使用闭包时也需要注意性能影响,特别是在大量使用的情况下。