每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.函数名实际上是指向函数对象的指针.
函数声明:
1
2
3
4
|
function
sum( num1,num2) {
return
num1+num2;
}
var
sum = sum(1,2);
//3
|
函数声明提升: 上面这个例子是函数声明在前,调用在后,但是js引擎能把函数声明提到顶部.
函数表达式:
1
2
3
4
|
var
sum =
function
(num1,num2) {
return
num1+num2;
}
console.log(sum(1,2));
|
function后面没有变量名,sum就相当于变量名,直接调用.但是不能在调用之后才定义,会报 "Uncaught TypeError: undefined is not a function"错误.
说说函数名后面的 ( )
以上面的sum(num1,num2)为例
- sum(); 执行函数
- sum: 没有括号是访问函数的指针不执行函数
arguments对象和this对象
- arguments对象存放着函数的所有参数,类似数组但不是数组,
- 函数内部的this引用的是函数据以执行的环境变量,当在全局作用域中调用函数时,this对象引用的就是window对象.
arguments.callee属性:指向拥有这个arguments对象的函数.在递归的时候用到
1
2
3
4
5
6
7
|
function
fac(num) {
if
(num<=1){
return
1;
}
else
{
return
num* arguments.callee(num)
}
}
|
使用arguments.callee,函数内部调用和函数本身的名字不会有耦合.
函数传参:
题目描述
输入例子:
argsAsArray(function (greeting, name, punctuation) {return greeting + ', ' + name + (punctuation || '!');}, ['Hello', 'Ellie', '!'])
输出例子:
Hello, Ellie!
1
2
3
|
function
argsAsArray(fn, arr) {
return
fn(arr[0], arr[1], arr[2]);
}
|
题目描述 考察:call() apply() bind() 改变上下文this
输入例子:
speak(function () {return this.greeting + ', ' + this.name + '!!!';}, {greeting: 'Hello', name: 'Rebecca'})
输出例子:
Hello, Rebecca!!!
1
2
3
4
5
6
7
|
//三种方案
//apply
function
speak(fn, obj) {
return
fn.apply(obj);}
//call
function
speak(fn, obj) {
return
fn.call(obj);}
//bind
function
speak(fn, obj) {
return
fn.bind(obj)();}
|
注意:在JavaScript中,函数是一种对象,其上下文是可以变化的,对应的,函数内的this也是可以变化的,函数可以作为一个对象的方法,也可以同时作为另一个对象的方法,可以通过Function对象中的call或者apply方法来修改函数的上下文,函数中的this指针将被替换为call或者apply的第一个参数。将函数 fn 的执行上下文改为 obj 对象,只需要将obj作为call或者apply的第一个参数传入即可。
题目描述 考察:var obj = {},var obj = new Object();
1、返回一个对象
2、对象的 greeting 属性值等于 str1, name 属性值等于 str2
3、对象存在一个 sayIt 方法,该方法返回的字符串为 greeting属性值 + ', ' + name属性值
1
2
3
4
5
6
7
8
9
10
|
function
createModule(str1,str2) {
var
newObj = {
greeting:str1,
name:str2,
sayIt:
function
(){
return
this
.greeting+
', '
+
this
.name;
//注意this
}
}
return
newObj;
}
|
题目描述
输入例子:
var C = function(name) {this.name = name; return this;}; var obj1 = new C('Rebecca'); alterObjects(C, 'What\'s up'); obj1.greeting;
输出例子:
What's up
1
2
3
|
function
alterObjects(constructor, greeting) {
constructor.prototype.greeting = greeting;
}
|
原型链:bhggg
题目描述 考察:递归 arguments.callee()函数
1
2
3
4
5
6
7
|
function
fibonacci(n) {
if
(n==1||n==2) {
return
1;
}
else
{
return
arguments.callee(fibonacci(n-1))+arguments.callee(fibonacci(n-2));
}
}
|
注意: 函数递归应该始终使用 argument.callee来递归调用自身,不要使用函数名-----函数名可能会变化.
闭包
先来讲一讲"作用域"的概念,再了解闭包是什么."作用域",举个例子,简单来说就是,外部函数包含内部函数,内部函数可访问外部的变量,而外部的却不能访问内部的.在函数中访问一个变量时,就会从作用域中搜索具有相应名字的变量,作用域链本质上是 一个指向变量对象的指针列表,访问是线性的有次序的. 闭包会携带包含它的函数的作用域,内部函数可以访问外部环境变量对象.但是闭包也因比其他函数占用更多的内存带来了不好的一面,应慎重使用闭包.
函数中声明的变量是局部变量,在函数外部是没有办法访问的.下面拿自增的举例
1
2
3
4
5
|
function
box(){
var
age = 100;
return
age;
}
alert(age);
// "Uncaught ReferenceError: age is not defined"
|
而利用闭包可以返回局部变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//使用匿名函数实现局部变量驻留内存
function
box() {
var
age = 100;
return
function
(){
age++;
return
age;
};
}
var
b = box();
alert(b());
//100
alert(b());
//101
alert(b());
//102
alert(b());
//103
alert(b());
//104
b =
null
;
//解除引用,等待垃圾回收
|