函数Function

    函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

一、定义函数的方法:

1.函数声明

function sum(num1,num2){}

2.函数表达式

var sum=function(num1,num2){}

使用函数表达式定义时,没有必要使用函数名,但也可以是var sum=function ab(num1,num2){}

使用不带圆括号的函数名是访问函数指针,而非调用函数。

3.区别

解析器会率先读取函数声明,并使其在执行任何代码之前可用;至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

二、函数没有重载

JS中函数没有重载,在创建第二个函数时,实际上覆盖了第一个函数。

三、作为值的函数

函数本身就是变量,所以函数也可以作为值来使用。可以像传递参数一样把一个函数传递给另一个函数,而且也可以将一个函数作为另一个函数的结果返回。

四、函数内部属性

1.arguments

在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。arguments对象和数组类似,因此可以通过方括号访问,length确定传递进来的参数个数。arguments[0]

另外arguments的值永远与对应命名参数的值保持同步。

function doAdd(num1,num2){

  arguments[1]=10;

  alert(arguments[0]+num2);//num2每次都被重写为10

}

这个对象还有一个属性callee,该属性是一个指针,指向拥有这个arguments对象的函数。

function factorial(num){

  if(num<=1){

    return 1;

  }else{

    return num*arguments.callee(num-1);

  }

}

2.另一个函数对象的属性caller

这个属性保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。

function outer(){

  inner();

}

function inner(){

  alert(inner.caller);//弹出调用inner的函数的引用,也就是outer,因此会输出function outer(){inner();}

}

为了实现更松的耦合,可以这样调用

function inner(){

  alert(arguments.callee.caller);

}

五、函数的属性和方法

每个函数都包含两个属性length和prototype; length属性表示函数希望接受的命名参数的个数。

function sayName(num1,num2){}

alert(sayName.length)//2

prototype是保存函数所有实例方法的真正所在。不可枚举,无法使用for-in发现。

每个函数都包含两个非继承而来的方法:apply()和call()

用途:在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

扩充函数赖以运行的作用域。

1.apply()

接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。第二个参数可以是Array的实例,也可以是arguments对象。

2.call()

作用同apply,区别仅在于接收参数的方式不同。第一个参数相同,第二个参数是直接传递给函数,也就是说传递给函数的参数必须逐个列举出来。

3.bind()

其this值会被指定给传给bind()函数的值。

window.color='red';

var o={color:'blue'};

var b={color:'yellow'};

function sayColor(){

  alert(this.color);

}

var osaycolor=sayColor.bind(o);

var bsaycolor=sayColor.bind(b);

osaycolor()//'blue'

bsaycolor()//'yellow'

4.toLocalString()  toString() valueOf()

始终返回函数的代码。

六、理解apply() call()

经常会这样定义:
  
function cat(){
  }
cat.prototype={
  food:"fish",
  say: function(){
     alert("I love "+this.food);
  }
}

var newCat = new cat();
newCat.say();

但是如果我们有一个对象newDog = {food:"bone"},我们不想对它重新定义say方法,那么我们可以通过call或apply用newCat的say方法:
newCat.say.call(newDog);
cat.prototype.say.call(newDog);

所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。

用的比较多的,通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。我们可以通过:
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
这样domNodes就可以应用Array下的所有方法了。
 

call和apply可以用来重新定义函数的执行环境,也就是this的指向。通过一个操作DOM的例子来理解。


function changeStyle(attr, value){
    this.style[attr] = value;
}
var box = document.getElementById('box');
window.changeStyle.call(box, "height", "200px");

call中的第一个参数用于指定将要调用此函数的对象,在这里,changeStyle函数将被box对象调用,this指向了box对象,如果不用call的话,程序报错,因为window对象中没有style属性。
apply的用法:

window.changeStyle.apply(box, ['height', '200px']);
 
1. 
function add(a,b){  
    alert(a+b);  
}  
function sub(a,b){  
    alert(a-b);  
}  
add.call(sub,3,1); //  4

2.

function Animal(){ 
  this.name = "Animal"; 
  this.showName = function(){ 
    alert(this.name); 
  } 
}

function Cat(){ 
  this.name = "Cat"; 
} 

var animal = new Animal(); 
var cat = new Cat(); 

//通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。
animal.showName.call(cat,",");   //Cat
//animal.showName.apply(cat,[]);  //Cat

3.实现继承

function Animal(name){ 
  this.name = name; 
  this.showName = function(){ 
    alert(this.name); 
  }

  this.hi=function(){// 注意这里必须是this引用才能继承,否则cat.hi()时,会报错,hi不是一个函数 

    alert("hello "+this.name);

  } 
} 

function Cat(name){ 
  Animal.call(this, name); 
} 

var cat = new Cat("Black Cat"); 
cat.showName();//Black Cat

cat.hi();//hello Black Cat

4.多重继承

function Class10(){

  this.showSub = function(a,b){
    alert(a-b);
  }
}

function Class11(){

  this.showAdd = function(a,b){
    alert(a+b);
  }
}

function Class2(){

  Class10.call(this);
  Class11.call(this);
}

var c2=new Class2();

c2.showSub(10,3)//7

c2.showAdd(10,3)//13
原文地址:https://www.cnblogs.com/YangqinCao/p/5411758.html