Js中的闭包与高级函数

时间: 2019-10-16阅读: 303标签: 闭包

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设计模式,因为它是核心

站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/6452

关闭

JavaScript必须掌握的基础 --- 闭包

闭包是一个让初级JavaScript使用者既熟悉又陌生的一个概念。因为闭包在我们书写JavaScript代码时,随处可见,但是我们又不知道哪里用了闭包。

JavaScript之闭包

闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。下面写下我的学习笔记~

js闭包问题

使用闭包能够让局部变量模拟全局变量一样,但是它只能被特定函数使用。我们都知道:1.全局变量可能会造成命名冲突,使用闭包不用担心这个问题,因为它是私有化,加强了封装性,这样保护变量的安全

js循环中的异步&&循环中的闭包

for循环中let 和var的区别,setTimeout(func,time)函数运行机制,一个需求,一个数组array[1,2,3,4,5],循环打印,间隔1秒

Js中闭包的概念、原理、作用及应用

闭包:有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一个函数。从官方定义我们知道闭包是一个函数,只不过这个函数有[超能力],可以访问到另一个函数的作用域。为什么说这个叫做[超能力]呢?

我终于理解了闭包

闭包这个词一听就很高级,令人害怕。但实际上,闭包非常的强大,JS 的精髓之一就是闭包。实际上,我们经常在使用闭包,而不自知!

闭包实现:异步变同步

在不使用ES6的前提下如何将一个多个异步请求按顺序执行呢?要求使用JavaScript代码按顺序依次请求这5张图片,一次只能请求一张,可以结合 闭包+回调+递归 组合来解决

搞懂JS闭包

闭包(Closure)是JS比较难懂的一个东西,或者说别人说的难以理解, 本文将以简洁的语言+面试题来深入浅出地介绍一下。在将闭包之前,需要先讲一下作用域。JS中有全局作用域和局部作用域两种。

JavaScript 闭包的底层运行机制

我研究JavaScript闭包(closure)已经有一段时间了。我之前只是学会了如何使用它们,而没有透彻地了解它们具体是如何运作的。那么,究竟什么是闭包?Wikipedia给出的解释并没有太大的帮助。闭包是什么时候被创建的,什么时候被销毁的?具体的实现又是怎么样的?

Js中的闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数。来看下面的示例:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广