函数是第一类对象 first-class object,可以作为带有属性和方法的值以及参数进行传递。
创建函数的语法
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函数。
即时函数中定义的变量将会用于它自身的局部变量,不必担心全局空间被临时的变量污染。
//定义模块module1
(function(){
//模块1中的所有代码
}());
本例子中即时函数的返回值是一个函数,它将分配给变量getResult,并且将简单地返回res值,该值被预计算并存储在即时函数的闭包中
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属性,其中包含了该函数期望的参数数量。
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);
调用invoking函数和应用applying函数可以得到相同的结果
//定义函数
var sayHi=function(who){
return "Hello"+ (who?", "+who:"")+"!";
};
//调用函数
sayHi(); //输出Hello
sayHi('world'); //输出Hello,World!
//应用函数
sayHi.apply(null,['hello']); //输出Hello, hello!
//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