zzrshuiwuhen 2019-06-28
函数是这样一段JavaScript代码 它只定义一次 但可能被执行或调用多次
Function类型是JavaScript提供的引用类型之一 通过Function类型创建Function对象
在JavaScript中 函数也是以对象的形式存在的 每个函数都是一个Function对象
函数名 本质就是一个变量名 是指向某个Function对象的引用
// 1.函数声明方式 function fun(){ console.log('this is function'); } // 2.字面量方式 var fn = function(){ console.log('this is function too'); } // 判断函数是否为Function类型的 console.log(fun instanceof Function);// true console.log(fn instanceof Function);// true // JavaScript中所有的函数都是Function类型的对象 /* 3.创建Function类型的对象 - 是一个函数 var 函数名 = new Function(参数,函数体); * 由于函数的参数和函数体都是以字符串形式传递给Function的 */ var f = new Function('a','console.log(a)'); f(100);// 以函数方式进行调用
// 1.Object与Function都是自身的类型 console.log(Object instanceof Object);// true console.log(Function instanceof Function);// true // 2.Object自身是构造函数,而构造函数也是函数,是函数都是Function类型 console.log(Object instanceof Function);// true // 3.Function是引用类型,用于创建对象,是对象都是Object类型 console.log(Function instanceof Object);// true
..变量的声明提前 console.log(v);//undefined var v = 100; //如果使用函数声明方式定义函数时 - 函数的声明提前 fun() function fun(){ console.log('this is function'); }
Function的apply()方法用于调用一个函数 并且接受指定的this值 以及一个数组作为参数
// 定义函数 function fun(value){ console.log('this is ' + value); } // 函数的调用方式 fun('function');// 语法结构:函数名称() /* apply(thisArg,argArray)方法 -> 用于调用一个指定函数 * 参数 * thisArg - this * argArray - 数组,作为参数(实参)的列表 */ fun.apply(null, ['function']);
Function的call()方法用于调用一个函数 并且接受指定的this值作为参数 以及参数列表
//定义函数 function fun(value value2){ console.log('this is' + value); } //函数的调用方式 fun('function','张三');//语法结构:函数名称() fun.apply(null,['function','张三']); //call()方法 - 用于调用一个函数 fun.call(null,'function','张三');
Function的bind()方法用于创建一个新的函数(称为绑定函数) 并且接受指定的this值作为参数 以及参数列表
// 定义函数 function fun(value){ console.log('this is ' + value); } /* bind(thisArg, arg1, arg2, ...)方法 * 作用 - 用于创建一个新函数(称为绑定函数) * 参数 * thisArg - this * arg1, arg2, ... - 表示参数列表 * 返回值 - 返回新的函数 */ // var f = fun.bind();// 相对于从指定函数复制一份出来 fun('李四');// this is 李四 var f = fun.bind(null, '张三'); f();// this is 张三
在其他开发语言中 函数具有一种特性 叫做重载 重载就是定义多个同名的函数 但每一个函数接受的参数的个数不同 程序会根据用时传递的实参个数进行判断 具体调用的是哪个函数
但是在JaveScript中 函数是没有重载现象的 也就是说 如果同时定义多个同名的函数 只有最后一个定义的函数是有效的
/* 重载的含义 1.定义多个同名的函数,但具有数量不同的参数 2.调用函数,根据传递参数的个数调用指定的函数 */ function add(a,b){ return a + b; } function add(a,b,c){ return a + b + c; } function add(a,b,c,d){ return a + b + c + d; } add(1,2);// 3 add(1,2,3);// 6 add(1,2,3,4);// 10 // JavaScript的函数不存在重载 -> 当函数同名时,最后一次定义的函数有效 console.log(add(1,2));// NaN console.log(add(1,2,3));// NaN console.log(add(1,2,3,4));// 10
JavaScript提供了arguments对象 该对象可以模拟函数重载的现象 arguments对象是函数内部的本地变量 arguments已经不再是函数的属性了
arguments对象可以获取函数的所有参数 但arguments对象并不是一个数组 而是一个类数组对象(没有数组特有的方法)
/* JavaScript提供arguments对象 * 该对象存储当前函数中所有的参数(实参) - 类数组对象 * 场景 - 该对象一般用于函数中 * 作用 - 用于获取当前函数的所有参数 * 属性 * length - 函数所有参数(实参)的个数 * 用法 - 模拟实现函数的重载 */ function add(){ var num = arguments.length; switch (num) { case 2: return arguments[0] + arguments[1]; break; case 3: return arguments[0] + arguments[1] + arguments[2]; break; case 4: return arguments[0] + arguments[1] + arguments[2] + arguments[3]; break; } } console.log(add(1,2));// 3 console.log(add(1,2,3));// 6 console.log(add(1,2,3,4));// 10
调用自身的函数被称之为递归函数 在某种意义上说 递归近似于循环 两者都有重复执行相同的代码 并且两者都需要一个终止条件以避免无限循环或者无限递归
/* 函数的递归 -> 就是在指定函数的函数体中调用自身函数 function fun(){ // 当前函数的逻辑内容 console.log('this is function'); // 调用自身函数 -> 实现递归 fun(); } fun(); */ function fn(v){ console.log(v); if (v >= 10) { return; } // fn(v + 1); arguments.callee(v + 1); } // fn(0); var f = fn; fn = null; f(0); // console.log(f);
JavaScript可以将函数作为数据使用 作为函数本体 它像普通的数据一样 不一定要有名字 默认名字的函数被称之为匿名函数
function(a){return a;} /* 匿名函数的作用: 1.将匿名函数作为参数传递给其他函数 - 回调函数 2.将匿名函数用于执行一次性任务 - 自调函数 */
当一个函数作为参数传递给另一个函数时 作为参数的函数被称之为回调函数
// 作为另一个函数(fn)的参数的函数(one) - 回调函数 var one = function(){ return 1; } function fn(v){ return v(); } // one函数仅是作为fn函数的参数出现 - 并不是调用 // var result = fn(one); /* 以上代码等价于以下代码 以下代码中作为参数的函数 - 匿名回调函数 */ var result = fn(function(){return 1;}); console.log(result);// 1
回调函数的优点:
1.它可以在不做命名的的情况下传递函数(这意味着可以节省全局变量)
2.可以将一个函数调用操作委托给另一个函数(这意味着可以节省一些代码编写工作)
3.回调函数也有助于提升性能
// 作为另一个函数(fn)的参数的函数(one) -> 回调函数 var one = function(w){ return w; } function fn(v){// 形参是一个函数 return v(100);// 函数的调用体 } // var result = fn(one);// 实参必须是一个函数 var result = fn(function(w){return w;}); console.log(result);
自调函数就是定义函数后自行调用
/* 自调函数 - 定义即调用的函数 * 第一个小括号 - 用于定义函数 * 第二个小括号 - 用于调用函数 */ // 全局作用域 - 生命周期:JavaScript文件从执行到执行完毕 (function(value){ // 函数作用域 - 生命周期:从函数调用到调用完毕 console.log('this is ' + value); })('function'); // 表达式语法 (function(value){ // 函数作用域 - 生命周期:从函数调用到调用完毕 console.log('this is ' + value); }('function')); !function(value){ // 函数作用域 - 生命周期:从函数调用到调用完毕 console.log('this is ' + value); }('function'); +function(value){ // 函数作用域 - 生命周期:从函数调用到调用完毕 console.log('this is ' + value); }('function');
将一个函数作为另一个函数的结果进行返回 作为结果返回的函数称之为值的函数
var one = function(){ return 100; } // 作为值的函数 -> 内部函数的一种特殊用法 function fun(){ var v = 100; // 内部函数 return function(){ return v; }; } var result = fun(); //console.log(result);// one函数 //console.log(result());// 100 console.log(fun()());
很多开发语言中都具有块级作用域 但ECMAScript5版本中并没有跨级作用域 这经常会导致理解上的困惑
虽然ECMAScript5版本没有块级作用域 但具有函数作用域 在某个函数内部定义的便利的作用域就是该函数作用域
每一段JavaScript代码(全局代码或函数)都有一个与之关联的作用域链
var a = 10;// 全局变量 function fun(){ var b = 100;// fun函数作用域的局部变量 // 内部函数 function fn(){ var c = 200;// fn函数作用域的局部变量 // 内部函数 function f(){ var d = 300;// f函数作用域的布局变量 // 调用变量 console.log(a);// 10 console.log(b);// 100 console.log(c);// 200 console.log(d);// 300 } f(); // 调用变量 // console.log(a);// 10 // console.log(b);// 100 // console.log(c);// 200 // console.log(d);// d is not defined } fn(); // 调用变量 // console.log(a);// 10 // console.log(b);// 100 // console.log(c);// c is not defined // console.log(d);// d is not defined } fun();
JavaScript允许函数嵌套 并且内部函数可以访问定义在外部函数中的所有变量和函数 以及外部函数能访问的所有变量和函数 但是 外部函数却不能够访问定义在内部函数中的变量和函数
当内部函数以某一种方式被任何一个外部函数作用域访问时 一个闭包距产生了
闭包就是词法表示包括不必计算的变量的函数 也就是说 该函数能使用函数外定义的变量
var n;// 定义变量,但不初始化值 function fun(){// 函数作用域 var v = 100; // 进行初始化值 -> 一个函数 n = function(){ console.log(v); } // n(); } fun(); n();// 100
闭包的特点:
1.局部变量:在函数中定义有共享意义(如 缓存 计数器等)的局部变量(注:定义全局变量会对外造成污染)
2.内部函数:在函数(f)中声明有内嵌函数 内嵌函数(g)对函数(f)长得局部变量进行访问
3.外部使用:函数(f)向外返回此内嵌函数(g) 外部可以通过此内嵌函数持有并访问声明在函数(f)中的变量 而此变量在外部是通过其他途径无法访问的
闭包的作用:
1.提供可共享的局部变量
2.保护共享的局部变量 提供专门的读写变量的函数
3.避免全局污染