函数的作用:功能的封装,直接调用,代码复用率提高
构建对象的模板(构造函数)
函数实际上是对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法,由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。
1.函数声明
//第一种方式
function 函数名(形参列表){
//函数体
}
//第二种方式 匿名函数
var 函数名 = function(形参列表){
//函数体
}
2.函数内部属性
只有在函数内部才能访问的属性。this也可以在函数外部进行使用。
arguments
ECMAScript函数的参数与大多数其他语言中的函数的参数有所不同,ECMAScript函数不介意传递参数的个数以及参数类型,这是因为函数的参数在函数内部是使用一个类数组对象来表示的。这个类数组对象就是arguments。
arguments是一个类数组对象,包含着传入函数中的所有参数。arguments主要用途是保存函数参数,但是这个对象还有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
- 伪数组 并不是真正意义上的数组
- 具有数组的length属性
- 按照索引的方式进行存储
- 没有真正数组的一些方法 pop() push()等
function add(a, b) {
console.log(arguments[0],arguments[1],arguments[2],arguments[3]);
console.log(a+b);
}
console.log(add.length);//结果是2 表示函数希望接受的命名参数的个数,即形参的个数。
add(1);
// 结果是
// 1 undefined undefined undefined
// NaN
add(1,2);
// 结果是
// 1 2 undefined undefined
// 3
add(1,2,3);
// 结果是
// 1 2 3 undefined
// 3
callee
callee 属性是 arguments 对象的一个成员,仅当相关函数正在执行时才可用。
// 实现匿名的递归函数
var sum = function (n) {
if (1 == n) {
return 1;
} else {
return n + arguments.callee(n - 1); //6+5+4+3+2+1
}
}
console.log(sum(6));//输出结果:21
this
面向对象语言中 this 表示当前对象的一个引用。
但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
- 在方法中,this 表示该方法所属的对象。
- 如果单独使用,this 表示全局对象。
- 在函数中,this 表示全局对象。
- 在事件中,this 表示接收事件的元素。
- 在显示函数绑定时,我们可以自己决定this的指向
var person = {
firstName: "LeBron",
lastName: "James",
id: 8888,
fullName: function () {
return this.firstName + " " + this.lastName;
}
};
console.log(person.fullName()); //LeBron James
方法中的 this
在对象方法中, this 指向调用它所在方法的对象。
在上面一个实例中,this 表示 person 对象。
fullName 方法所属的对象就是 person。
单独使用 this
单独使用 this,则它指向全局对象。
在浏览器中,window 就是该全局对象为 [object Window]:
在node中,指向的是一个{}
var x = this;
console.log(x); //{}
函数中使用 this(默认)
在函数中,函数的所属者默认绑定到 this 上。
在浏览器中,window 就是该全局对象为 [object Window]:
在node中,指向的就是global对象
事件中的 this
在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素
显式函数绑定
在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。
当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法:
var person1 = {
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName: "Bob",
lastName: "muu",
}
var name = person1.fullName.call(person2); // 返回 "Bob muu"
console.log(name);
3.函数调用
函数声明好之后并不会直接运行,需要进行调用才能运行。
调用函数的方式不仅限于()执行,还有其他几种方式
- 函数名(实参列表);
- 函数名.call(执行环境对象,实参列表);
- 函数名.apply(执行环境对象,实参列表数组);
- 函数名.bind(执行环境对象)(实参列表);
call(执行环境对象,实参列表);
调用call方法,第一个参数就是要把b添加到哪个环境中,简单来说,this就会指向那个对象。
var obj = {
name: 'zhangsan',
sayName: function () {
console.log(this.name);
}
}
var b = obj.sayName;
b.call(obj);
console.log(b); //zhangsan
在使用call调用的时候,还可以传递多个参数
var obj = {
name: 'zhangsan',
sayName: function (a,b) {
console.log(this.name);
console.log(a , b);
}
}
var b = obj.sayName;
b.call(obj,4,5);
console.log(b); //zhangsan 4 5
apply(执行环境对象,实参列表数组);
apply方法和call方法有些相似,它也可以改变this的指向
var obj = {
name: 'zhangsan',
sayName: function () {
console.log(this.name);
}
}
var b = obj.sayName;
b.apply(obj);
console.log(b); //zhangsan
同样apply也可以有多个参数,但是不同的是,第二个参数必须是一个数组
var obj = {
name: 'zhangsan',
sayName: function (a,b) {
console.log(this.name);
console.log(a , b);
}
}
var b = obj.sayName;
b.apply(obj,[1,2,3]);
console.log(b); //zhangsan 1 2
注意:如果call和apply的第一个参数是null,那么this在node环境下指向的是global对象,在HTML中指向的是window对象
bind(执行环境对象)(实参列表)
var obj = {
name: 'zhangsan',
sayName: function () {
console.log(this.name);
}
}
var b = obj.sayName;
b.bind(obj); // 代码没有被打印,这就是bind和call、apply方法的不同,实际上bind方法返回的是一个修改过后的函数。
var c = b.bind(obj);
console.log(c); //发现c是[Function: bound sayName]函数
//执行c后
c(); //打印出来才是zhangsan
同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的
总结
call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别,根据自己的实际情况来选择使用。
4.函数的应用
函数本质上是一种对象,可以将其当做普通对象来使用
-
回调函数
回调,就是回头调用的意思。主函数的事先做完,回头再调用传进来的那个函数。
function a(callback) {
callback();
console.log('我是主函数');
}
//定义回调函数
function b() {
// 模仿延时操作
setTimeout(() => {
console.log('我是回调函数');
}, 3000);
}
//调用主函数,将函数B传进去
a(b);
回调函数的作用:回调函数都用在耗时操作上面:因为主函数不用等待回调函数执行完,可以接着执行自己的代码。比如ajax请求,比如处理文件等
-
作为返回值
在作用域链中,就使用到了函数作为返回值的用法
var a = 10
function fn() {
var b = 20
function foo() {
console.log(a + b) //30
}
return foo
}
var x = fn(), // 执行fn() 返回的是foo
b = 200
x() //执行x,就是执行foo函数