一.函数基本理论

function compare(val1,val2){
return val1 - val2;
}
var result = compare(5,10);

1,函数的定义没什么意义,之后创建一个字符串,就是函数代码

2,函数执行(被调用)的时候发生的事情:(以上面的代码为例)

创建一个执行环境execution context ,该对象有一个特殊的属性叫[scope chain] 作用域链,属性的值是一个类数组对象,如上图所示,第一个包含了arguments,val1和val2的活动对象,第二个是包含了compare和result,的活动对象。注意,这里的活动对象都没有加进去this关键字,这是因为,当函数内部通过作用域链寻找一个变量时候,与this关键字没有任何关系,所以不会从作用域链上面解析。

理解函数的基本原理对于函数的理解函数闭包的概念很有帮助。

二.高阶函数

1.函数作为参数传递

最经典的例子就是毁掉函数

var fs  = require('fs');
fs.readFile('test.txt',function(data,err){
console.log(data);
});

2.函数作为返回值

作为返回值时候,要注意此时的this指向。

3.函数柯里化

函数柯里化指首先接受一些参数,接受到的参数后不立即执行,而是返回一个新函数,刚才传入的参数在函数形成的闭包中被保存起来,待到真正求值的时候刚才保存的参数才会真正的求值。

var cost = (function(){
var args = [];
return function(){
if(arguments.length===0){
var money =0;
for(var i-0;i<args.length;i++){
money+=args[i];
}
return money;
}else{
[].push.apply(args,arguments);
} }
})();
cost(100);//100
cost(200);//200
cost();//300

4.函数节流

函数节流的思想就是让一些频繁执行的函数减少执行频率;比如因为浏览器窗口变化引起resize事件的频繁执行,mouseover,上传进度等等。

var throttle = function(fn,interval){
var _self = fn,timer,firstTime;
return function(){
var args = arguments,_me = this;
if(firstTime){
_self.apply(_me,args);
return firstTime = false;
}
if(timer){
return false;
}
timer = setTimeout(function(){
clearTimeout(timer);
timer = null;
_self.apply(_me,args);
},interval||500);
}
};
window.onresize = throttle(function(){
console.log(1)},500);

代码的解决办法是利用定时器延迟执行,如果定时器在规定时间后还没执行完,那么,下一次执行的时候就不会执行,直接返回;

5.分时函数

分时函数应用的场景比如,你的QQ好友有上千个,每一个好友是一个dom,这是加载的时候浏览器可能吃不消,就要用到setInterval函数来延迟加载。

//ary需要加载的数据,fn加载逻辑,count每一批加载的个数
var timeChunk = function(ary,fn,count){
var obj, t;
var len = ary.length;
var start = function(){
for(var i=0;i<Math.min(count||1,ary.length);i++){
var obj = ary.shift();
fn(obj);
}
};
return function(){
t = setInterval(function(){
if(ary.length===0){
return clearInterval(t);
}
start();
},200);
}
}
var ary = [];
for(var i=0;i<1000;i++){
ary.push(i);
}
var renderFirendList = timeChunk(ary,function(n){
var div = document.createElement('div');
div.innerHTML = n;
document.body.appendChild(div);
},8);
renderFirendList();

6.惰性加载函数

惰性 加载函数也很常见,比如浏览器嗅探中的时间绑定函数

var addEvent = function(elem,type,handler){
if(window.addEventListener){
return elem.addEventListener(type,handler,false);
}
if(window.addEvent){
return elem.addEvent('on'+type,handler);
}
}

以上代码在非IE浏览器下每次都不会走第二个分支,并且每次添加一个事件就会执行一次判断,虽然这不会增加性能开销,但是可以利用惰性加载来解决

var addEvent = function(elem, type, handler){
if(window.addEventListener){
addEvent = function(elem, type, handler){
elem.addEventListener(type, handler, false)
}
}else if(window.addEvent){
addEvent = function(elem, type, handler){
elem.addEvent('on'+type, handler);
}
}
addEvent(elem,type,handler);
}

三.this

this的判断只要记住一点,就是在执行的时候动态绑定的,而不是函数声明时候绑定,以下是优先级

if(hava new){

  this 就是new返回的这个对象

}else if(hava call,apply 绑定){

  apply,call绑定的那个对象就是this

}else if(有对象调用){

  this就是这个调用的对象

}else{

  默认绑定到window //这种情况一般是闭包

}

window.name = 'globalname';
var obj = {};
obj.name = 'lucy';
obj.show = (function(){
console.log(this.name);
return function(){ console.log(this.name)}
})() obj.show();
VM928:6 globalname
VM928:7 lucy

