一、函数
函数:n条语句的封装体
- 创建
- function 函数名(){} 声明函数:
一经声明,全局调用(不在意书写位置)。 - var 函数名 = function(){} 函数表达式 :
匿名函数若带上名字,名字失效。 - **构造函数 var 函数名 = new Function(参数, 语句) **不常用
-
属性
- name 函数的名字
- length 返回函数的形参个数 -
形参、实参
- 形参个数 > 实参个数 多余的形参值是 undefined
- 形参个数 < 实参个数 多余的实参在arguments里
- arguments :所有实参的集合,是一个伪数组,常用于实现不定参函数
- 非严格模式下 arguments.callee 是对函数的引用。严格模式不可用。 -
简单类型值作为实参 、 引用类型作为实参的区别:
1. 简单类型值作为参数,函数内部的变化不会影响到传入的变量
2. 引用类型值作为参数,函数内部的变化会影响到传入的变量
- 默认参 短路语句 -
返回值
- return 不写默认返回 undefined -
函数作用域
- 内部可以使用外部函数或者window的变量
- 函数外不能使用函数内部变量
- 立即执行函数 (创建独立空间) 函数表达式的立即执行 3 -
高级函数:将函数作为参数或者返回值的函数
- 闭包:能够访问另一个函数作用域中变量的函数
-
函数声明提升 > 变量的声明提升
1.不定参函数 arguments
function add(){
var count = 0;
for(var i = 0; i < arguments.length; i ++){
count += arguments[i];
}
return count;
}
var returnValue = add(1,2); // 3
2. ES6 不定参 (…args) 除已知参数外剩下的参数的集合
// 剩余参数必须写在末尾
function add2(a,b, ...args){
console.log(args);
}
add2(1,2,3,4,5); // [3,4,5]
3.默认参
function mul(a, b){
// 如果没有a, a = 2
// 如果没有b, b = 3
a = a || 2;
b = b || 3;
return a * b;
}
console.log(mul()); // 6
function mul1(a = 3, b = 2){
console.log("默认参", a * b);
}
mul1(); // 6
mul1(4); // 8
mul1(undefined, 4); // 12
4.obj.assign 合并对象
function sayName(obj){
obj = Object.assign({
name: "xx"
}, obj);
console.log(obj.name);
}
sayName(); // "xx"
sayName({
}); // "xx"
sayName({
name: "李白"}); // "李白"
5.环境作用域中:首先函数声明提升,然后才轮到变量声明提升。
var a = 10;
function fn(){
console.log(a); // undefined
return;
a += 30;
var a = 20;
console.log(a);
}
fn();
console.log(a); // 10
6.立即执行函数
// 1. 函数表达式的立即执行
var fn = function (){
console.log("函数表达式的立即执行");
}();
// 2. 声明函数的立即执行
(function fn(){
console.log("立即执行");
}())
(function fn(){
console.log("立即执行");
})()
// 3. 函数表达式使用两个括号时
var fn = (function(){
console.log("函数表达式的立即执行");
}())
var fn = (function(){
console.log("函数表达式的立即执行");
})()
7.闭包题
闭包的本质就是:指有权访问另一个函数作用域中的变量的函数。
function fun(n, o) {
console.log(o);
return {
fun: function (m) {
return fun(m, n);
}
};
}
第一道:
// var a = fun(0); // undefined
// a.fun(1); // 0
// a.fun(2); // 0
// a.fun(3); // 0
第二道:链式操作
// var b = fun(0).fun(1).fun(2).fun(3); // undefined 0 1 2
第三道:
var c = fun(0).fun(1); // undefined 0
c.fun(2); // 1
c.fun(3); // 1
-
作用:
- 延长局部变量的生命周期
- 让函数外部能操作内部的局部变量
-
闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域
-
闭包应用:
- 回调函数
- 模块化编码: 封装一些数据以及操作数据的函数, 向外暴露一些行为
- 遍历添加事件监听
-
缺点:
-
变量占用内存的时间可能会过长
-
可能导致内存泄露
-
解决:及时释放 : f = null; // 让内部函数对象成为垃圾对象
-
-
闭包题2
// 闭包题1:编写一个像 sum(a)(b) = a+b 这样工作的 sum 函数。
function sum(a, b) {
return function (b) {
console.log(a + b);
}
}
sum(3)(-4);
- 闭包题3
// 闭包题2: 简化 sort 按字段排序
// 有一组需要排序的对象
let users = [
{
name: "John", age: 20, surname: "Johnson" },
{
name: "Pete", age: 18, surname: "Peterson" },
{
name: "Ann", age: 19, surname: "Hathaway" }
];
// 通常的做法:
// 通过 name (Ann, John, Pete)
users.sort(function (a, b) {
return a.name > b.name ? 1 : -1 });
console.log(users);
// 通过 age (Pete, Ann, John)
// users.sort(function (a, b) {
return a.age > b.age ? 1 : -1 });
// console.log(users.sort());
// 要求简化为: 根据key升序排列
function byField(key) {
return function (a, b) {
return a[key] > b[key] ? 1 : -1;
}
}
users.sort(byField('name'));
console.log(users);
users.sort(byField('age'));
console.log(users);
// 排序后修改对象数组地址,以前打印的同一堆地址的对象数组,所以结果都一致。