《javascript设计模式与开发实践》读书笔记之函数,this,闭包
一.函数基本理论
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,闭包的更多相关文章
- JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)
说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...
- JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)
上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值, ...
- Javascript设计模式与开发实践读书笔记(1-3章)
第一章 面向对象的Javascript 1.1 多态在面向对象设计中的应用 多态最根本好处在于,你不必询问对象“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用行为就好,剩下的一切 ...
- javascript设计模式与开发实践阅读笔记(4)——单例模式
定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录 ...
- javascript设计模式与开发实践阅读笔记(8)——观察者模式
发布-订阅模式,也叫观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 在JavaScript开发中,我们一般用事件模型来替代传统的观察者模式. ...
- javascript设计模式与开发实践阅读笔记(7)——迭代器模式
迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...
- javascript设计模式与开发实践阅读笔记(6)——代理模式
代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对 ...
- 《JavaScript设计模式与开发实践》笔记第八章 发布-订阅模式
第八章 发布-订阅模式 发布-订阅模式描述 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于 ...
- 《JavaScript设计模式与开发实践》笔记第一章
第一章 面向对象的JavaScript 动态类型语言和鸭子类型 编程语言按照数据类型大体可以分为两类:静态类型语言.动态类型语言. 静态类型语言:在编译时便已确定变量的类型. 优点: 在编译时就能发现 ...
- javascript设计模式与开发实践阅读笔记(5)——策略模式
策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率 ...
随机推荐
- laravel 服务容器实现原理
前言 通过实现laravel 框架功能,以便深入理解laravel框架的先进思想. 什么是服务容器 服务容器是用来管理类依赖与运行依赖注入的工具.Laravel框架中就是使用服务容器来实现 ** 控制 ...
- 平时常用的一些java方法,请留意
平时常用的一些java方法,请留意. package com.util; import java.io.BufferedInputStream; import java.io.BufferedWrit ...
- Akka(6): become/unbecome:运算行为切换
通过一段时间的学习了解,加深了一些对Akka的认识,特别是对于Akka在实际编程中的用途方面.我的想法,或者我希望利用Akka来达到的目的是这样的:作为传统方式编程的老兵,我们已经习惯了直线流程方式一 ...
- Azure 基础:Table storage
Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob.Queue.File 和 Table.其中的 Table 就是本文的主角 Azure Tabl ...
- 第45篇 js操作打开本地程序
原文地址:http://blog.laofu.online/2017/06/10/how-js-controlApp/ 背景 假设有这样一个产品,一个web和一个winform客户端,在客户在web的 ...
- vue-schart : vue.js 的图表组件
介绍 vue-schart 是使用vue.js封装了sChart.js图表库的一个小组件.支持vue.js 1.x & 2.x 仓库地址:https://github.com/lin-xin/ ...
- 如何用phpcms将静态网页生成动态网页?
在前两篇随笔中已经简单介绍了phpcms,那么现在让我们来看一下如何用phpcms将静态网页生成动态网页? 1.在templates文件夹下新建模板文件夹ceshi(名字可以自己随笔起) 2.在ces ...
- 电脑上的windows键突然失灵了,肿么办
windows经常会用到,或许平时感觉不出异常来,偶尔用一次的时候,去发现失灵了,肿么办? 如果只是单纯的弹出开始菜单来,可以按Ctrl+Esc,功能是一样的. 这种情况其实是windows被禁用了, ...
- django ngRoute ui-router 开发环境下禁用缓存
问题描述: Python manage.py runserver ,禁用缓存,及时修改反馈到浏览器 解决办法: 使用dummy cache: Dummy caching (for developmen ...
- 一篇文章带你快速入门createjs
开始用createjs这个框架的时候,发现网上的相关教程还是挺少的,所以写一篇文章,方便日后查看. createjs简介 官网:http://www.createjs.cc/ createjs中包 ...