函数进阶
函数的定义和调用
定义方法:
- 自定义函数(命名函数) function fn() {...};
- 利用函数表达式(匿名函数) var fn = function() {...};
- 利用 new Function var fn = new Function( '形参1', '形参2', '函数体'); (了解)
由第三种方法可知,所有的函数都是 Function 的对象实例,也有如下关系:
调用方法 和 this 指向:
函数 | 调用方法 | 内部 this 的指向 |
普通函数 | fn(); | window |
对象的方法 | obj.fn(); | 所属对象 |
构造函数 | new Fn(); | 实例对象 |
绑定事件函数 | 触发事件后自动调用 | 绑定事件对象(调用者) |
定时器函数 | 到达指定时间后自动调用 | window |
立即执行函数 (function() {...})(); | 立即自动调用 | window |
改变 this 指向的方法
.call() (见上一篇ES5的继承章节)
apply()
fn.apply( thisArg, [argsArray] )
也是可以调用函数,改变 this 的指向;但是要以数组的形式传递参数;
所以可以利用 apply 调用内置对象 Math 的方法应用到数组身上,
如 Math.max.apply(Math, arr); 返回数组中的最大值(原本用法是 Math.max(a, b,...); )。
bind()
可以改变 this 的指向,但是不会调用函数,返回改变 this 指向后的新函数;
fn.bind( thisArg, args1, arg2,... )
严格模式
ES5 新增的严格模式(strict code)是采用具有限制性 JS 变体的一种方式,即在严格的条件下运行 JS 代码;
为整个脚本开启严格模式:在脚本中添加 'use strict';
为某个函数开启严格模式:在函数中添加 'use strict';
严格的规定:
- 变量必须先声明,再使用;
- 不能删除已声明的变量(不能 delete x;)。
- 在全局作用域中,普通函数里面的 this 是 undefined(不是指向 window);
- 构造函数必须用 new Fn; 来调用(不能直接 Fn(); )。
- 函数里的参数不能重名;
- 不允许在非函数的代码块(if、for)内声明函数。 等等
高阶函数
是指对其他函数进行操作的函数,它接收函数作为参数(回调函数),或者输出的返回值是函数:
// 接收函数参数
function fn(callback) {
// 调用回调函数
callback&&callback();
}
//返回函数
function fn() {
return function() {};
}
闭包(closure)
是指有权访问另一个函数作用域中局部变量的函数,延伸了变量的作用范围;
也是高阶函数(返回值是函数);
// fn() 函数是一个闭包
function fn() {
var num = 10;
// funtion fun() {
// console.log(num);
// }
// return fun;
return function() {
console.log(num);
}
}
var f = fn; // 相当于 f = function fun() {...}
f(); //外部的 f() 函数就访问了 fn() 函数的变量(实现闭包)
案例
利用闭包得到点击的 li 的索引号;
立即执行函数是小闭包,因为它里面的任意函数都可以使用外面立执函数传来的变量。
递归
一个函数在内部调用它本身,这个函数就是递归函数;
递归容易发生“栈溢出”(死循环),所以必须要加退出条件 return。
浅拷贝和深拷贝
(jQuery 的 extend?方法)
浅拷贝:只拷贝一层数据,更深层的对象只拷贝它们的引用(地址);
如果改变源对象或者拷贝对象深层的数据,都会使另一个的数据同时改变。
方法:
- for (k in obj) 一层层赋值;
- ES6 新增,Object.assgin(target,...source)
深拷贝:每一层的数据都拷贝,更深层的对象会重新开辟一个空间,再进行赋值;
- 递归函数