[1]三种函数定义的方式
[1.1]函数声明:使用function关键字,后跟一组参数以及函数体
[注意]函数的形参之间用逗号分割,因为是声明多个变量,不是多个语句,所以用逗号分隔,而不是分号
function sun(num1,num2){
return num1+num2;
}
[1.2]函数表达式
var sum = function(num1,num2){
return num1+num2
}
[1.3]Function构造函数
var sum = new Function('num1','num2','return num1 + num2');
//[不推荐]会导致解析两次代码,第一次解析常规ECMAScript代码,第二次解析传入构造函数中的字符串,影响性能
[tips]函数声明与函数表达式的区别:
[a1]解析器会率先读取函数声明,并使其在执行任何代码之前可用
[a2]至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行
[b]如果将函数表达式放在对函数的引用语句之后,会弹出"unexpected identifier"意外标识符错误
[c]除了什么时候可以通过变量访问函数这一点区别之外,函数声明与函数表达式的语法其实是等价的
[2]函数参数
[2.1]函数参数在内部是用一个数组来表示的,在函数内部可以通过arguments对象来访问这个参数数组
[2.2]形参只提供便利,但不是必须的
[2.3]开发人员可以利用argument.length属性让函数能够接收任意个参数分别实现适当的功能
[2.4]没有传递值的形参默认为undefined
[2.5]函数参数也被当作变量来对待,因此其访问规则与执行环境中的其他变量相同
[2.6]arguments对象可以和形参一起使用,它的值与对应形参的值保持一致。但形参数组和arguments对象并不指向同一内存空间,它们的内存空间是独立的,但值会同步。
e.g. function doAdd(num1,num2){
arguments[1] = 10;
//[注意1]若未传入num2,num2 == undefined,并不会被赋值为10,而arguments[1] == 10
//[注意2]若传入num2,则 num2 == arguments[1] == 10,二者都等于10
//[注意3]在严格模式下,不允许为arguments赋值,但允许为arguments[n]赋值
alert(arguments[0] + num2);
}
doAdd(1,2);//11
doAdd(1);//NaN 因为 1 + Number(undefined) == 1 + NaN == NaN
[2.7]所有参数传递的都是值,不可能通过引用传递参数
function setName(obj){ obj.name = 'Nicholas'; obj = new Object(); obj.name = 'greg'; } var person = new Object(); setName(person); alert(person.name);//'Nicholas'
[tips]严格模式的限制
[a]不能把函数命名为eval或arguments
[b]不能把函数参数命名为eval或arguments
[c]不能出现两个命名参数同名的情况
[3]函数返回值:通过return语句后跟要返回的值来实现返回值,未指定返回值的函数则默认返回undefined
[注意]位于return语句之后的任何代码都永远不会执行
[4]函数重载:ECMAScript函数没有重载,不存在函数签名的特性,因为其函数参数是以一个包含零或多个值的数组的形式传递的。
[注意]通过检查传入函数中参数的类型和数量并作出不同的反应,可以模仿方法的重载。
[5]函数的属性
[5.1]this:引用的是函数据以执行的环境对象,当在网页全局作用域中调用函数时,this对象引用的是window
[注意]在严格模式下,未指定环境对象而调用函数,则this值不会转型为window,除非明确把函数添加到某个对象或者调用apply()或call(),否则this值将是undefined
[5.2]arguments:一个类数组对象,包含着传入函数中的所有参数
[5.2.1]arguments下有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数
[注意]当函数在严格模式下运行时,访问arguments.callee会导致错误
[tips]阶乘函数
function factorial(num){ if(num <=1){ return 1; }else{ return num* factorial(num-1); } }
若使用arguments.callee可以消除函数解耦
function factorial(num){ if(num <=1){ return 1; }else{ return num* arguments.callee(num-1); } }
[5.3]length:表示函数希望接收的命名参数的个数
[5.4]prototype:在ECMAScript5中,prototype属性是不可枚举的,因此使用for-in无法发现
[5.5]caller(ECMAScript5):除了Opera的早期版本不支持,其他浏览器都支持ECMAScript3并没有定义的属性。这个属性保存着调用当前函数的函数的引用。如果是在全局作用域中调用当前函数,它的值为null
[注意1]ECMAScript5还定义了arguments.caller属性,在严格模式下访问它也会导致错误,而在非严格模式下这个属性始终是undefined,定义这个属性是为了分清arguments.caller和函数的caller属性
[注意2]严格模式还有一个限制:不能为函数的caller属性赋值,否则会导致错误
window.color = 'red'; var o = {color: 'blue'}; function sayColor(){ alert(this.color); } sayColor();//'red' o.say = sayColor; o.say();//'blue'
function outer(){ inner(); } function inner(){ alert(inner.caller); } outer();//弹出function outer(){inner()}; //为了更松散的耦合,可以改为这样: function outer(){ inner(); } function inner(){ alert(arguments.callee.caller); } outer();
[6]函数的方法:apply和call这两个方法都是用于在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。最大的好处是对象不需要与方法有任何耦合关系,这两个方法的强大地方在于能够扩充函数的作用域。
[6.1]apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。第二个参数可以是Array()的实例,也可以是arguments对象。
[6.2]call()方法与apply()方法相同,区别仅仅在于接受参数的方式不同,在使用call()方法时,传递给函数的参数必须逐个列举出来,而apply方法接收arguments对象或一个数组
[6.3]bind()(ECMAScript5):创建一个函数的实例,其this值会被绑定到传给bind()函数的值
function sum(num1,num2){ return num1+num2; } function callSum1(num1,num2){ return sum.apply(this,arguments); } function callSum2(num1,num2){ return sum.apply(this,[num1,num2]); } function callSum00(num1,num2){ return sum.call(this,num1,num2); } function callSum01(num1,num2){ return sum.bind(this,num1,num2)(); } alert(callSum00(10,10));//20 alert(callSum01(10,10));//20 alert(callSum1(10,10));//20 alert(callSum2(10,10));//20
var color = 'red'; var o = {color: 'blue'}; function sayColor(){ alert(this.color); } sayColor();//red sayColor.call(this);//red sayColor.apply(this);//red sayColor.bind(this)();//red sayColor.call(window);//red sayColor.apply(window);//red sayColor.bind(window)();//red sayColor.call(o);//blue sayColor.apply(o);//blue sayColor.bind(o)();//blue
[7]继承的方法:始终返回函数代码(因浏览器而异,有的返回的代码与源代码中的函数代码一样。有的删除了注释并对某些代码做了改动)
[a]toLocaleString()
[b]toString()
[c]valueOf()
[8]函数的应用
[8.1]函数成为参数
function callSomeFunction(someFunction,someArgument){
return someFunction(someArgument);
}
[8.2]从一个函数返回另一个函数
[tips]根据属性名创建比较函数
function createComparisonFunction(propertyName){ return function (object1,object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1 < value2){ return -1; }else if(value1 > value2){ return 1; }else{ return 0; } }; }
[8.3]为函数形参添加默认值
function G(id){ var id = id || 'div1';//为函数形参添加默认值来替代undefined document.getElementById('id').innerHTML = '内容1' }