1.函数的定义
函数就是一个特殊的对象,是一个Function类的实例,其实在内存中存储的操作是通过一个键值对来存储的
函数的名称仅仅只是一个键,值指向的是内存中的一个对象,这个对象就是function对象
function fn1(){
alert("fn1");
} 由于函数是一个对象,所以可以通过如下方式进行定义:
以下是通过函数的拷贝来完成赋值的,两个引用并没有指向同一个对象
var fn2 = fn1; //内存中是将fn1的内容拷贝到fn2
fn2(); //--> fun1
fn1 = function(){ alert("fnn1");}函数虽然是一个对象,但是和对象有一些区别,对象是通过引用的指定完成对象的赋值的,而函数却是通过对象的拷贝来完成的
所以fn1虽然变了,并不会影响fn2
fn2(); // --> fn1
fn1(); // --> fnn1对象是通过引用的指定完成对象的赋值的,此时修改o1或者o2会将两个值改变
var o1 = new Object();
var o2 = o1;
o2.name = "Leon";
alert(o1.name); //-->Leon2.函数的重载
函数就是一个对象,不存在重载,只存在覆盖,后边定义的覆盖前面定义的
function sum(sum1,sum2){
return num1+num2;
}
//相当于
-->
var sum = function(sum1,sum2){
return num1+num2;
}此时sum所指向的内存空间已经从有两个参数的函数变化成只有num1的函数中在调用的时候就只会调用只用num1的函数
特别指出:函数的参数和调用没有关系,如果函数只有一个参数但传入两个参数,仅仅只匹配一个,所以js中不存在重载
function sum(num1){
return num1+100;
}
//相当于
-->
var sum = function(sum1,sum2){
return num1+num2;
}
alert(sum(19));//-->119
alert(sum(19,20));// -->119函数有如下创建方式
var fn = new function (arg1,arg2,...,argn,function body);
var fn = new function ("num1","num2","alert(num1+num2)");3.函数的值传递
由于函数是一个对象,我们就可以把fun当作一个参数传递
function callFun(fun,arg){
return fun(arg);
}
function say(str){
alert("hello"+str);
}
-->相当于
var say = xxx //这是一个对象
callFun(say,"Leon"); //将say传入fun fun相当于指向say的内存空间
function sum(num){
return num+100;
}
alert(callFun(sum,20)); //如此就是灵活性的改变 function fn1(arg){
/**
此时返回的是一个函数对象
**/
var re1 = function(num){
return arg+num;
}
return rel;
}
//
var f = fn1(20);//f是一个函数对象 所带来的好处就是 arg参数的作用域被放大 可以在任何时候再次调用 带来更多的灵活性
alert(f(11));//如此可以完成对这个函数的调用4.函数的argument
在函数对象中有一个属性arguments,通过这个属相可以获得相应的参数值,这个属性可以获取相应的参数值。
这个属性是一个数组,其实就是传递进来的参数
function say(num){
alert(arguments.length); // -->3
alert(num);// --> 1
for(var i=0;i<arguments.length;i++){
alert(arguments[i]); // 1 2 3
}
}
say(1,2,3);在agruments这个对象中有一个callee的方法,arguments.callee(arg)可以反向调用
function factorial(num){
if(num<=1) return 1;
//此时是耦合在一起的
else return num*factorial(num-1);
}
/**
以上是一个求阶乘的函数,以上递归函数用的函数名称和原有的函数名称耦合在一起,如果将来这个函数名称更改之后,
递归调用就会失效
**/
var cf = factorial;
//此时不会报错
alert(cf(5));//120
//此时由于cf这个函数依然使用factorial这个名称来调用,但是factorial已经指向null了,所以就会报错
//如上情况就需要arguments.callee方法来调用
factorial = null;
alert(cf(5));//报错
function factorial_1(num){
if(num<=1) return 1;
//以下实现函数名的解耦和,在js中都是通常使用这种方式做递归
else return num*arguments.callee(num-1);
}
var cf = factorial_1;
factorial_1 = null;
alert(cf(5));5.函数的this
当需要创建一个类的时候,设置类的属性和方法需要通过this关键字来引用
但是特别注意:this关键字在调用时会根据不同的调用对象而变得不同
var color ="red";
function showColor(){
alert(this.color);
}创建一个类,有一个color的属性和一个show的方法
function Circle(color){
this.color = color;
this.show = showColor;
}
var c = new Circle("yellow");
//使用c来调用show方法,等于调用了showColor()方法
//现在的this是c
c.show();// --> yellow
//此时调用的对象是window
//this是window,就会找window的color
showColor();6.函数的属性
函数有两个非常有用的属性:length 和 prototype
length指的是该函数所期望传递进来的参数个数
function fn1(){}
function fn2(num1,num2){}
function fn3(num3){}
alert(fn1.length);// --> 0
alert(fn2.length);// --> 2
alert(fn3.length);// --> 17.函数的方法
函数有两个非常有用的方法:call apply
这两个方法是可以通过函数名称来调用的函数
对于apply而言:
有两个参数,第一个是调用的上下文,第二个是参数数组,可以直接把arguments传递进去
对于call而言
第一个参数是上下问对象,后面的参数是不同函数参数
function sum(num1,num2){
return num1+num2;
}
function callSum1(num1,num2){
//使用sum这个函数来完成一次调用,调用的参数就是callSum1这个函数的参数
return sum.apply(this,arguments);
}
function callSum2(num1,num2){
//关键是第二个参数是数组
return sum.apply(this,[num1,num2]);
}
alert(callSum1(12,22));// -->34
alert(callSum1(22,32));// -->54
function callSum3(num1,num2){
//call是通过参数列表来完成传递,其他没有任何区别
return sum.call(this,num1,num2);
}Ex
var color ="red";
function showColor(){
alert(this.color);
}
function Circle(color){
this.color = color;
}
var c = new Circle("yellow");
showColor.call(this); //使用上下文调用,结果是 red
showColor.call(c); //使用上下文调用,结果是 yellow 通过以上发现,使用call和apply之后,对象可以不需要定义方法
就是call和apply的一种运用