您的位置:首页 > Web前端 > JavaScript

JavaScript世界第一等公民 函数的几个级别

2012-07-25 14:48 239 查看
1.入门级
在<script></scirpt>标签里写两种函数:

f1();
f2();
function f1(){
alert("function1");
}
var f2 = function(){
alert("function2");
}

这两种书写方式是有一点区别的:f1是一种函数命名方式,在初始化window这个顶级对象时候,所有内在的这些函数都已经初始化过了,所以无论在哪个地方调用都是正确的,本质上是属于window的一个属性而存在的;而第二种实质上是一种函数匿名方式存在的,f2是window的一个变量,它指向一个函数表达式,表达式是解释执行的方式,只有运行到这个函数的地方才动态去执行,所以之前f2是没有指向该函数的,但是其值已经有了,是一个undefined,这是由于var这个关键词在初始化全局或局部变量时候,var变量是一次性全部初始化完成的,所以会先有一个值存在。当代码执行到 f2=function..的时候,f2才得到一个函数的指向。此时才能调用。

函数递归:
斐波那契函数:
function fib(n){
if(n==1 || n==2){
return 1;
}else{
return fib(n-2)+fib(n-1);
}
}

函数参数匿名:
函数内部有一个arguments参数可以获取到函数的参数对象,该对象是一个array,
function test1(){
para = arguments;
}

2.进阶 匿名函数和嵌套函数:
匿名函数由于没有名称调用,而基本上以一次性执行而存在。如:
(funciton(){}()); (function( ){ })();都是可以直接执行内部函数体的,而里面的环境为一个全新的变量环境不会污染全局环境,带来方便,js执行环境中有一个glob环境,一不小心就会使得各个引入包之间的函数重名,为此,使用匿名函数来处理这个变量重名问题,将所在的js代码全部封装到各自的匿名函数执行环境中,然后暴露出接口,使得全局能访问到内部函数就可以了:

var mylib=(function(global){
function log(){
alert('logs');
}
log1 = log;//1.该方式是利用匿名变量即全局变量,注册到window对象上,不推荐

global.log1 = log;//2.通过函数接口注册到window上,推荐



return { //3。该方式利用前面mylib的指向得到return的对象,该返回值是一个 、、、、、、、、、对象,对象拥有各种接口访问到匿名函数中的各个函数,相当于一个‘’‘’‘’‘’mylib命名空间下各种资源调用,推荐。


log:log
}
}(window));

高阶函数:当函数作为一个函数的参数使用时,就是高阶函数了

function plus(n){
return n+n;
}

function square(n){
return n*n;
}

function fn(n,callback){
return callback(n);
};

alert(fn(22,plus));
alert(fn(22,square));

闭包:
闭包(Closure)并不是一个新鲜的概念,很多函数式语言中都使用了闭包。在JavaScript中,当你在内嵌函数中使用外部函数作用域内的变量时,就是使用了闭包。用一个常用的类比来解释闭包和类(Class)的关系:类是带函数的数据,闭包是带数据的函数。
闭包中使用的变量有一个特性,就是它们不在父函数返回时释放,而是随着闭包生命周期的结束而结束。比如像上一节中generator的例子,gen1和gen2分别使用了相互独立的变量i(在gen1的i自增1的时候,gen2的i并不受影响,反之亦然),只要gen1或gen2这两个变量没有被JavaScript引擎垃圾回收,他们各自的变量i就不会被释放。在JavaScript编程中,不知不觉就会使用到闭包,闭包的这个特性在带来易用的同时,也容易带来类似内存泄露的问题。

var elem = document.getElementById('test');

elem.addEventListener('click', function() {

alert('You clicked ' + elem.tagName);

});

这段代码的作用是点击一个结点时显示它的标签名称,它把一个匿名函数注册为一个DOM结点的click事件处理函数,函数内引用了一个DOM对象elem,就形成了闭包。这就会产生一个循环引用,即:DOM->闭包->DOM->闭包...DOM对象在闭包释放之前不会被释放;而闭包作为DOM对象的事件处理函数存在,所以在DOM对象释放前闭包不会释放,即使DOM对象在DOM tree中删除,由于这个循环引用的存在,DOM对象和闭包都不会被释放。可以用下面的方法可以避免这种内存泄露:

上面这段代码中用this代替elem(在DOM事件处理函数中this指针指向DOM元素本身),让JS运行时不再认为这个函数中使用了父类的变量,因此不再形成闭包。
闭包还会带来很多类似的内存泄露问题,只有在写代码的时候着重注意一下闭包,尽量避免此类的问题产生

函数作为类的构造函数:
function Person(name){
this.name = name;
this.toString = function(){
return "hello"+this.name +"!";
}
}

var p = new Person("ddtou");
alert(p);

三。妖怪级别:
1 .Function类。在javascript运行时中有一个内建的类叫做Funciton,用funciton关键字声明一个函数其实就是创建一个Function类的实例的简写方法,因此,所有的函数都拥有Function类的方法如:call,apply,bind。。可以使用instanceof 检查该问题:

既然是对象,那么可以使用原始类生成一个函数对象了:
new Function ([arg1[, arg2[, ... argN]],] functionBody)
前面全是函数参数,最后一个是函数体,需要说明的是函数体使用字符串来传入,所以最外面用"",里面字符串使用'',参数不用加,就能区分是参数还是。。

var f1 = new Function('name',"return 'Hello'+name+'!!'; ");
f1("ddtou ");//Hello ddtou !!
到这儿,很多人可能会问为什么需要这样一个妖怪呢?“存在的即是合理的”,Function类有它独特的用途,你可以利用它动态地生成各种函数逻辑,或者代替eval函数的功能,而且能保持当前环境不会被污染*。

2.自更新函数:
函数在执行之后自己将自己更新成新的代码,这个是利用其绑定到的当前环境的指向更新自己的代码,同时利用的也是脚本的特点,直到运行到该地方才执行,动态性:
function selfUpdate(){
this.selfUpdate= function(){
alert("sencond run");
}
alert('first run');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: