JavaScript模式 读书笔记三

第四章函数

函数是第一类对象 first-class object,能够做为带有属性和方法的值以及参数进行传递。 node

建立函数的语法 浏览器

function foo(){}; //函数声明
var bar=function(){}; //函数表达式
var baz=function baz(){};//函数命名表达式



函数的提高


//反模式
//仅用于掩饰

//全局函数
function foo(){
  alert("global foo");
}
function bar(){
  alert("global bar");
}

function hoisMe(){
  console.log(typeof foo); //输出function
  console.log(typeof bar); //输出undefined
  foo();  //输出local foo
  bar();  //输出 TypeError: bar is not a function

  //函数声明
  //变量 foo以其实现者被提高
  function foo(){
    alert("local foo");
  }

  //函数表达式
  //仅变量 bar被提高
  //函数实现并未被提高
  var bar=function(){
     alert("local bar");
  }


}

hoisMe();


回调示例


//重构findNodes()以接受一个回调函数
var findNodes=function(callback){
  var i=100000,
  nodes=[],
  found;

  if(typeof callback!=="function"){
    callback=false;
  }

  while(i){
    i-=1;
    // 这里是复杂的逻辑...

    //如今进行回调函数
    if(callback){
      callback(found);
    }

    nodes.push(found);

  }
  return nodes;
}

//回调函数
var hide=function(node){
  node.style.display="none";

}
//找到制定节点,并在后续执行中将其隐藏起来
findNodes(hide);



//传递一个匿名回调函数
findNodes(function(node){
  node.style.display="block";
});


回调与做用域



//重构findNodes()以接受一个回调函数
var findNodes=function(callback,callback_obj){
  var i=100000,
  nodes=[],
  found;



  while(i){
    i-=1;
    // 这里是复杂的逻辑...

    //如今进行回调函数
    if(typeof callback==="string"){
      callback=callback_obj[callback];
    }
    if(typeof callback==="function"){
       callback.call(callback_obj,found);
    }

    nodes.push(found);

  }
  return nodes;
}

//回调函数
var myapp={};
myapp.color="green";
myapp.paint=function(node){
  node.style.color=this.color;
};
//找到制定节点,并在后续执行中将其隐藏起来
findNodes(myapp.paint,myapp);


返回函数


var setup=function(){
  alert(1);
  return function(){
    alert(2);
  }
}

//使用setup函数
var my=setup(); //alert1
my(); //alert 2



var setup=function(){
  var count=0;
  return function(){
     return (count+=1);
  }
}

//用法
var next=setup();
next(); //返回1
next(); //返回2
next(); //返回3


自定义函数

惰性函数定义 lazy function definition 缓存

var scareMe=function(){
  alert("Boo!");
  scareMe=function(){
    alert("Double boo!");
  }
};

//使用自定义函数
scareMe(); //输出Boo!
scareMe(); //输出Double boo!



var scareMe=function(){
  alert("Boo!");
  scareMe=function(){
    alert("Double boo!");
  }
};

//1 .添加一个新的属性
scareMe.property="properly";

//2. 复制给另外一个不一样名称的变量
var prank=scareMe;

//3. 做为一个方法使用
var spooky={
  boo:scareMe
};

//calling with a new name
prank(); //输出 Boo!
prank(); //输出 Boo!
 console.log(prank.property); //输出properly

 //做为一个方法来调用
 spooky.boo(); //输出Boo!
 spooky.boo(); //输出Boo!
 console.log(spooky.boo.property); // 输出  properly

 //使用自定义函数
 scareMe(); //输出 Double boo!
 scareMe(); //输出 Double boo!
console.log(scareMe.property); //undefined


即时函数的返回值

即时函数也叫自调用self-invoking 或者自执行self-executing函数。 闭包

即时函数中定义的变量将会用于它自身的局部变量,没必要担忧全局空间被临时的变量污染。 app

//定义模块module1
(function(){
  //模块1中的全部代码
}());



本例子中即时函数的返回值是一个函数,它将分配给变量getResult,而且将简单地返回res值,该值被预计算并存储在即时函数的闭包中 ide

var getResult=(function(){
  var res=2+2;
  return function(){
    return res;
  }
}());


定义对象属性时也可使用即时函数 函数

