5.5 引用类型(Function类型)(JavaScript高级程序设计 第3版)

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()方法始终都返回函数的代码,代码因浏览器而异,不能用来实现功能,但在调试代码时很有用。

猜你喜欢

转载自blog.csdn.net/weixin_39752673/article/details/81385077