那些年我们一起过的JS闭包,作用域,this,让我们一起划上完美的句号。
之前有写过闭包,作用域,this方面的文章,但现在想想当时写的真是废话太多了,以至于绕来绕去的,让新手反而更难理解了,所以就有了此篇文章,也好和闭包,作用域,this告一段落。
第一个问题:什么是闭包?
我不想回答这个问题,但是我可以告诉你的是闭包可以解决函数外部无法访问函数内部变量的问题。下面是一段没有使用闭包的代码:
function fn(){
var a = 10;
}
alert(a);
//报错了,因为a没有定义,虽然函数fn里面定义了a但是,但是它只能在函数fn中使用。也就是作用域的问题。
再看‘闭包可以解决函数外部无法访问函数内部变量的问题’这段话,好像有点意思,那么究竟闭包是怎么做的,看下面代码。
function fn(){
//定义了一个变量name
var name = '追梦子';
//我现在想在外部访问这个变量name怎么办呢?哈:不是有return,我把它返回出去,我再用个变量接收一下不就可以了,哈哈哈哈~~~~~
return name;
}
var name = fn();//接收fn返回的name值。
alert(name);//追梦子;
·······这里的闭包就是利用函数的return。除了通过return还可以通过其他的几种方法如下:
方法1:
function fn(){
var a = 0;
b = a;
}
alert(b)
这里利用了js的一个特性,如果在函数中没有用var定义变量,那么这个变量属于全局的,但这种方法多少有些不好。
方法2:
var f = null;
function fn(){
var a = 0;
f = function(){
a++;
f.a = a;
};
}
fn();
f();
alert(f.a);//1
f();
alert(f.a);//2
但好像也没有那样神奇对吧?其实闭包还有一个很重要的特性。来看一个例子。
var lis= document.getElementsByTagName['li'];
//假如这段代码中的lis.length = 5;
for(var i=0;i<lis.length;i++){
lis[i].onclick = function(){
alert(i);
};
}
最终结果是不管单击哪个li元素都是弹5。不信你试试。为什么呢。看下面分析。
for(var i=0;i<lis.length;i++){
}
// i = 5对吧
lis[0].onclick = function(){
alert(i);
};
lis[1].onclick = function(){
alert(i);
};
lis[2].onclick = function(){
alert(i);
};
lis[3].onclick = function(){
alert(i);
};
lis[4].onclick = function(){
alert(i);
};
为什么会这样呢,因为你for循环只是给li绑定事件,但是里面的函数代码并不会执行啊,这个执行是在你点击的时候才执行的好吧?但是此时的i已经是5了,所以所有的都打印出5来了。
如果想解决这个问题我们可以使用闭包,闭包的特点不只是让函数外部访问函数内部变量这么简单,还有一个大的特点就是通过闭包我们可以让函数中的变量持久保持。来看。
function fn(){
var num = 0;
return function(){
num+=1;
alert(num);
};
}
var f = fn();
f(); //1
f(); //2
如果你是初学者可能没觉得这有什么。OK,让你看个东西。
function fn(){
var num = 5;
num+=1;
alert(num);
}
fn(); //6
fn(); //6
为什么呢?因为函数一旦调用里面的内容就会被销毁,下一次调用又是一个新的函数,和上一个调用的不相关了,不过有个特殊的情况,看这:
function fn(){
var num = 0;
return function(){
num+=1;
alert(num);
};
}
var f = fn();
f(); //1
f(); //2
这段代码很简单,不要被它欺骗了,我们首页定义了一个fn函数,里面有个num默认为0,接着返回了一个匿名函数(也就是没有名字的函数)。我们在外部用f接收这个返回的函数。这个匿名函数干的事情就是把num加1,还有我们用来调试的alert。
这里之所以执行玩这个函数num没有被销毁是因为那个匿名函数的问题,因为这个匿名函数用到了这个num,所以没有被销毁,一直保持在内存中,因此我们f()时num可以一直加。
这里你可以看不懂了,之所以有这种感觉是因为js回收机制你不懂,强烈建议你看我之前的再次讲解js中的回收机制是怎么一回事。这篇文章。
关于闭包的知识就到这里了,如果你想看关于闭包的案例可以看这篇:从闭包案例中学习闭包的作用,会不会由你。
而外说一句:这里并不是说return就是闭包,这里只是强调return的重要性,如果你还是一个新手建议你多看一些初级文章,在来看这篇文章,希望你会有新收获。写这篇文章一开始我也说了它的目的是回顾一下当初我没有理解的地方,当初已经理解的这篇文章并没有过多的去讲。
作用域竟然上面已经讲完了~~~
大前端 369451410欢迎你的加入。
那就说一下this:
我们经常用this,但是也许你还不清楚它是什么吧?
lis[i].onclick=function(){this.style.border="1px solid #ccc";} ;
此时的this表示lis[?]它的引用。
这里的i不是i实际上是一个准确的数字:如lis[2].onclick = function(){this.style.border="1px solid #ccc";}; this = lis[2] ;
简单来说this它始终引用一个对象。
lis[2]它也一个对象,是一个HTMLElement对象。
其实不管什么情况下它都会有对象的,这个你不用操心,看
function fn(){
this.name = "追梦子";
};
fn();
alert(this.name);//追梦子
//当然也可以这样
alert(name);
虽然这段代码中看似没有对象,但大错特错,因为浏览器环境中默认就有一个window对象,因此你在函数中直接用this.name实际上这个this就表示window。
var json = {
name:'yyy',
fn:function(){alert(this.name)}
};
json.fn(); // yyy;
fn属于json,所以this实际上就是json。
如果你是初学者建议你暂时先记住这三点,当然this还有很多要说的,不过做为初学者你可以在项目中通过console.log来检查this是否是你预期的那样。
更多关于this的内容,可以看彻底理解js中this的指向,不必硬背。
这篇文章并不算是一篇入门的教程,这篇文章主要是总结之前没有理解的地方,或者是以一种更加简单明了的方式写的,当然是按照我自己的理解来的,不一定你能理解,sorry,好了一切就从这里结束吧。
那些年我们一起过的JS闭包,作用域,this,让我们一起划上完美的句号。的更多相关文章
- js闭包的作用域以及闭包案列的介绍:
转载▼ 标签: it js闭包的作用域以及闭包案列的介绍: 首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...
- JS 之作用域链和闭包
1.JS无块级作用域 <script> function Main(){ if (1==1){ var name = "alex"; } console.log(nam ...
- js中作用域和闭包
作用域链实例 (1) function example() { var age = 23; alert(age) } var age = 25; example(); alert(age); // ...
- JS之作用域与闭包
JS之作用域与闭包 作用域在JS中同样也是一个重要的概念.它不复杂,因为ES5中只有全局作用域和函数作用域,我们都知道他没有块级作用域.但在ES6中多了一个let,他可以保证外层块不受内层块的影响 ...
- 深入理解JS函数作用域链与闭包问题
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } ); a.fun(); a.f ...
- javascript深入理解js闭包
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- 浅谈Js闭包现象
一.1.我们探究这个问题的时候如果按照正常的思维顺序,需要知道闭包是什么它是什么意思,但是这样做会让我们很困惑,了解这个问题我们需要知道它的来源,就是我们为什么要使用闭包,先不管它是什么意思! ...
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- Js闭包常见三种用法
Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...
随机推荐
- Unity : Ran out of trampolines of type 2
Unity 导出游戏到 iOS 平台,当时选择的设置是 mono2x, 结果游戏各种莫名其妙的崩溃,再崩溃, 几乎运行不到一分钟就崩溃,而在 editor 和 android 平台都是正常的. 查看出 ...
- C# final project
Problem Statement You are tasked with developing a task manager. The task manager will allow people ...
- 转:如何调试PHP的Core之获取基本信息
其实一直想写这个系列, 但是一想到这个话题的宽泛性, 我就有点感觉无法组织. 今天我也不打算全部讲如何调试一个PHP的Core文件, 也不会介绍什么是Coredump, 选择一个相对比较简单的方向来介 ...
- 关于HIVE的数据模型介绍
(1)Hive数据库 类似传统数据库的DataBase,在第三方数据库里实际是一张表.简单示例命令行 hive > create database test_database; (2)内部表 H ...
- cordova for ios(android一样)添加插件
1.进入当前工程文件夹 终端:cd ~/Desktop/ cd piao 2.添加插件 :cordova plugin add Basic device information (Device API ...
- STL学习
//vector的使用 //相当于数组,常用的 添加 删除 清空 测长 操作 #include<iostream> #include<algorithm> #include&l ...
- 找回消失的ASUS显卡
笔记本蓝屏了几次之后,发现独立显卡GT335M不见了,设备管理器,驱动精灵,都找不到,网上问这个问题的人还不少,得到的回答几乎都是说重装驱动.根本不行,这时候安装nVIDIA驱动,会提示说“未找到兼容 ...
- Groonga 3.0.8 发布,全文搜索引擎
Groonga 3.0.8 改进了管理界面的可用性,支持 groonga_query_log_path 指令(groonga-httpd) 提供基于 nginx 的 HTTP 服务功能,改进了 del ...
- Ubuntu全新安装firefox最新版本
Ubuntu默认安装firefox,但是自带的软件仓库是不会随firefox更新的,我在使用中老是提示flash插件需要激活,提示中可选的解决方式有三种 1.更新flash插件,但是跳转到adobe的 ...
- Aoite 系列(03) - 一起来 Redis 吧!
Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数 ...