在js中,函数属于较为容易掌握,但使用情况则最为复杂的一种技术。本文仅尝试从如下方面着重阐述一些特点及用法,留待今后update:
1、 函数属于对象类型的一种(ECMAScript中有5中简单类型Undefined、Null、Boolean、Number和String,还有1种复杂类型Object),并且是标准内置类型Function的实例
function demo() { } alert(typeof demo);//function,注意,不是object
2、函数在定义的时候,参数与返回值均为可选。
3、在js中,函数没有重载,当定义了2个名字相同的函数,则该函数名属于后定义者(或简称覆盖)
大致分为如下3种:
//1.使用函数声明语法 function demo1(){} //2.使用函数表达式 var demo2=function(){};//注意不要省略分号,因为有些js引擎实现必须通过分号来判断表达式结尾 //3.使用Function构造函数 var demo3=new Function("m","n","return m+n;");//不推荐
区别:
第一种定义方式:常规方式,不赘述
第二种定义方式:较为特殊,但基本特点和第一种相似。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,因此第二种定义方式实质上等价于:首先定义一个匿名函数,然后将其值赋给一个变量。
第三种定义方式:在Function构造器中,参数分别为若干个形参和函数的具体实现代码,因为使用这种方式定义的时候存在2次解析(一次解析ECMAScript代码,一次解析传入构造器的字符串)、书写代码可读性不好及脚本注入的问题,故不推荐使用。
js解析器在向环境中加载数据时,对前2种方式并非完全一样。
解析器会首先读取函数声明,并使其在执行任何代码之前可访问;而函数表达式,则必须等到解析器执行到他所在的代码行才会真正被解释执行:
alert(demo1(3,4)); function demo1(m,n){ return m+n; }
这段代码运行没问题,最终答案为:弹出“7”
alert(demo2(3,4)); var demo2=function(m,n){ return m+n; };
这段代码在执行期间会导致错误,因为在执行到函数所在语句之前,变量demo2不会保存对函数的引用
除开这一点区别之外,函数声明与函数表达式的语法其实是等效的。
1、常规方式,不赘述
2、apply
function add(n1, n2) { return n1 + n2; } //param1:在其中运行函数的作用域 //param2:Array的实例 alert(add.apply(this, [ 1, 2 ]));//注意,不能去掉中括号 alert(add.apply(window, [ 1, 2 ]));
3、call
function add(n1, n2) { return n1 + n2; } //param1:在其中运行函数的作用域 //param2:可变参数,必须逐个罗列 alert(add.call(this, 1, 2 )); alert(add.call(window, 1, 2 ));
基本上这2种调用方式的区别就在于第二个参数,apply必须传入一个数组的实例,而call则类是java中的可变参数,必须逐个罗列
apply和call在使用场景上,主要是为了扩展函数赖以运行的作用域,而这一点,常规调用方式难以做到
var gender = "female"; var obj = { gender : "male" }; function demo() { alert(this.gender); } demo(this);//female demo.call(window);//同上 demo.call(obj);//male
使用call与apply,实际上做到了:解除了函数调用者与函数实现的耦合关系。或者说apply和call用起来有点像java反射当中method.invoke(obj,args)