一篇文章把你带入到JavaScript中的闭包与高级函数
在JavaScript中,函数是一等公民。JavaScript是一门面向对象的编程语言,但是同时也有很多函数式编程的特性,如Lambda表达式,闭包,高阶函数等,函数式编程时一种编程范式。
function dada() {
var a = 1;
var b = function() {
console.log(a);
}
return b
// b 就是一个闭包函数,因为它能访问dada函数的作用域
}
JavaScript的函数也是对象,可以有属性,可以赋值给一个变量,可以放在数组里作为元素,可以作为其他对象的属性,什么都可以做,别的对象能做的它也能做,别的对象不能做的它也能做。
函数和其他普通对象来说,是一样的,有属性有方法,普通对象能做的,函数也能做。学习JavaScript中的闭包和高级函数是基础篇哦!
那么什么是闭包?闭包,就是有权访问其外部作用域中的变量和参数的函数。
var func = (function() {
var item = 0;
return {
add: function(num) {
item = typeof num === 'number' ? num : 1;
},
value: function() {
return item;
}
}
})();
闭包函数可以访问它创建时所处的上下文环境中的变量以及参数,this以及arguments除外。
闭包:
函数作为返回值,高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。闭包的形成与变量的作用于和变量的生命周期密切相关。
变量作用域:
var func = function() {
var a = 1;
console.log(a); // 1
}
func();
console.log(a); // Uncaught ReferenceError: a is not defined
闭包是一个可以访问到其他函数内部变量的函数,闭包的重点在于,变量的作用域,和,变量的生命周期。
变量的作用域
// 变量的作用域
var my = function() {
var a = 1;
console.log('my', a); // 1
}
my();
console.log(a) // ReferenceError: a is not defined
变量的声明周期
// 变量的生命周期
let fu = function() {
let a = 0;
a ;
console.log('dada', a);
}
fu(); // 1
fu(); // 1
fu(); // 1
let func = function() {
let a = 0;
return function() {
a ;
console.log('a', a);
}
}
let fun = func()
fun(); // 1
fun(); // 2
fun(); // 3
闭包中的变量没有被销毁,这个涉及到垃圾回收机制,即标记清楚和引用计数
function num() {
for(var i=0; i< 10; i ) {
setTimeout(function() {
console.log('da', i) // 10
},0)
}
}
num();
function num1() {
for(var i=0; i< 10; i ) {
(function (i) {
setTimeout(function() {
console.log('da', i)
},0)
})(i) // 1,2,3,...,10
}
}
num1()
什么是闭包的例子:
function da() {
var a = 1;
function dada() {
console.log(a);
}
return dada
}
var d = da();
d(); // 1
闭包如果不是那么必要,请不要去创建它,因闭包在处理速度和内存消耗方面对性能具有负面影响。
闭包的形式与变量的作用域以及变量的生存周期有着密切的相关性。
变量的作用域:
变量的作用域指的是变量的有效范围,当一个函数中声明的一个变量不带上关键字var的时候,这个变量就成为了全局变量,当这个变量用var声明的时候,这个变量就变成了局部变量,只有在函数内部才能访问到这个变量,在函数外面是访问不到的。举例:
var func = function() {
var a = 1;
alert(a); // 1
};
func();
alert(a); // Uncaught ReferenceError: a is not defined
嵌套例子:
var a = 1;
var fun = function() {
var b = 2;
var func1 = function() {
var c = 3;
alert(b); // 2
alert(a); // 1
}
func1();
alert(c); // c is not defined
};
fun();
变量的生命周期:
闭包的又一重要概念,变量的生命周期,对于全局变量的生命周期来说是永久的,对于函数内部的局部变量来说,是短暂的,它们都会随着调用的结束而被销毁。
var func = function() {
var a = 1;
};
func();
var func = function() {
var a = 1;
return function() {
a ;
alert(a);
}
};
var da = func();
da(); // 2
da(); // 3
da(); // 4
闭包
函数作为返回值
function num(arr) {
return arr.reduce(function (x,y) {
return x y;
});
}
num([1,2,3]); // 6
变成函数
function func(arr) {
var sum = function() {
return arr.reduce(function(x,y) {
return x y;
});
}
return sum;
}
// 调用 函数
var da = func([1,2,3]); // 调用函数
// 运行
da(); // 6
var da1 = func([1,2]);
var da2 = func([1,2]);
da1 == da2 // false
每次调用返回的都是一个新的函数
利用闭包进行缓存:
function add(a) {
return a 1;
}
利用闭包进行缓存:
闭包的作用
封装变量,闭包可以封装形成私有变量:
var da = function() {
var a = 1;
for (var i=0; i < arguments.length; i ){
a = a * arguments[i];
}
return a;
}
alert(a(1,2,3));
在JavaScript中是没有块级作用域的概念的:
function add() {
var arr = [ 1,2,3 ];
for (var i=0; i < arr.length; i ) {
alert( arr[i]);
}
var i; // 重新声明变量
alert(i);
}
块级作用域效果,闭包:
(function() {
// 块级作用域
})()
延续局部变量的生命周期:
var myImg = function( src ) {
var img = new Image(0;
img.src = src;
};
myImg('http:///...');
解决请求丢失问题:
var da = (function() {
var imgs = [];
return function(src) {
var img = new Image();
imgs.push(img);
img.src = src;
}
})();
闭包是指有权访问另一个函数作用域中变量的函数。
闭包:函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内。
词法作用域:作用域是在编写代码的时候确定的动态作用域:作用域是在代码运行的时候确定的
<script>
function add(num){
var sum = 5;
return sum num;
}
var sum = add(4);
</script>
Execution Contexts = {
variable object:变量对象;
this value: this指针;
scope chain:作用域链;
}
全局变量
function myFunction() {
var a = 4;
return a * a;
}
var a = 4;
function myFunction() {
return a * a;
}
var counter = 0;
function add() {
return counter = 1;
}
add();
add();
add();
// 计数器现在为 3
function add() {
var counter = 0;
return counter = 1;
}
add();
add();
add();
// 本意是想输出 3, 但事与愿违,输出的都是 1 !
function outter(){
var sky="blue";
function inner(){
console.log(sky);
}
return inner;
}
var result=outter();
result(); //"blue"
函数与对其状态即为词法环境的引用共同构成闭包,也就是,闭包可以让你从内部函数访问外部函数作用域。
词法作用域:
function init() {
var name = "dada";
// name 是一个被 init 创建的局部变量
function displayName() {
// displayName() 是内部函数,一个闭包
alert(name);
// 使用了父函数中声明的变量
}
displayName();
}
init();
闭包:
function mFunc() {
var name = "dada";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = mFunc();
myFunc();
高阶函数
什么是高阶函数,JavaScript中的函数都指向某个变量,既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,就叫高阶函数。
高级函数:
function add(x, y, f) {
return f(x) f(y);
}
'use strict';
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow);
// [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);
var f = function (x) {
return x * x;
};
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var result = [];
for (var i=0; i<arr.length; i ) {
result.push(f(arr[i]));
}
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x y;
});
// 25
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x * 10 y;
});
// 13579
在一个数组中,删除偶数,保留奇数:
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
r;
// [1, 5, 9, 15]
回调函数
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element);
// 依次打印'A', 'B', 'C'
console.log(index);
// 依次打印0, 1, 2
console.log(self);
// self就是变量arr
return true;
});
'use strict';
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr);
// [1, 2, 10, 20]
var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1;
// ['A', 'B', 'C']
a2;
// ['A', 'B', 'C']
a1 === a2;
// true, a1和a2是同一对象
every()方法可以判断数组的所有元素是否满足测试条件
find()方法用于查找符合条件的第一个元素
findIndex()方法返回这个元素的索引
高阶函数即为输入参数里有函数,或是输出是函数的函数
function add() {
var num = 0
return function(a) {
return num = num a
}
}
var adder = add()
adder(1)
// 输出: 1
adder(2)
// 输出: 3
高阶函数满足条件:函数作为参数被传递,函数作为返回值输出
回调函数:
var getUserInfo = function( userId, callback ){
$.ajax( 'http://xxx.com/getUserInfo?' userId, function( data ){
if ( typeof callback === 'function' ){
callback( data );
}
});
}
getUserInfo( 522624714, function( data ){
alert ( data.userName );
});
//从小到大排列
[ 1, 5, 3 ].sort( function( a, b ){
return a - b;
});
// 输出: [ 1, 3, 5 ]
//从大到小排列
[ 1, 5, 3 ].sort( function( a, b ){
return b - a;
});
// 输出: [ 5, 3, 1 ]
什么是函数式编程,函数式编程时一种编程形式,让你能将函数作为参数传递给其他函数并且能够将函数作为值返回。
在JavaScript中,函数是一类特殊的对象:
function hello() {
console.log('hello');
}
hello();
hello.name='da';
console.log(hello.name); // da
const num = function(x) {
return x*x;
}
num(8); // 64
高阶函数是一个函数,它是接收函数作为参数或者是将函数作为输出的值进行返回。高阶函数实战:
const arr1 = [1,2,3];
const arr2 = arr1.map(function(x) {
return x * 2;
});
console.log(arr2);
const arr1 = [1,2,3];
const arr2 = arr1.map(x => x*2);
结语
简而言之,高阶函数是一个函数,它是可以接受函数作为参数,还可以作为返回一个值返回,返回一个函数。闭包可以让你从内部函数访问外部函数作用域。闭包即是一个函数,能够访问另一个函数作用域的变量的函数。
关于目前文章内容即涉及前端,PHP知识点,如果有兴趣即可关注,很荣幸,能被您发现,真是慧眼识英!也感谢您的关注,在未来的日子里,希望能够一直默默的支持我,我也会努力写出更多优秀的作品。我们一起成长,从零基础学编程,将 Web前端领域、数据结构与算法、网络原理等通俗易懂的呈现给小伙伴。分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯。
推荐阅读
1、你知道多少this,new,bind,call,apply?那我告诉你
2、为什么学习JavaScript设计模式,因为它是核心
意见反馈:若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。
感谢阅读,原创不易,喜欢就点个赞吧,这是我写作最大的动力。
欢迎关注达达的简书!
这是一个有质量,有态度的博客
一篇文章把你带入到JavaScript中的闭包与高级函数的更多相关文章
- JavaScript中的闭包与匿名函数
知识内容: 1.预备知识 - 函数表达式 2.匿名函数 3.闭包 一.函数表达式 1.定义函数的两种方式 函数声明: 1 function func(arg0, arg1, arg2){ 2 // 函 ...
- JavaScript中的闭包和匿名函数
JavaScript中的匿名函数及函数的闭包 1.匿名函数 2.闭包 3.举例 4.注意 1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没 ...
- 让你分分钟学会Javascript中的闭包
Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...
- Javascript中的闭包(转载)
前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...
- 狗日的Javascript中的闭包
前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...
- 难道这就是JavaScript中的"闭包"
其实对于JavaScript中的"闭包"还没真正理解,这次在实际Coding中似乎遇到了"闭包"的问题,仅此摘录,以待深究. 表现为jQuery的post方法回 ...
- JavaScript中常见的数组操作函数及用法
JavaScript中常见的数组操作函数及用法 昨天写了个帖子,汇总了下常见的JavaScript中的字符串操作函数及用法.今天正好有时间,也去把JavaScript中常见的数组操作函数及用法总结一下 ...
- JavaScript中常见的字符串操作函数及用法
JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
随机推荐
- .net core mvc启动顺序以及主要部件4-MVC
前面三章已经把MVC启动过程以及源代码做了讲解,本章开始正式MVC,mvc全称叫model view controller,也就是把表现层又细分三层,官网的图片描述: 默认创建了一个.net core ...
- 我的第一个netcore2.2 api项目搭建(三)续
上一章快速陈述了自定义验证功能添加的过程,我的第一个netcore2.2 api项目搭建(三) 但是并没有真正的去实现,这一章将要实现验证功能的添加. 这一章实现目标三:jwt认证授权添加 在netc ...
- asp.net core 系列之允许跨域访问2之测试跨域(Enable Cross-Origin Requests:CORS)
这一节主要讲如何测试跨域问题 你可以直接在官网下载示例代码,也可以自己写,我这里直接使用官网样例进行演示 样例代码下载: Cors 一.提供服务方,这里使用的是API 1.创建一个API项目.或者直接 ...
- MySQL5.6.17 绿色版 安装配置
安装篇: 下载完成之后,用解压工具解压到没有中文.空格的文件夹下,解压后的显示如图: 个人建议把解压后的文件夹重命名,如果有中文去掉中文,便于自己理解使用,如图: 打开重命名之后的文件夹,找到mysq ...
- EXT.NET Combox下拉Grid
<ext:ComboBox ID="cmbCategory" runat="server" TypeAhead="true" Forc ...
- 【转载】Windows系统电脑如何更换盘符号
在笔记本电脑或者办公电脑的使用过程中,有时候需要更换盘符号,例如在重装系统后,硬盘相应的分区盘符号可能会发生错乱变化,此时如果想更换回重装系统之前的盘符号,可以通过计算机管理里面的磁盘管理来实现更换盘 ...
- tp5 模型中配置数据库连接信息
namespace app\api\model; use think\Model; class BaseModel extends Model { protected $connection = [ ...
- Git拉取Gitlab上的代码时,报128的解决方法
今天拉取gitlab上的代码时出现错误,一直返回128 首先我们确定我们在存储库上有没有权限,然后我就去项目中的 Members上看是否有权限,然后发现也是有的. 然后克隆的时候发现输入一万遍密码都还 ...
- jperf windows
jperf windows版是款简单实用的网络性能测试的工具:它也是款图形界面的iperf程序,可以这进行使用JPerf程序的时候,快速的进行简化您的命令行参数,而且这进行测试结束之后,还是以图形化的 ...
- Django之form主键
Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...