函数是这样一段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值做为参数 以及参数列表app
// 定义函数 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能够将函数做为数据使用 做为函数本体 它像普通的数据同样 不必定要有名字 默认名字的函数被称之为匿名函数this
function(a){return a;} /* 匿名函数的做用: 1.将匿名函数做为参数传递给其余函数 - 回调函数 2.将匿名函数用于执行一次性任务 - 自调函数 */
当一个函数做为参数传递给另外一个函数时 做为参数的函数被称之为回调函数code
// 做为另外一个函数(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.避免全局污染