var o={
  message:(function(){
    var who="me",
    what="call";
    return what + " "+who;
  }()),
  getMsg:function(){
    return this.message;
  }
};

//用法
console.log(o.getMsg());  //输出call me
console.log(o.message);   //输出call me


即时对象初始化

immediate object initalization 测试

({
  //在这里能够定义设定值
  //又名配置常数
  maxwidth:600,
  maxheight:400,

  //还能够定义一些实用的方法
  gimmeMax:function(){
    return this.maxwidth+ "X" +this.maxheight;
  },

  //初始化
  init:function(){
    console.log(this.gimmeMax());
    //更多初始化任务。。。
  }

}).init();


初始化时分支

init-time branching 也称为加载时分支 load-time branching 是一种优化模式 优化

//接口
var utils={
  addListener:null,
  removeListener:null
};

//实现 
if(typeof window.addEventListener==="function"){
  utils.addListener=function(el,type,fn){
    el.addEventListener(type,fn,false);
  };
  utils.removeListener=function(el,type,fn){
    el.removeEventListener(type,fn,false);
  }
}else if(typeof document.attachEvent==="function"){  //判断为IE浏览器
  utils.addListener=function(el,type,fn){
    el.attachEvent('on'+type,fn);
  };
  utils.removeListener=function(el,type,fn){
    el.detachEvent("on"+type,fn);
  };

}else{  //更早版本的浏览器 
   utils.addListener=function(el,type,fn){
     el['on'+type]=fn;
   };
   utils.removeListener=function(el,type,fn){
     el['on'+type]=null;
   }
}



函数属性——备忘模式

对于每一个函数,它都会自动得到一个length属性,其中包含了该函数指望的参数数量。 this

function func(a,b,c,d){}
console.log(func.length);


能够在任什么时候候将自定义属性添加到你的函数中。自定义属性的其中一个用例是缓存函数结果(即返回值),所以下次调用该函数时就不会重作潜在的繁重计算。 缓存函数结果也被称为备忘memoization 


var myFunc=function(param){
  if(!myFunc.cache[param]){
    var result={};
    //。。。开销很大的操做。。。
    myFunc.cache[param]=result;
  }
  return myFunc.cache[param];
}
//缓存存储
myFunc.cache={};


配置对象

当须要传递大量参数时,一个更好的办法是仅使用一个参数对象来代替全部参数,该参数对象称为conf,也就是配置的意思。


var conf={
  username:"lilu",
  first:"Yi",
  last:"Liu"
}

function addPerson(person){
  return person.username +" " +person.first+" "+person.last;
}

addPerson(conf);


Curry


函数应用

调用invoking函数和应用applying函数能够获得相同的结果

//定义函数
var sayHi=function(who){
  return "Hello"+ (who?", "+who:"")+"!";
};

//调用函数
sayHi(); //输出Hello
sayHi('world'); //输出Hello,World!

//应用函数
sayHi.apply(null,['hello']); //输出Hello, hello!



Curry化


//curry化的add()函数
//接受部分参数的列表
function add(x,y){
  var oldx=x,oldy=y;
  if(typeof oldy==="undefined"){ //部分
    return function(newy){
      return oldx+newy;
    }
  }
  //彻底应用
  return x+y;
}
//测试
typeof add(5); //输出function
add(3)(4); //7
//建立病存储一个新函数
var add2000=add(2000);
add2000(10);//输出2010

一个通用curry化函数


function schonfinkelize(fn){
  var slice=Array.prototype.slice,
    stored_args=slice.call(arguments,1);
  return function(){
    var new_args=slice.call(arguments),
        args=stored_args.concat(new_args);
    return fn.apply(null,args);
  }
}

//普通函数
function add(x,y){
  return x+y;
}

//将一个函数curry化以得到一个新的函数
var newadd=schonfinkelize(add,5);
newadd(4); //输出9

/另外一种选择——直接调用新函数
schonfinkelize(add,6)(7);


更多用法


//普通函数
function add(a,b,c,d,e){
  return a+b+c+d+e;
}

//可运行于任意数量的参数
schonfinkelize(add,1,2,3)(5,5); //16

//两步curry化
var addOne=schonfinkelize(add,1);
addOne(10,10,10,10); //输出41

var addSix=schonfinkelize(addOne,2,3);
addSix(5,5); //输出16
相关文章
相关标签/搜索