一、函数的声明方式
1、普通的函数声明
function box(num1,num2){ return num1+num2; }
alert(box(1,2));
2、使用变量初始化函数
var box=function(num1,num2){ return num1+num2; } alert(box(1,2));
3、使用Function构造函数
var box=new Function("num1","num2","return num1+num2"); alert(box(1,2));
第三种不推荐,因为这种语法导致解析两次代码(第一次解析常规ECMAScript代码,第二次解析传入构造函数中的字符串)
,从而影响性能,但我们可以通过这种语法来理解,函数是对象,函数名是指针的概念
二、作为值的函数,函数可以传递函数
1、函数的返回值可以来传递
function box(sum,num){ return sum+num; } function sum(num){ return num+10; } var result=box(sum(10),10); //这里传递的是函数的返回值,和普通变量没区别 alert(result);
2、把函数本身作为参数来传递,而不是作为结果
function box(sum,num){ return sum(num); } function sum(num){ return num+10; } var result=box(sum,10) //这里sum是函数,当做参数传递到另外一个函数里,而不是返回值 alert(result)
三、函数内部属性
1、arguments类数组对象,包含了传入函数中所有参数,这个对象还有一个callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数
function box(num){ if(num<=1){ return 1; }else{ return num*box(num-1); //3*2*1 } } alert(box(3));
以上是一个阶乘或者是递归,box调用了自己,如果很多自我调用修改也许会麻烦,所以用到arguments.callee来调用自己
function box(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); //arguments.callee 调用自身,实现递归 } } alert(box(3));
2、this
四、函数的属性和方法
1、length 函数希望接收参数个数
function box(a,b){ return a+b; } alert(box.length) //2
2、prototype 原型,下面有两个方法 apply()和call(),每个函数都包含这两个非继承而来的方法,这两个方法的用途都在特定的作用域中调用函数,实际上等于设置函数体内this对象的值
function box(a,b){ return a+b; } function sum(a,b){ return box.apply(this,[a,b]); //this表示window作用域,[]表示传递的参数 } function sum1(a,b){ return box.apply(this,arguments); //这个可以当数组传递 } alert(box(10,10));alert(sum(10,10)); alert(sum1(10,10));
call()和apply()方法相同,他们的区别在于接收参数方式不同。对于call()方法,第一个参数也是作用域,没有变化,变化只是其余的参数都是直接传递给函数的
function box(a,b){ return a+b; } function sum(a,b){ return box.call(this,a,b); //this表示window作用域,[]表示传递的参数 } alert(box(10,10)); alert(sum(10,10));
以上是对象冒充,其实call()和apply()最大的作用是修改作用域
var color="hongse"; var box={ color:"lanse" } function sayColor(){ alert(this.color); } sayColor.call(window); sayColor.call(this); //this就是window sayColor.call(box);
----------------------------------------------进阶----------------------------------------------
1、当函数作为对象的方法时,this指向该对象
2、作为普通函数调用时(当函数不作为对象属性调用时,也就是普通函数方式,此时的this总是指向全局对象,在JavaScript中,这个全局对象是Window对象
例子1:
var myObject={ name:"sven", getName:function(){ return this.name; } } console.log(myObject.getName()) //sven var myObject1=myObject.getName; window.name="lee"; console.log(myObject1()) //lee
例子2:
var div=document.getElementById('div1'); div1.onclick=function(){ console.log(this); //这里的this是dom节点 function callback(){ console.log(this); //这里的this是window,因为是作为普通函数调用的 } callback(); }
-------修改方法,callback.call(this)
3、使用new调用构造器时,如果构造器显示返回一个object类型的对象,那么这次结果最终会返回这个对象,而不是之前期待的this
例1
var myObject=function(){ this.name="sven"; return { name : "anne" //返回object类型 } } var obj=new myObject(); console.log(obj.name) //输出 anne
4、Function.prototype.call 或 Function.prototype.apply 调用
跟普通函数相比,用Function.prototype.call 或 Function.prototype.apply可以动态的改变传入函数的this
例1
var obj1={ name:"sven", getName:function(){ return this.name; } } var obj2={ name:"annr" } console.log(obj1.getName()); //输出 sven console.log(obj1.getName.call(obj2)); //输出 anne -------------call是function方法-----------
5、call和apply
apply接收两个参数,第一个参数指定了函数体内this对象的指向,第二个是个集合(可以是数组,也可以是类数组)
var func=function(a,b,c){ console.log([a,b,c]); } func.apply(null,[1,2,3]) //[1,2,3]
其实和之前学的是一样的,调用函数的时候,都省略了call或apply,比如调用 a(),其实是a.apply()的缩写,只不过,第一个参数是null,函数体内的this会指向默认的宿主对象,在浏览器中则是window
var func=function(a,b,c){ console.log(this===window); } func.apply(null,[1,2,3])
***借用其他对象的方法
有时候我们使用call或者apply的目的不在于指定this指向,而是另有用途,比如借用其他对象的方法,传入null代替某个具体的对象
Math.max.apply(null,[1,2,5]) //5
借用Array.prototype对象上的方法,往arguments中添加一个新的元素,通常会借用Array.prototye.push方法
(function(){ Array.prototype.push.call(arguments,3) console.log(arguments) })(1,2) //[1,2,3] 把任意对象传入Array.prototype.push var a={}; Array.prototype.push.call(a,"frist"); a[0]; //frish a.length; //1
想把arguments转成真正的数组的时候,可以借用Array.prototype.slice方法,想截去arguments列表的头一个元素的时候,可以借用Array.prototype.shift方法
(function(){ Array.prototype.slice.call(arguments) console.log(arguments) })(1,2) //[1,2] (function(){ Array.prototype.shift.call(arguments) console.log(arguments) })(1,2) //[2]