JS中立即执行函数和闭包的区别
函数声明
规则:必须指定一个函数名字
foo();
function foo() {
console.log("函数声明")
}
由于函数声明会被提升,所以调用函数可以在之前或之后调用
函数表达式
规则:将函数赋值给一个变量
var foo = function () {
console.log("函数表达式")
}
foo()
由于函数表达式,只会对变量foo进行提升,只有运行到代码处,才会对变量foo进行赋值,所以调用函数必须在函数表达式之后
立即执行函数
常用的两种方式
(function () {
console.log("立即执行函数")
})(); (function () {
console.log("立即执行函数")
}())
立即执行函数的演变
1:在函数表达式后加括号,可以立即执行函数
var foo = function () {
console.log("立即执行函数")
}();
2:在匿名函数后加括号,不可以立即执行函数
function () {
console.log("立即执行函数")
}();
在函数表达式后加括号可以立即执行函数,但如果不把匿名函数赋值给变量,而直接在后边加一个括号,则会报语法错误。因为当JS引擎在遇到function时,会默认把它当作是函数声明,所以必须要有一个函数名
3:在函数声明后加括号,不可以立即执行函数
function foo() {
console.log("立即执行函数")
}()
如果给匿名函数添加一个函数名,也就变成了函数声明,然后在函数声明后加括号,也会报语法错误,因为函数声明会被提升,当提升后就相当于在代码中只写了一对括号,而这个括号和前面的函数声明又没什么关系,所以语法报错
javascript中,括号内不允许包含语句,但可以是表达式
引擎先遇到括号,然后遇到关键字function , 就自动把括号里面的代码识别为函数表达式,而不是函数声明,所以立即执行函数可以这样写(function(){})()
闭包
定义:内部函数被外部函数以外的变量引用时,就形成了一个闭包
常用方式示例:
function foo() {
var num = 10;
return function () {
var age= 20;
console.log(++num);
console.log(++age);
}
}
var f = foo();
f(); //11 21
f(); //12 21
通过闭包就可以让外部作用域访问函数内部作用域的变量,我们知道当函数执行完以后,会立即销毁,但 foo 函数内的 num 属性被内部的匿名函数引用着,而内部函数又被外部变量 f 引用着,所以函数 foo 在执行完以后虽然会立即销毁,但它内部的匿名函数在创建的时候就会随之创建一个特殊的容器,用于保存 上层作用域 中 变量 的引用,所以foo 函数中的 num 并不会销毁,当执行第一次 f() 时,会创建 f() 对应的作用域,其中num 会从之前创建的特殊的容器中取出上层作用域中变量的值,而 age 会立即声明一个,当函数执行完毕后,就会销毁对应的作用域,此时 age 也会随之销毁,但变量 f 对应的指针地址不会变,当再次执行 f() 时,又会再创建一个 f() 对应的作用域,num 还是会从上层作用域中拿,但 age 还是会重新声明,使用完后还是会被销毁。
很显然这样会一直持有对 num 的引用,无法进行回收,造成内存占用,所以当不使用时,可以把 f 置为null,来让垃圾回收器进行回收。
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。
如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也
会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后
不会被回收的原因
闭包优点和缺点
优点
减少全局变量的使用,保证了内部变量的安全,同时外部函数也可以访问内部函数的变量
在内存中维持一个变量,也可以用作缓存
缺点
被引用的内部变量不能被销毁,增大了内存消耗,使用不当易造成内存泄露,解决办法可以在内部变量不使用时,把外部的引用置为 null
闭包就是函数间的跨作用域访问,会导致性能损失
立即执行函数和闭包的区别
立即执行函数和闭包没有关系,虽然两者会经常结合在一起使用,但两者有本质的不同
立即执行函数只是函数的一种调用方式,只是声明完之后立即执行,这类函数一般都只是调用一次(可用于单例对象上),调用完之后会立即销毁,不会占用内存
闭包则主要是让外部函数可以访问内部函数的作用域,也减少了全局变量的使用,保证了内部变量的安全,但因被引用的内部变量不能被销毁,增大了内存消耗,使用不当易造成内存泄露
立即执行函数与闭包常结合示例
如:单例
let single = (function () {
let name = "小明";
let age = 20;
return {
getName: function () {
return name;
},
getAge: function () {
return age;
}
}
})();
console.log(single.getName()); //小明
console.log(single.getAge()); //20
给对象创建了私有变量name、age又对外提供了获取的方法,典型的自执行函数和闭包结合使用的示例
原文链接:https://blog.csdn.net/Liu_yunzhao/article/details/90641956
JS中立即执行函数和闭包的区别的更多相关文章
- js中自执行函数(function(){})()和(function(){}())区别
方式一,调用函数,得到返回值.强制函数直接量执行再返回一个引用,引用在去调用执行方式二,调用函数,得到返回值.强制运算符使函数调用执行(function(){})(); 是 把函数当作表达式解析,然后 ...
- JS中立即执行函数的理解
1.匿名函数不能单独定义,必须进行赋值操作或者立即执行,否则会被JS引擎定义为语法错误 function(){alert(dada);} VM229:1 Uncaught SyntaxError: U ...
- js中立即执行函数写法理解
在理解了一些函数基本概念后,回头看看( function(){…} )()和( function (){…} () )这两种立即执行函数的写法,最初我以为是一个括号包裹匿名函数, 并后面加个括号立即调 ...
- js中自执行函数写法
//自执行写法1 (function T(){ alert(1) })() //自执行写法2 var T1=function(){ alert(1) }(); //传值 var para1={a:1; ...
- js中的匿名函数和匿名自执行函数
1.匿名函数的常见场景 js中的匿名函数是一种很常见的函数类型,比较常见的场景: <input type="button" value="点击" id ...
- js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题)
js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题) 一.总结 需要好好看下面代码 本质是因为匿名函数用到了循环中的变量,而普通方式访问的话,匿名函数的访问在循环之后,所以得到的i是循环 ...
- js中如何在一个函数里面执行另一个函数
1.js中如何在函数a里面执行函数b function a(参数c){ b(); } function b(参数c){ } 方法2: <script type="text/javasc ...
- 聊一下JS中的作用域scope和闭包closure
聊一下JS中的作用域scope和闭包closure scope和closure是javascript中两个非常关键的概念,前者JS用多了还比较好理解,closure就不一样了.我就被这个概念困扰了很久 ...
- 对js中局部变量、全局变量和闭包的理解
对js中局部变量.全局变量和闭包的理解 局部变量 对于局部变量,js给出的定义是这样的:在 JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它.(该变量的作用域 ...
- js中的回调函数的理解和使用方法
js中的回调函数的理解和使用方法 一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为 ...
随机推荐
- spring-in-action-day05-REST
1.创建RESTFUL端点 (1)创建get端点 (2)创建post端点 (3)创建put/patch端点 (4)创建delete端点 2.启用超媒体 3.消费REST端点 3.1使用RestTemp ...
- JAVA虚拟机14 类加载器
1.简介 Java虚拟机设计团队有意把类加载阶段中的"通过一个类的全限定名来获取描述该类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的 ...
- vue 事件中央总线
vue 事件中央总线 作用: 实现任意组件间的通信 实现的方法: 有以下两种方式 方式1: 全局事件总线 1.在main.js文件中定义 new Vue({ el: '#app', router, s ...
- window.alert和console.log()
使用 window.alert() 您能够使用警告框来显示数据: 实例 <!DOCTYPE html> <html> <body> <h1>我的第一张网 ...
- 【源码】RapidJSON 源码剖析(0.1):调试工具 GDB 的使用
[源码]RapidJSON 源码剖析(0.1):调试工具 GDB 的使用 正式开始源码阅读之前,有必要了解一下源码阅读中用到的调试工具 GDB. GDB(GNU Debugger) 是一种可以运行在多 ...
- Oracle 备份与恢复 (Docker部署版)
Oracle 备份与恢复 (Docker部署版) 一,宿主机设置定时备份脚本 1.检查Oracle容器是否正常运行 docker ps 2.进入容器,创建shell脚本 #oracle11g 是容器名 ...
- CF1470E 题解 —— 询问分叉转构建虚树的复杂度证明
简要题意:给定一个长为 \(n\) 的排列 \(p\) 和一个整数 \(c\le 4\),称排列 \(p'\) 合法当且仅当 \(p'\) 可以通过 \(p\) 翻转若干个不交的区间 \([l,r]\ ...
- python中的字符串的常用方法介绍
a = "alxe Li 金角大王" #创建一个字符串来演示方法的功能结果.一下都使用这个字符串演示. 首先要了解的常识性的知识点是:字符串是不可变的序列.所有对字符串的内 ...
- typescript - 学习档案
由于内容繁多,使用掘金来记录此笔记,方便索引跟随!未完待续~~~ 地址如下: https://juejin.cn/post/6899350420541014030/#heading-20
- 【博图scl语言】313-2dp
①如果 if(***) then *** := ***; end_if; ②循环 for n1:=1 to 50 by 1 do end_for; WHILE #n1 < 54 DO END_W ...