5.5 Function类型
三种创建方式:
函数声明语法、函数表达式、Function构造函数;
//声明语法
function sum(num1, num2){
return num1 + num2;
}
//函数表达式
var sum = function (num1, num2){
return num1 + num2;
}; //注意要加分号,像声明变量一样
//Function构造函数
var sum = new Function("num1", "num2", "return num1 + num2"); //不推荐
//from page 110
由于函数名仅仅指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。换句话说,一个函数可能有多个名字,如下:
function sum(num1, num2){
return num1 + num2;
}
alert(sum(10, 10)); //20
var anotherSum = sum;
alert(anotherSum(10, 10)); //20
sum = null;
alert(anotherSum(10,10)); //20
//from page 110
5.5.1 没有重载
将函数名想象为指针,也有助于理解ECMAScript中没有函数重载的概念,曾在第3章使用过的例子:
function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num){
return num + 200;
}
var result = addSomeNumber(100); //300
//from page 111
后面的函数覆盖了前面的函数。
5.5.2 函数声明与函数表达式
函数声明与函数表达式之间的区别在于:解释器会优先读取函数声明,在代码执行之前,解释器就已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中。对代码求值时,JavaScript引擎在第一遍会声明函数并将它们放到源代码树的顶部。
alert(sum(10, 10)); // 20
function sum(num1, num2){
return num1 + num2;
}
alert(sum1(10, 10)); // 报错sum1 is not a function 不会执行下一行代码
var sum1 = function (num1, num2){
return num1 + num2;
}
//from page 111
5.5.3 作为值的函数
函数本身就是变量,所以可以作为值来使用。也就是说不仅可以像传递参数一样把函数传递给另一个函数,还可以将一个函数作为另一个函数的结果返回。
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10, 10);
alert(result1); //20
function getGreeting(name){
return "Hello, " +name;
}
var result2 = callSomeFunction(getGreeting, "Aska");
alert(result2); //Hello, Aska
//from page 112
要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对大括号。
可以从一个函数中返回另一个函数,这是一种极为有用的技术,如下:
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;
}
}
}
var data = [{name:"Yang",age:3},{name:"Aska",age:4}];
data.sort(createComparisonFunction("name"));
console.log(data); // [{name:"Aska",age:4},{name:"Yang",age:3}]
data.sort(createComparisonFunction("age"));
console.log(data); // [{name:"Yang",age:3},{name:"Aska",age:4}]
//from page 113
5.5.4 函数内部属性
函数内部有两个特殊的对象:arguments和this。
① arguments:是个类数组对象,包含传入函数中的所有参数;主要保存函数参数,这个对象还有个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
function factorial(num){
if(num<=1){
return 1;
}else{
return num*(factorial(num-1));
}
}
alert(factorial(5)); //120
上面函数适合用在函数名字不改的情况下。但问题是,这个函数的执行与函数名factorial耦合在一起了,为了消除这种耦合现象,可以像下面这样:
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
alert(factorial(5)); //120
//from page 114
function outer(){
inner();
}
function inner(){
alert(inner.caller);
}
outer();
② this:this引用的是函数执行的环境对象。当在全局作用域中调用函数时,this对象引用的就是window。
window.color="red";
var o = {color : "blue"};
function sayColor(){
alert(this.color)
}
sayColor(); //red;
o.sayColor = sayColor;
o.sayColor(); //blue
//from page 114
③ caller ,这个属性保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,他的值为null。
function outer(){
inner();
}
function inner(){
alert(inner.caller);
}
outer();
以上代码会显示outer()函数的源代码。因为outer调用了inner(),所以inner.caller指向 outer()。为了更松散的耦合,如下:
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();
//from page 115
5.5.5 函数属性和方法
包括两个属性:length() 和 prototype() ;
① length():表示函数希望接收的命名参数的个数;
function sum(num1, num2){
return num1 + num2;
}
alert(sum.length); //2
② prototype():保存他们所在实例方法的真正所在,如toString() 等方法实际都保存在prototype中的。
两个方法(非继承):apply() 和 call();
① apply() :接受两个参数,一个是在其中运行函数的作用域,另一个是参数数组。第二个参数可以是Array实例,也可以是arguments对象。
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this,arguments); //传入arguments对象
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); //传入数组
}
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20
//from page 116
② call():第一个参数是this值,第二个参数是其余参数都直接传递给函数。
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1, num2);
}
alert(callSum(10, 10)); //20
//from page 20
apply() 和 call()真正强大的地方是能够扩充函数赖以运行的作用域,如下:
window.color="red";
var o = {color : "blue"};
function sayColor(){
alert(this.color)
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
//from page 117
③bind():这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值,如下:
window.color="red";
var o = {color : "blue"};
function sayColor(){
alert(this.color)
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
每个函数继承的toLocaleString() 和toString()方法始终都返回函数的代码,代码因浏览器而异,不能用来实现功能,但在调试代码时很有用。