对于面向对象编程的语言来说,对象是很重要的一个概念,而对于函数来说,每个函数实际上都是对象,每个函数都是Function类型的实例,而且与其他引用类型一样具有属性和方法。
函数声明与函数表达式
通常有三种声明函数的方法
- 使用函数声明语法
function sum(num1, num2) {
return num1 + num2;
}
这也是最常用的方法
- 使用函数表达式定义函数
var sum = function (num1, num2) {
return num1 + num2;
};
可能会注意到function
关键字后面没有函数名,这是因为使用函数表达式定义函数时,通过变量sum
就可以引用函数
- 使用Function构造函数
var sum = new Function("num1", "num2", "return num1 + num2");
但是非常不推荐这种写法,因为这种语法会导致解析两次代码(第一次解析ECMAScript代码,第二次解析传入构造函数的参数)从而影响性能
关于变量提升
对于1,2两种声明函数的方法有什么不同呢?看下面这个例子
// 使用函数声明创建函数
console.log(sum(10,10)); //会打印出20
function sum(num1, num2) {
return num1 + num2;
};
// 使用函数表达式创建函数
console.log(add(10,10)); //会报错
var add = function(num1, num2) {
return num1 + num2;
};
实际上,解析器在执行环境中加载数据时,解析器会率先读取函数声明,并使其在执行任何代码之前可用,而至于函数表达式,则必须等到解析器执行到它所在的代码行才会真正被解释执行。
函数内部属性
在函数内部,有两个特殊的对象:arguments
和this
arguments
是一个类数组对象,包含着传入函数的所有参数,之前在基础算法的时候已经讲过。但是arguments
还有一个名叫callee
属性,该属性是一个指针,指向拥有arguments
对象的函数。具体用法之前写过了,看这里
另一个比较特殊的对象就是this
了,关于this
知乎上@方方老师的这篇文章讲的特别好
函数的属性和方法
因为在ECMAScript中函数是对象,因此函数也有属性和方法。
每个函数包含两个属性:length
和prototype
length
表示函数接受的参数的个数
function sayName(name) {
console.log(name);
}
function sum(sum1, sum2) {
return num1 + num2;
}
function sayHi() {
console.log("Hi!");
}
console.log(sayName.length); //1
console.log(sum.length); //2
console.log(sayHi.length); //0
另一个属性prototype
是保存引用类型所有实例方法的真正所在,比如toString()
和valueOf()
等方法都保存在prototype
名下,prototype
在实现继承时非常重要,下一篇我们再讲。
每个函数都包含两个非继承来的方法:apply()
和call()
apply()
和call()
都是在特定的作用域中调用函数,等于设置函数体内this
的值,他们的区别在于:
apply()
接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组,既可以是Array
实例,也可以是arguements
对象。
call()
第一个参数和apply()
一样,但是传递参数的时候,必须逐个例举出来。
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]); //传入数组
}
function callSum3(num1, num2) {
return sum.call(this, num1, num2); //使用call必须把参数列举出来
}
console.log(callSum1(10,10)); //20
console.log(callSum2(10,10)); //20
console.log(callSum3(10,10)); //20
既然apply()
和call()
的参数有作用域,那么是用来干什么的呢?看下面的例子:
window.color = "red";
var 0 = { color: "blue" };
function sayColor() {
console.log(this.color);
}
sayColor(); //red
sayColor.call(this) //red
sayColor.call(window) //red
sayColor.call(o) //blue
是不是this
的值又懵了?如果懵了,就翻上去看方方老师那篇文章。
没错,apply()
和call()
的作用就是扩充函数的作用域
大概就是这么多了,书上这一章的内容我反复看了好几遍才理解,所以学习哪有什么捷径,无他,唯手熟尔
那么,聪明的你,看完之后懂了没有?
下一篇准备讲原型