`

JavaScript函数

阅读更多
在JavaScript中,函数本身与其他任何的内置对象在低位上是没有任何区别的,也就是说,函数本身也是对象。

总的来说,函数在JavaScript中可以:

Ø  被赋值给一个变量

Ø  被赋值为对象的属性

Ø  作为参数被传入别的函数

Ø  作为函数的结果被返回

Ø  用字面量来创建

创建JavaScript函数的一种不长用的方式(几乎没有人用)是通过new操作符来作用于Function“构造器”:
var funcName = new Function( [argname1, [... argnameN,]] body ); 
var add = new Function("x", "y", "return(x+y)");  
print(add(2, 4));  //返回6
但是,谁会用如此难用的方式来创建一个函数呢?如果函数体比较复杂,那拼接这个String要花费很大的力气,所以JavaScript提供了一种语法糖,即通过字面量来创建函数:
function add(x, y){   
    return x + y;   
} 
或者
var add = function(x, y){   
    return x + y;   
}  

事实上,这样的语法糖更容易使传统领域的程序员产生误解,function关键字会调用Function来new一个对象,并将参数表和函数体准确的传递给Function的构造器。

通常来说,在全局作用域内声明一个对象,只不过是对一个属性赋值而已,比如上例中的add函数,事实上只是为全局对象添加了一个属性,属性名为add,而属性的值是一个对象,即function(x, y){return x+y;}
为了说明函数跟其他的对象一样,都是作为一个独立的对象而存在于JavaScript的运行系统,我们不妨看这样一个例子:

function p(){   
    print("invoke p by ()");   
}   
    
p.id = "func";   
p.type = "function";   
    
print(p);   
print(p.id+":"+p.type);   
print(p());  

运行结果:

function (){
print("invoke p by ()");
}
func:function
invoke p by ()

函数的参数
在JavaScript中,函数的参数是比较有意思的,比如,你可以将任意多的参数传递给一个函数,即使这个函数声明时并未制定形式参数,比如:
function adPrint(str, len, option){   
    var s = str || "default";   
    var l = len || s.length;   
    var o = option || "i";   [color=red]//????????????[/color]      
    s = s.substring(0, l);   
    switch(o){   
       case "u":   
           s = s.toUpperCase();   
           break;   
       case "l":   
           s = s.toLowerCase();   
           break;   
       default:   
           break;   
    }   
      
    print(s);   
}   
    
adPrint("Hello, world");   
adPrint("Hello, world", 5);   
adPrint("Hello, world", 5, "l");//lower case   
adPrint("Hello, world", 5, "u");//upper case  


函数adPrint在声明时接受三个形式参数:要打印的串,要打印的长度,是否转换为大小写的标记。但是在调用的时候,我们可以按顺序传递给adPrint一个参数,两个参数,或者三个参数(甚至可以传递给它多于3个,没有关系),运行结果如下:
Hello, world
Hello
hello
HELLO

事实上,JavaScript在处理函数的参数时,与其他编译型的语言不一样,解释器传递给函数的是一个类似于数组的内部值,叫arguments,这个在函数对象生成的时候就被初始化了。比如我们传递给adPrint一个参数的情况下,其他两个参数分别为undefined.这样,我们可以才adPrint函数内部处理那些undefined参数,从而可以向外部公开:我们可以处理任意参数。



我们通过另一个例子来讨论这个神奇的arguments:
function sum(){   
    var result = 0;   
    for(var i = 0, len = arguments.length; i < len; i++){   
       var current = arguments[i];   
       if(isNaN(current)){   //判断是否是非数值
           throw new Error("not a number exception");   
       }else{   
           result += current;   
       }   
    }   
      
    return result;   
}   
    
print(sum(10, 20, 30, 40, 50));   
print(sum(4, 8, 15, 16, 23, 42));//《迷失》上那串神奇的数字   
print(sum("new")); 


函数sum没有显式的形参,而我们又可以动态的传递给其任意多的参数,那么,如何在sum函数中如何引用这些参数呢?这里就需要用到arguments这个伪数组了,运行结果如下:
150
108
Error: not a number exception

函数作用域
作用域的概念在几乎所有的主流语言中都有体现,在JavaScript中,则有其特殊性:JavaScript中的变量作用域为函数体内有效,而无块作用域,我们在Java语言中,可以这样定义for循环块中的下标变量:
public void method(){   
    for(int i = 0; i < obj1.length; i++){   
       //do something here;   
    }   
    //此时的i为未定义   
    for(int i = 0; i < obj2.length; i++){   
       //do something else;   
    }     
}


function func(){   
    for(var i = 0; i < array.length; i++){   
       //do something here.   
    }   
    [color=red]//此时i仍然有值[/color],及I == array.length   
    print(i);//i == array.length;   
} 


JavaScript的函数是在局部作用域内运行的,在局部作用域内运行的函数体可以访问其外层的(可能是全局作用域)的变量和函数。JavaScript的作用域为词法作用域,所谓词法作用域是说,其作用域为在定义时(词法分析时)就确定下来的,而并非在执行时确定,如下例:
var str = "global";   
function scopeTest(){   
    print(str);   
    var str = "local";   
    print(str);   
}   
    
scopeTest();  


正确的运行结果:?????
undefined
local


因为在函数scopeTest的定义中,预先访问了未声明的变量str,然后才对str变量进行初始化,所以第一个print(str)会返回undifined错误。那为什么函数这个时候不去访问外部的str变量呢?这是因为,在词法分析结束后,构造作用域链的时候,会将函数内定义的var变量放入该链,因此str在整个函数scopeTest内都是可见的(从函数体的第一行到最后一行),由于str变量本身是未定义的,程序顺序执行,到第一行就会返回未定义,第二行为str赋值,所以第三行的print(str)将返回”local”。



函数的上下文:
在JavaScript中,函数也是一种对象,并非其他任何对象的一部分,理解这一点尤为重要,特别是对理解函数式的JavaScript非常有用,在函数式编程语言中,函数被认为是一等的。

函数的上下文是可以变化的,因此,函数内的this也是可以变化的,函数可以作为一个对象的方法,也可以同时作为另一个对象的方法,总之,函数本身是独立的。可以通过Function对象上的call或者apply函数来修改函数的上下文:

call和apply通常用来修改函数的上下文,函数中的this指针将被替换为call或者apply的第一个参数,我们不妨来看看例子:
//定义一个人,名字为jack   
var jack = {   
    name : "jack",   
    age : 26   
}   
    
//定义另一个人,名字为abruzzi   
var abruzzi = {   
    name : "abruzzi",   
    age : 26   
}   
    
//定义一个全局的函数对象   
function printName(){   
    return this.name;   
}   
    
//设置printName的上下文为jack, 此时的this为jack   
print(printName.call(jack));   
//设置printName的上下文为abruzzi,此时的this为abruzzi   
print(printName.call(abruzzi));   
    
print(printName.apply(jack));   
print(printName.apply(abruzzi));


只有一个参数的时候call和apply的使用方式是一样的,如果有多个参数:
setName.apply(jack, ["Jack Sept."]);   
print(printName.apply(jack));   
    
setName.call(abruzzi, "John Abruzzi");   
print(printName.call(abruzzi)); 


运行结果:
Jack Sept.   
John Abruzzi 

apply的第二个参数为一个函数需要的参数组成的一个数组,而call则需要跟若干个参数,参数之间以逗号(,)隔开即可。

赋值给变量
//声明一个函数,接受两个参数,返回其和   
function add(x, y){   
    return x + y;   
}   
    
var a = 0;   
a = add;//将函数赋值给一个变量   [color=red]函数是对象,引用同一个对象[/color]var b = a(2, 3);//调用这个新的函数a   
print(b);


这段代码会打印”5”,因为赋值之后,变量a引用函数add,也就是说,a的值是一个函数对象(一个可执行代码块),因此可以使用a(2, 3)这样的语句来进行求和操作。

作为参数传递
//高级打印函数的第二个版本   
function adPrint2(str, handler){   
    print(handler(str));   
}   
    
//将字符串转换为大写形式,并返回   
function up(str){   
    return str.toUpperCase();   
}   
    
//将字符串转换为小写形式,并返回   
function low(str){   
    return str.toLowerCase();   
}   
    
adPrint2("Hello, world", up);   
adPrint2("Hello, world", low); 


执行结果:
HELLO, WORLD
hello, world


应该注意到,函数adPrint2的第二个参数,事实上是一个函数,将这个处理函数作为参数传入,在adPrint2的内部,仍然可以调用这个函数,这个特点在很多地方都是有用的,特别是,当我们想要处理一些对象,但是又不确定以何种形式来处理,则完全可以将“处理方式”作为一个抽象的粒度来进行包装(即函数)。

作为函数的返回值:
function currying(){   
    return function(){   
       print("curring");   
    }   
} 


函数currying返回一个匿名函数,这个匿名函数会打印”curring”,简单的调用currying()会得到下面的结果:
function (){   
    print("curring");   
}  


如果要调用currying返回的这个匿名函数,需要这样:
currying()();
第一个括号操作,表示调用currying本身,此时返回值为函数,第二个括号操作符调用这个返回值,则会得到这样的结果:
curring











分享到:
评论

相关推荐

    javascript函数式编程

    JavaScript函数式编程是利用JavaScript语言编写函数式风格代码的一种编程范式。函数式编程强调使用纯函数、避免副作用、函数的不可变性以及利用高阶函数等概念。通过阅读《JavaScript函数式编程指南》,读者可以了解...

    JavaScript函数式编程.pdf

    不过,由于【标题】中提供了文档的名称——"JavaScript函数式编程.pdf",我可以根据这个名称扩展出关于JavaScript函数式编程的知识点。 JavaScript函数式编程的知识点非常丰富,涉及很多方面的内容,下面将详细介绍...

    C#与JAVASCRIPT函数的相互调用 C#调用JAVASCRIPT函数的调用 JAVASCRIPT调用C#函数的调用

    C#与JAVASCRIPT函数的相互调用 C#调用JAVASCRIPT函数的调用 JAVASCRIPT调用C#函数的调用

    javascript函数速查

    JavaScript函数是编程语言的核心组成部分,它是一段可重复使用的代码块,可以接受参数并返回值。在JavaScript中,函数不仅可以作为表达式,还能作为变量赋值、作为参数传递以及作为返回值。本速查指南将深入探讨...

    javascript函数速查手册

    JavaScript函数是编程语言的核心组成部分,尤其在Web开发中起着至关重要的作用。这份"JavaScript函数速查手册"涵盖了JavaScript函数的各个方面,旨在帮助开发者快速查找和理解各种函数的用法和特性。 一、函数基础 ...

    QT和网页中的JavaScript函数进行相互调用的实现

    - 这里的回调函数用于处理JavaScript函数的异步返回结果,如果需要同步获取结果,可以使用`QWebEngineScript`来注册一个全局JavaScript对象,然后通过该对象调用JavaScript函数。 2. **JavaScript调用QT函数**: ...

    javascript 函数教程(由浅入深)

    以下是关于JavaScript函数的详细讲解: 1. **函数定义**: - 无参函数定义:`function 函数名 () { 代码... }` - 有参函数定义:`function 函数名 (参数列表) { 代码... }` - 参数列表中的参数可以是变量、常量...

    JavaScript函数式编程pdf

    JavaScript函数式编程是一种编程范式,它将计算视为数据处理,并强调使用无副作用的纯函数。在JavaScript中,函数式编程允许我们写出更简洁、可读性更强的代码,同时提高了代码的复用性和测试性。《JavaScript函数式...

    javascript函数式编程 underscore.js

    JavaScript函数式编程是一种编程范式,它强调使用函数来组织代码,将计算视为一系列惰性求值的操作。Underscore.js是一个轻量级的JavaScript实用库,它为开发者提供了大量函数式编程工具,使得在JavaScript中实践...

    JavaScript函数(源代码)

    JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)...

    JavaScript 函数式编程 (英文版)

    JavaScript函数式编程是一种编程范式,它强调将计算视为对数据进行操作的纯函数,而不是通过改变状态或显式指令来控制程序流程。在JavaScript中,函数式编程可以帮助我们写出更简洁、可读性强且易于测试的代码。下面...

    JavaScript函数式编程

    JavaScript函数式编程

    javascript指南和函数式编程

    而《JavaScript函数式.zip》可能是一份关于JavaScript函数式编程的资料集合,函数式编程是一种编程范式,强调使用函数和避免改变状态。其中可能涵盖以下知识点: 1. **纯函数**:理解纯函数的定义,即给定相同的...

    第7节 JavaScript函数及应用.rar

    第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数...

Global site tag (gtag.js) - Google Analytics