折腾自己的js闭包(一)
闭包是什么鬼?
15年10月份初到现在的公司时,有天晚上加班后临下班时,当时的组长问我知道闭包不,由于我是半路出家来做程序的,几乎很少用到闭包这个东东,并不是很了解这个概念,组长写出了这么段代码。
var temp = {
data: [],
totalRecords: 0
};
(function(dm){
for(var i=0;i<10;i++){
dm.data.push(i*i);
dm.totalRecords += 1;
}
})(temp);
console.log(temp); //结果得到 object{data:Array[10],totalRecords:10}
我当时就觉得很神奇了,函数内部的dm变量,经过这么一折腾,在外面也就可以访问到其变化之后的值了,原因何在?于是乎,后来我花了时间来研究这个闭包,到底是什么鬼?到底会有什么时候需要用到?
首先来说我们平常遇到的一个很普遍的变量的作用域的问题,例如有如下js代码:
function f1(){
var strB = strA + " is writing code."
document.write(strB);
}
f1(); //结果当然是2个字符串拼接起来 xiangxiao's weekend is writing code.
这个无需多解释,因为在js函数内部肯定是可以访问并使用在函数体外面的变量的嘛;
再来看另一段js代码:
function f1(){
var strA = "xiangxiao's weekend";
var strB = strA + " is writing code."
};
document.write(strB); //此处报错
报错的原因就是这个strA和strB是函数f1 的局部变量,它 的作用域仅限于f1函数体内部,外部是访问不了的,这里牵扯到作用域的问题,既然说到这儿也就耗一点篇幅来讲这个作用域的东东吧。
在JavaScript中,函数也是对象,也可以通过var func = new Function('a','b','return a+b')这样的形式来定义函数,一般不这样做的原因是将众多代码弄在一个超长的字符串里,代码的可读性太差。简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。
1、全局作用域
即在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:
(1)最外层函数和在最外层函数外面定义的变量拥有全局作用域,例如:
(2)未使用var关键字定义的变量也被赋予了全局的作用域;
};
say(); //结果是xiangxiao
document.write(authorName);//报错
document.write(blogName);//结果是dearxiangxiao
(3)所有window对象的属性拥有全局作用域。
这个就无需举例了,window.innerWidth诸如此类的东东,用得也蛮多的了。window对象还可自定义属性和方法,当然跟这里没啥关系了。
2、局部作用域
和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所以在一些地方也会看到有人把这种作用域称为函数作用域。
之前1中的(1)那个例子
Fn(); // 这是语句,Statement;解释器遇到语句是会运行它的。
function Fn(){ //some code}();
当然是不能,但是为什么呢?因为 function Fn(){ //some code} 这个部分只是一个声明,对于解释器来说,就好像你写了一个字符串 "function Fn(){ //some code}",它需要使用解析函数,比如 eval() 来执行它才可以。所以把 () 直接放在声明后面是不会执行,这是错误的语法。
如何把它变得正确?说起来也简单,只要把 声明 变成 表达式(Expression) 就可以了。实际上转变表达式的办法还是很多的,最常见的办法是把函数声明用一对 () 包裹起来,于是就变成了:
(function Fn() { //some code})();
这样等价于:
function Fn() { //some code};
Fn();
另外,还有很多其他写法可以将函数声明变为表达式,比如:
!function() { //some code}();
+function() {// some code}();
再回到那段组长写的代码
var temp = {
data: [],
totalRecords: 0
};
(function(dm){
for(var i=0;i<10;i++){
dm.data.push(i*i);
dm.totalRecords += 1;
}
})(temp);
console.log(temp);
这里相当于定义了一个以temp为参数的函数,(function(dm){ //......省略代码})() 这部分里第一个括号里相当于定义了一个函数,返回值是一个函数,第二个括号就是在执行这个被返回的函数了,dm只不过是形参,temp的值在那个匿名函数里改变了,后面再打印temp的值,理所当然的是 object{data:Array[10],totalRecords:10}了。
这就是这篇博文的全部内容了,个人简见解,不喜勿喷,后面我还会研究下闭包的具体用途。
ps:吐槽一下成都的这个鬼天气,今年感觉没春天啊,冬天之后立马到夏天,放个清明节下了2天雨。