对于上面的代码,obj.show定义为一个对象的方法,但是该方法立即执行,并且是在全局的作用域下执行的,所以输出为globalname,当obj.show执行完之后返回了一个函数赋值给obj.show,说以obj.show此时才真正是对象的方法,所以第二个返回lucy,这个例子完美的证明了运行时动态绑定this。

另外,有一点就是对于事件绑定函数,this指向那个绑定的元素,settimeout中的延迟函数中的this指向window。

this在递归调用中是个坑!!!!!!!!!!!!!!注意注意

四.闭包

闭包是有权访问另外一个函数作用域中的变量的函数。《JavaScript高级程序设计第三版》。

典型的例子是一个内部函数访问外部函数的变量,即使这个内部函数返回了或者是被调用了,仍然可以访问外部变量,如下

function com(propertyName){
return function(obj1,obj2){
var value1 = obj1[propertyName];
var value2 = obj2[propertyName];
return value1 - value2;
}
}
var obj1 ={'name':1};
var obj2 ={'name':2};
var compare = com('name');
console.log(compare(obj1,obj2));

上面例子中,匿名函数访问了外部函数的局部变量propertyName,并且当它返回了,而且是在其他地方被调用了仍然可以访问。比如com函数返回了一个匿名函数,并且在其他地方被调用了这个函数,但是仍然可以访问propertyName变量对象,但是有一点就是,这里的propertyName是一个变量对象(活动对象)而不是变量本身,如果是在for等循环语句中就会出现错误。如下面的例子:

function foo(){

    var result = [];
for(var i = 0; i < 5; i++){
result[i] = function(){
return i;
}
}
return result;
}
var s = foo(); console.log(s[1]());//5

上面代码输出结果是5的原因是每一个内部匿名函数包含的活动对象是i这个变量对象,所以最终foo()执行返回的每一个result[i](这里的i没有变成5是因为它没在匿名函数内),都是外部foo活动对象,所以最终结果就是5.避免这种结果的方法就是在外面继续增加一层作用域,使每一个result[i]函数都持有自己i的活动对象。

function bar(){
var result = [];
for(var j = 0; j < 5; j++){
result[j] = (function(num){
return function(){
return num;
}
})(j)
}
return result;
}

这2段代码的函数活动对象图如下:

第一个代码所有的result都引用函数foo中活动对象i所以当foo执行完返回后,i变量的值是5所以出现如上所示。

第二段代码中,由于参数是按值复制传递的,所以j会一次赋值给num,最内层的匿名函数保存了3个活动对象,分别是立即执行函数,bar,和window,并且立即执行函数也是有5个,并且保存了5个num值,这样就可以达到预期的效果。

闭包在实际开发中的一些应用:

1.setTimeout函数中的应用

for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0)
}
//
//
//

这个运行结果的解释就是i变量只有一个,但是有3个匿名函数都引用了。

2.事件绑定与闭包

for( var i=0; i<5; i++ ) {
document.getElementById("p"+i).onclick=function() {
alert(i); //访问了父函数的变量i, 闭包,结果都弹出5
};
};

如果用户点击每一个按钮,它弹出的都是5,因为当用户点击的时候这里的i值都变成了5,有点类似于运行时动态绑定的概念,也类似于C语言中的指针,因为i变量是一个虽然存在于外部window对象上,但是内部函数引用了这个变量,所以它无论函数返回都常驻内存,alert的时候就访问了这个内存中的区域。

参考文献:

1.《JavaScript高级程序设计》

2.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Method_binding

