每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法.函数名实际上是指向函数对象的指针.
函数声明:
function sum( num1,num2) {
return num1+num2;
}
var sum = sum(1,2); //3
函数声明提升: 上面这个例子是函数声明在前,调用在后,但是js引擎能把函数声明提到顶部.
函数表达式:
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对象的函数.在递归的时候用到
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!
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!!!
//三种方案
//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属性值
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
function alterObjects(constructor, greeting) {
constructor.prototype.greeting = greeting;
}
原型链:bhggg
题目描述 考察:递归 arguments.callee()函数
function fibonacci(n) {
if(n==1||n==2) {
return 1;
} else {
return arguments.callee(fibonacci(n-1))+arguments.callee(fibonacci(n-2));
}
}
注意: 函数递归应该始终使用 argument.callee来递归调用自身,不要使用函数名-----函数名可能会变化.
闭包
先来讲一讲"作用域"的概念,再了解闭包是什么."作用域",举个例子,简单来说就是,外部函数包含内部函数,内部函数可访问外部的变量,而外部的却不能访问内部的.在函数中访问一个变量时,就会从作用域中搜索具有相应名字的变量,作用域链本质上是 一个指向变量对象的指针列表,访问是线性的有次序的. 闭包会携带包含它的函数的作用域,内部函数可以访问外部环境变量对象.但是闭包也因比其他函数占用更多的内存带来了不好的一面,应慎重使用闭包.
函数中声明的变量是局部变量,在函数外部是没有办法访问的.下面拿自增的举例
function box(){
var age = 100;
return age;
}
alert(age); // "Uncaught ReferenceError: age is not defined"
而利用闭包可以返回局部变量:
//使用匿名函数实现局部变量驻留内存
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; //解除引用,等待垃圾回收