🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## ## **声明函数** ``` //申明普通函数 function fun(){}; fun()//执行普通函数 //函数表达式申明 var fun1=function(){}; fun1() //执行函数表达式申明 的函数 //使用Function构造函数 var fun2=new Function(); fun2()//函数表达式申明 ``` >每个 JavaScript 函数实际上都是一个`Function`对象。运行`(function(){}).constructor === Function // true`便可以得到这个结论 ## **立即执行函数申明** 直接这样写function foo(){}()解释器会报错 **IIFE**(立即调用函数表达式)函数的调用方式通常是将函数表达式、它的调用操作符、分组操作符放到一个括号内,来告诉解释器这里有一个需要立即执行的函数。否则通常情况下,解析器遇到一个function关键字,都会把它当做是一个函数声明,而不是函数表达式 ``` //此写法前面最好加分号,否则他前面的执行体没有结束符时就会报错 ;( function foo(){ //... }() ) //此写法前面最好加分号,否则他前面的执行体没有结束符时就会报错 ;( function foo(){ //... } ) () !function foo() { //... }() +function foo() { //... }() -function foo() { //... }() ~function foo() { //... }() ``` ## **立即执行的匿名函数** ``` //此写法前面最好加分号,否则他前面的执行体没有结束符时就会报错 ;( function(){ console.log(11111); }() ) //此写法前面最好加分号,否则他前面的执行体没有结束符时就会报错 ;( function() { console.log(11111); } ) () !function() { //... }() +function() { //... }() -function() { //... }() ~function() { //... }() ``` **call()与apply()** 这两个方法都是函数对象的方法,需要通过函数对象来调用 当对函数调用call()和apply ()都会调用函数执行 ``` function demo(){} //下面三种方式效果一样都是调用函数 demo();//以函数的形式调用 //以方法的形式调用 demo.apply(); demo.call(); ``` **解析器在调用函数时每次都会向函数内部传递进两个隐含的参数** * 1、第一个隐含的参数就是this this指向的是一个对象,这个对象我们称为函数执行的上下文对象 根据函数的调拥方式不同,this会指向不同的对象 1.以函数的形式调用时,this永远都是Window 2.以方法的形式调用时,this就是调用方法传递的那个对象 ``` var obj={ name:"object", sayName:function(a,b){ console.log(this.name); console.log(a,b) } }; var obj2={ name:"object2", }; //call方法可以将实参在对象之后传递 //apply方法需要将实参统一放入数组中传递 obj.sayName();//object undefined undefined obj.sayName.apply();//空 undefined undefined obj.sayName.apply(obj2);//object2 obj.sayName.apply(obj2,[1,2]);//object2 1 2 obj.sayName.call(obj2,1,2);//object2 1 2 ``` * 2、第二个隐含参数是封装实参的对象arguments arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度 在调用函数时,我们所传递的实参都会在arguments中保存 arguments.length可以用来获取实参的长度 它里边有一个属性叫做callee,这个属性对应一个函数对象,就是当前正在指向的函数的对象 ``` function demo(){ console.log(this); console.log(arguments[0]); console.log(arguments.length); //console.log(arguments.callee==demo); //true } demo();//Window undefined 0 demo("a","b",true);//Window a 3 ``` **闭包:** ```html <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <script type="text/javascript"> var btn=document.getElementsByTagName("button") for (var i = 0; i < btn.length; i++) { btn[i] } //上面循环一次就要计算一次长度,改成下面这种形式性能更好 for (var i = 0,len=btn.length; i < len; i++) { btn[i].onclick=function(){ console.log(i+1);//点击哪个按钮都全是4 } } //改成这样 for (var i = 0,len=btn.length; i < len; i++) { btn[i].index=i btn[i].onclick=function(){ console.log(this.index+1); } } //或者以闭包形式 for (var i = 0,len=btn.length; i < len; i++) { (function(i){ btn[i].onclick=function(){ console.log(i+1); } })(i) } </script> ``` 如何产生闭包?当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变星(函数)时,就产生了闭包 产生闭包的条件?:函数套内部函数引用了外部函数的数据(变量/函数) 函数定义执行完成 ``` //分别在var a=2;和var b=2;处打断点 function fn1(){ var a=2;//断点执行到此时由于函数提升此时已有闭包 function fn2(){ console.log(a) } fn2(); } fn1(); function fn3(){ var b=2;//断点在此时无闭包 var fn4=function(){ console.log(b) } fn4(); } fn3(); ``` **闭包函数的常用使用场景** 1,将函数作为另一个函数的返回值 ``` //例子1:未达到引用了外部函数的数据的条件,所以没有闭包 function fn1(){ function fn2(){} return fn2; } fn2(); //例子2:达到闭包的条件 function fn1(){ var a=2; function fn2(){ a++; console.log(a) } return fn2; } fn2(); //例子3:达到闭包的条件 function fn1(){ var a=2; function fn2(){ a++; console.log(a) } return fn2; } f=fn2();//函数的内容执行完即自动销毁,但是fn2赋值给了f,系统就不会自动销毁 f()//3 f()//4 f=null//死亡条件:成为垃圾对象 function fn1(){ var a=2; function fn2(){ a++; console.log(a) } return fn2; } fn2();//无值,函数的内容执行完即自动销毁 ``` 2·将函数作为实参传递给另一个函数调用 1.使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期) 2·让函数外部可以操作(读写)到函数内部的数据(变量/函数) 问题: 1·函数执行完后,函数内部声明的局部变量是否还存在? 一般不会存在,只有存在于闭包中的变量才能存在 2.在函数外部能直接访问函数内部的局部变量吗? 不能,但可以通过闭包来操作它 闭包示例之定义js模块: ``` function moudle(){ var msg="hello world!"; function fn1(){ return "fn1:"+msg; } function fn1(){ return "fn2:"+msg; } return { fn1:fn1, fn2:fn2 } } //优化 (function(){ var msg="hello world!"; function fn1(){ return "fn1:"+msg; } function fn1(){ return "fn2:"+msg; } window.moudle2 ={ fn1:fn1, fn2:fn2 } })() //进一步优化。使其成为可以压缩的代码 (function(w){ var msg="hello world!"; function fn1(){ return "fn1:"+msg; } function fn1(){ return "fn2:"+msg; } w.moudle2 ={ fn1:fn1, fn2:fn2 } })(window) ``` ``` //缺点函数执行完后,函数内的局部变量没有释放,占用内存时间会变长容易造成内存泄露 //解决:能不用闭包就不用 及时释放 function fun1(){ var arr=new Array[1000]; function fn2(){ console.log(arr.length); } return fn2; } var f=fn1(); f(); ``` 面试题: ``` var name1="the window"; var obj1={ name1:"my object1" fn1:function(){ return function(){ return this.name1; } } } obj1.fn1()();//the window var name2="the window"; var obj2={ name1:"my object2" fn2:function(){ var that=this; return function(){ return that.name2; } } } obj2.fn2()();//my object2 function fun(n,o){ console.log(o); return { fun:function(m){ return fun(m,n); } } } var a=fun(0); a.fun(1) a.fun(2) a.fun(3) var b= fun(0).fun(1).fun(2).fun(3) var c=fun(0).fun(1); c.fun(2) c.fun(3) ```