JavaScript中的函数:闭包,this,高阶函数的更多相关文章

  1. javascript设计模式学习之三—闭包和高阶函数

    一.闭包 闭包某种程度上就是函数的内部函数,可以引用外部函数的局部变量.当外部函数退出后,如果内部函数依旧能被访问到,那么内部函数所引用的外部函数的局部变量就也没有消失,该局部变量的生存周期就被延续. ...

  2. JavaScript之闭包与高阶函数(一)

    JavaScript虽是一门面向对象的编程语言,但同时也有许多函数式编程的特性,如Lambda表达式,闭包,高阶函数等. 函数式编程是种编程范式,它将电脑运算视为函数的计算.函数编程语言最重要的基础是 ...

  3. Javascript 闭包与高阶函数 ( 一 )

    上个月,淡丶无欲 让我写一期关于 闭包 的随笔,其实惭愧,我对闭包也是略知一二 ,不能给出一个很好的解释,担心自己讲不出个所以然来. 所以带着学习的目的来写一写,如有错误,忘不吝赐教 . 为什么要有闭 ...

  4. Javascript 闭包与高阶函数 ( 二 )

    在上一篇 Javascript 闭包与高阶函数 ( 一 )中介绍了两个闭包的作用. 两位大佬留言指点,下来我会再研究闭包的实现原理和Javascript 函数式编程 . 今天接到头条 HR 的邮件,真 ...

  5. JavaScript ES6函数式编程(一):闭包与高阶函数

    函数式编程的历史 函数的第一原则是要小,第二原则则是要更小 -- ROBERT C. MARTIN 解释一下上面那句话,就是我们常说的一个函数只做一件事,比如:将字符串首字母和尾字母都改成大写,我们此 ...

  6. [Node.js] 闭包和高阶函数

    原文地址:http://www.moye.me/2014/12/29/closure_higher-order-function/ 引子 最近发现一个问题:一部分写JS的人,其实对于函数式编程的概念并 ...

  7. 理解运用JS的闭包、高阶函数、柯里化

    JS的闭包,是一个谈论得比较多的话题了,不过细细想来,有些人还是理不清闭包的概念定义以及相关的特性. 这里就整理一些,做个总结. 一.闭包 1. 闭包的概念 闭包与执行上下文.环境.作用域息息相关 执 ...

  8. JS中几种常见的高阶函数

    高阶函数:英文叫Higher-order function.JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数 ...

  9. Python 进程线程协程 GIL 闭包 与高阶函数(五)

    Python 进程线程协程 GIL 闭包 与高阶函数(五) 1 GIL线程全局锁 ​ 线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的 ...

  10. JS的闭包、高阶函数、柯里化

    本文原链接:https://cloud.tencent.com/developer/article/1326958 https://cloud.tencent.com/developer/articl ...

随机推荐

  1. div的替代品

    人们在标签使用中最常见到的错误之一就是随意将HTML5的<section>等价于<div>--具体地说,就是直接用作替代品(用于样式).在XHTML或者HTML4中,我们常看到 ...

  2. 关于combotree的用法总结

    后台: 实体树 public class TreeNode{ private String id; private String text; private String level; private ...

  3. 怎么一次性获取form所有的值?rerialize() 、 serializeArray()方法的使用

    from直接提交当然方便,但是有时候需要对数据进行处理再用ajax提交,挨个去获取值未免太麻烦,讲两个一次性获取所有值的方法. 方法1 $("form").serialize(); ...

  4. MyBatis7:MyBatis插件及示例----打印每条SQL语句及其执行时间

    Plugins 摘一段来自MyBatis官方文档的文字. MyBatis允许你在某一点拦截已映射语句执行的调用.默认情况下,MyBatis允许使用插件来拦截方法调用 Executor(update.q ...

  5. struts2+hibernate+spring配置版框架搭建以及简单测试(方便脑补)

    为了之后学习的日子里加深对框架的理解和使用,这里将搭建步奏简单写一下,目的主要是方便以后自己回来脑补: 1:File--->New--->Other--->Maven--->M ...

  6. javaCV开发详解之技术杂烩:javaCV能帮我们做什么?能实现什么功能?ffmpeg和openCV能实现功能,javaCV如何做到更快、更简单的实现相应的功能?等等一堆实用话题

    前言: 该篇文章旨在帮助刚接触javaCV的盆友系统的认识音视频.javaCV.图像处理相关的体系知识和一些实用的知识. 序: javaCV早期因为内置了openCV库,所以常用来做图像识别应用,现在 ...

  7. Spring学习(9)--- @Autowired注解(二)

    可以使用@Autowired注解那些众所周知的解析依赖性接口,比如:BeanFactory,ApplicationContext,Environment,ResourceLoader,Applicat ...

  8. vue-router如何根据不同的用户给不同的权限

    闲聊: 小颖去年在上家公司用的vue1.0之前在做路由这块用的router.map,但是现在vue2.0里已经不能用了,所以之前解决权限问题的例子,小颖也参考不了呜呜 之前看一个美女写的:elemem ...

  9. 带着问题写React Native原生控件--Android视频直播控件

    最近在做的采用React Native项目有一个需求,视频直播与直播流播放同一个布局中,带着问题去思考如何实现,能更容易找到问题关键点,下面分析这个控件解决方法: 现在条件:视频播放控件(开源的ijk ...

  10. 在微服务系统开发部署中使用Azure RBAC自定义角色

    Azure的官方文档介绍了如何创建用于Azure基于角色的访问控制的自定义角色(RBAC Role). 我们也可以根据同样的原理把RBAC细粒度资源管理运用于微服务产品的开发部署中.(https:// ...