一.函数基本理论

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

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

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

创建一个执行环境execution context ,该对象有一个特殊的属性叫[scope chain] 作用域链,属性的值是一个类数组对象,如上图所示,第一个包含了,arguments,val1和val2的活动对象,第二个是包含了compare和result,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);//
cost(200);//
cost();//

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。

四.闭包

闭包是有权访问另外一个函数作用域中的变量的函数。《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的原因是每一个内部匿名函数包含的活动对象是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值,这样就可以达到预期的效果。

《javascript设计模式与开发实践》读书笔记之函数,this,闭包的更多相关文章

  1. JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)

    说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...

  2. JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

    上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...

  3. Javascript设计模式与开发实践读书笔记(1-3章)

    第一章 面向对象的Javascript 1.1 多态在面向对象设计中的应用   多态最根本好处在于,你不必询问对象“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用行为就好,剩下的一切 ...

  4. javascript设计模式与开发实践阅读笔记(4)——单例模式

    定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...

  5. javascript设计模式与开发实践阅读笔记(8)——观察者模式

    发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...

  6. javascript设计模式与开发实践阅读笔记(7)——迭代器模式

    迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  7. javascript设计模式与开发实践阅读笔记(6)——代理模式

    代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...

  8. 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式

    第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...

  9. 《JavaScript设计模式与开发实践》笔记第一章

    第一章 面向对象的JavaScript 动态类型语言和鸭子类型 编程语言按照数据类型大体可以分为两类:静态类型语言.动态类型语言. 静态类型语言:在编译时便已确定变量的类型. 优点: 在编译时就能发现 ...

  10. javascript设计模式与开发实践阅读笔记(5)——策略模式

    策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率 ...

随机推荐

  1. 一天搞定HTML----常用标签01

    1.常用标签说明 2.其他类标签演示 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8& ...

  2. CoreML试水--图片识别

    今年的WWDC上,关于人工智能方面Apple开放了CoreML工具包. 今天就趁着时间还早果断的尝试了一下到底有多容易. import UIKit import CoreML import Visio ...

  3. servlet与jsp

    Servlet生命周期 一.初始化阶段   当WEB客户第一次请求访问某个Servlet的时候,WEB容器将创建这个Servlet的实例.调用init()方法进行Servlet的初始化 一.响应客户请 ...

  4. Xamarin开发笔记—百度在线语音合成

    语音合成:也被称为文本转换技术(TTS),它是将计算机自己产生的.或外部输入的文字信息转变为可以听得懂的.流利的口语输出的技术. 技术选型:语音合成初步选择有两个,一是讯飞.二是百度. 因为使用的是X ...

  5. git 知识点汇总

    git commit git commit 命令执行后, git 主要执行了三个操作: 为每一个文件生成一个快照 每一个文件其实是真的数据, 所以 git 会把整个文件内容转成二进制, 然后经过压缩直 ...

  6. JDBC 数据库连接操作——实习第三天

    今天开始了比较重量级的学习了,之前都是对于Java基础的学习和回顾.继续上篇的话题,<谁动了我的奶酪>,奉献一句我觉得比较有哲理的话:"学会自嘲了,而当人们学会自嘲,能够嘲笑自己 ...

  7. C# 微信 企业号通知消息

    每当有个Create 事件,要通知相关的人员. 1.扫码登录企业微信,到企业应用. 2.获取微信配置信息. Secret和AgentId. 3.管理通讯录,配置接收消息的人群.可以按照部门,标签.获取 ...

  8. 记一次linux主机名莫名其妙变成了bogon

    起因:公司网络接口做了接口认证,虚拟机桥接至物理网卡无法完成认证进行网络访问,无奈之下只能讲虚拟机网络模式更改为NAT模式,更改完成之后进行ssh登录,发现主机名发生了变化. 更改NAT模式之前 [r ...

  9. RecycleView和CardView

    一.RecycleView <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" ...

  10. oracle创建数据库表空间 用户 授权 导入 导出数据库

    windows下可以使用向导一步一步创建数据库,注意编码. windows连接到某一个数据库实例(不然会默认到一个实例下面):set ORACLE_SID=TEST --登录开始创建表空间及可以操作的 ...