什么是webpack模块化构建工具

百度百科模块化:是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。

计算机模块化:一般指的是可以被抽象封装的最小/最优代码集合,模块化解决的是功能耦合问题。

组件化:是模块化进一步封装,根据业务特点或者不同的场景封装出具有一定功能特性的独立整体,

    另外,前端提到组件化更多的是具有模板,样式和js交互的UI组件。

工程化

  工程化是Web开发是遇到的问题:

  1,模块多了,依赖管理怎么做;

  2,页面复杂度提升之后,多页面,多系统,多状态怎么办;

  3,怎么解决多人研发中的性能,代码风格等问题;

  4,团队扩大之后,团队合作怎么做;

  5,权衡研发效率和产品迭代的问题。

Webpack 与 早期构建工具的区别:

1,早期前端工程化构建工具:Grunt,Gulp等构建工具

  该阶段解决的问题是:重复任务的问题,他们将某些功能拆解成固定步骤的任务,然后编写工具来解决

  如:图片压缩,地址添加hash,替换等,都是固定套路的重复工作。

2,现阶段的Webpack构建工具:

  现阶段Webpack则更像是从一套解决JS模块化依赖打包开始,利用强大的插件机制,逐渐解决前端资源依赖管理问题,

  依附社区力量逐渐进化成一套前端工程化解决方案。

什么是Webpack

  1,本质上是一个现代JS应用程序的静态模块打包器(static module bundler)。

  2,在Webpack处理应用程序是,它会在内部创建一个依赖图(dependency graph),用映射到项目需要的每个模块,

    然后将所有这些依赖生成到一个或多个bundle。  

前端模块化:指JavaScript的模块。

最常见的模块化:Nodejs的NMP包。

模块化的规范有:

  CommonJS  ,   AMD  ,  ES6 Module ,  CMD , UMD等等

一,CommonJS : 是Nodejs广泛使用的一套模块化规范,是一种同步加载模块化依赖的方式:

  1,require  引入一个模块

  2,exports  导入模块内容

  3,module  模块本身

二, AMD:是js模块加载库RequireJS提出并完善的一套模块化规范,AMD是一条异步加载模块依赖的方式:

  1,id   模块的id

  2,dependencies   模块依赖

  3,factory   模块的工厂函数,即模块的初始化操作函数

  4,require   引入模块

 

三,ES6 Module : ES6退出的一套模块化规范

  1,import     引入模块依赖

  2,export    模块导出

四,CMD:国产库SeaJS提出来的一套模块化规范

五,UMD:兼容 CommonJS 和 AMD 的一套规范

目前多数模块的封装,即可以Node.js环境运行,又可以在Web环境运行。一般会采用UMD的规范。

CSS也可以使用@import的方式来引入自己依赖的模块:

      @import  'reset.css';

函数的定义, 普通函数 构造函数 本质 作为数据,递归, 链式调用,间接调用,  arguments参数 return返回值函数的定义:   //函数:一次申明,四次使用(调用)   //函数分为:命名函数(有函数名称的函数) 和 匿名函数(没有名称的函数)   //命名函数   function add(a,b){   //函数体,属于局部作用域   return a+b;// return 表示函数一死,可以烧纸,return后面的是函数返回值   console.log("return 后面的代码永远不会执行。");   };   add(3,8);   //匿名函数    window.onload=function(){   //函数体,属于局部作用域   alert("hellow");   };
   //------函数执行过程-------   function add(a,b){   var result=a+b;   return result;   }   /*   -------上述函数每次被调用时都会发生的事情-------   1,浏览器全局对象window下面创建一个add方法   2,在add方法下面创建一个局部作用域   3,在局部作用域中创建变量 a=undefined , b=undefined , result=undefined   4,执行函数add(1,2);   5,给每个变量赋值 a=1 , b=2 , result=3   6,函数执行完毕,第一个要做的就是删除 add方法里面的局部作用域以及里面的变量,所以在外面无法访问里面的变量*/
//------------------------------------------   //------为什么要使用函数-------   /*1,复用代码   2,易于修改,维护   3,增加程序的可读性*/
   //以下函数对可读性的优化   //下面代码每次看的话都要分析如何实现,怎么判断春夏秋冬,   //每次查看都要分析,细节暴露太多了,所以可读性不是很强。这里就需要封装函数了   function doThings(month){   if (month>=3 && month<=5) {   //踏春   }else if(month>=6 && month<=8){   //游泳   }else if(month>=9 && month<=11){   //秋收   }else{   //冬天睡觉   }   }   //什么时候可以使用函数?   //1,代码中有重复代码,或者有相似代码时,需要封装函数。   //2,功能实现时有很多代码,细节暴露太多,可读性很差时,就需要封装函数。   //   //把上面函数封装成可阅读性比较强,不暴露细节,直接读函数名称就可以知道做什么?   //在实现比较强的阅读性时,不要暴露具体实现的函数过程,直接一个函数名即可。   function isSpring(month){     return month>=3 && month<=5;   }   function isSummer(month){     return month>=6 && month<=8;   }   function isAutumn(month){     return month>=9 && month<=11;   }   function isWinter(month){     return month>12 && month<=2   }   function doThings(month){      if (isSpring()) {      //踏春      }else if(isSummer()){      //游泳      }else if(isAutumn()){      //秋收      }else{      //冬天睡觉      }   }</script><script>//-------------函数的本质---------------/*函数二象性1,函数可以调用2,函数其实是对象:{}定义对象的方式:a,字面量的方式: var a={...}b,构造函数的方式: var obj=new Object();var arr=new Array();添加属性和方法:var person={};person.name="zheng";person.setName=function(name){this.name=name;}
var Person(arguments){name:"zheng",age:"18",addredd:"China"}定义函数的方式:a: function Person(arguments){...}b: var fn = new Person(a,b,c);*///-----以下是对象的操作-------/*var a={"name":"zheng","age":18,"love":"you"}a.name="love";a.setAge=function(age){return a.age=age;}console.log(a.name);console.log(a.setAge(88));*///-----以下是函数的操作-------function add(a,b){age="zheng";//设置age属性return a+b}console.log(add.name);//返回 add,这里name是函数关键字 表示返回当前函数的函数名称//给函数add设置age属性add.setage=function(age){this.age=age;}add.age="love";//重新设置 age 属性值console.log(add.age);//返回 loveadd.setage("you");//修改age的值console.log(add.age);//返回 youconsole.log(add(1,3));//输出 4console.log(add);//输出add函数本体
//给add函数对象添加一个start函数add.start=function(){console.log("hello");}add.start();//执行start方法,输出hello</script>
<script>//---------函数作为数据值来使用----------//值的集合是数组,键值对出现的就是对象//值的集合是数组var arr=[1,"a",function(){}];for(var p in arr){console.log(p);//输出的索引值 0 1 2console.log(arr[p]);//arr[p] 输出的是arr中的对象}//键值对是对象var array={"a":"love","b":"you","c":function(){}};for(var p in array){console.log(p);//输出array的属性console.log(array[p]);//输出array的属性值}
//---------函数作为参数来使用----------//这里的函数作为参数使用// setTimeout(function(){alert(1)},1000);//一秒钟后跳出弹窗setTimeout(fn,1000);//函数名称表示函数本体,fn()表示立即执行该函数本体。function fn(){alert(1);}
//---------函数作为返回值来使用----------function add(){return function(){alert(2)};}/*var newFn=add();//返回 return 后面的匿名函数本体newFn();//函数本体后面添加小括号,表示立即执行该函数*/add();//得到 function(){alert(2)}; 这个返回值,是一个匿名函数本体。add()();//表示执行匿名函数本体</script>
//========函数的三种定义方式============//-----第一,二种函数定义方式:------字面量:   function声明:  function add(){...body...}  //这里可以不要使用分号,这是函数调用: add();
var赋值表达式:var add=function(){...body...};//这里一定要使用分号,这是语句调用: add();
var add=function fn(){...}add(); //只能在外部调用,不能再函数体内调用fn();//这么调用是错误的,fn属于局部变量,不可以在外面调用//-----第三种函数定义方式:------构造函数:申明:var fn=new Function("a","b","return a+b;");调用:fn();
//============函数定义的区别===============字面量于构造函数的区别:1,字面量定义:直观,简洁,方便书写2,构造函数:笨重,复杂,效率低(解析字符串是变量是还函数体,实例化构造函数,函数体多的时候很难看)        构造函数的定义方式复杂难懂,效率较低,一般不用它来定义函数         使用构造函数的方式定义函数,不会被提前,函数调用必须在定义之后
声明方式:var声明方式 和 function声明方式 的区别:1,使用var声明方式 是一个条语句,不会申明提前,所以最后要加分号;2,使用function声明方式 是一个函数,会被申明提前,所以最后不要加分号。3,预解析的过程的不同,如下代码:<script>//这里是预解析的时候已经定义了function add(),//所以可以提前输出:function add(){return "a";}//使用function声明的方式定义函数,声明会被提前,函数调用在定义前后都无所谓console.log(add());//输出 afunction add(){return "a";}//-----console.log(add());var add=function(){return "a";}//预解析://var add=nudefined//预解析完了再逐行执行代码。//所以add是一个变量,不能当做函数执行add();//-----var ad=function(){return "b";}console.log(ad());//预解析://var ad=undefined;//预解析完成,再重头开始逐行执行代码//给 ad 进行赋值 ad=function(){return "b";}//所以这里的 ad是一个函数 ad();</script>
//使用时怎么选择函数//构造函数 傻大黑粗效率低,一般不建议使用//var 和 function 两种都差不多,一般都是根据团队风格进行选择的。======================<script>//使用构造函数实现:21 * 32 + 24 / 3 - 5var multiply=new Function("a","b", "return a*b;");//所有参数都必须使用字符串的形式,包括函数体。// console.log(multiply("21","32"));//调用该方法时,只需要带参数即可,函数体不用写。var divide=new Function("a","b","return a/b;");//所有参数都必须使用字符串的形式,包括函数体。// console.log(divide("24","3"));//调用该方法时,只需要带参数即可,函数体不用写。var substract=new Function("a","b","return a-b;");//所有参数都必须使用字符串的形式,包括函数体。// console.log(substract("333","222"));//调用该方法时,只需要带参数即可,函数体不用写。//等价下行:var add=new Function("a","b","return +a + +b;");//+a,+b表示取正,-a表示取负,!表示取反var add=new Function("a","b","return parseInt(a)+parseInt(b);");//所有参数都必须使用字符串的形式,包括函数体。// console.log(add("22","33"));//调用该方法时,只需要带参数即可,函数体不用写。var mul=multiply("21","32");//返回:672var divide=divide("24","3");//返回:8var add=add(mul,divide);console.log(add);//返回 680var sub=substract(add,"5"); //返回 675console.log(sub);//返回 675</script>
//========函数定义的位置============//具体哪里可以访问,请使用搜狗:zuoyongyu:作用域的知识1,全局作用域function add(){...} 在哪里都可以调用
2,函数作用域//fn1()函数只能在substract函数中进行访问,不可以在全局中访问。function substract(){fn1();//可以访问function fn1(){fn1();//可以访问function fn3(){fn1();//可以访问}}fn1();//可以访问function fn2(){fn1();//可以访问}}
3,不建议在代码块中定义函数:在javascript中不存在 if/for代码块的作用域,里面的函数预解析为window全局作用域if(true){function add(argument){...}}else{function substract(argument){...}}//函数预解析时就提前声明了:window下面的属性及其方法:function add(argument){...}function abstract(argument){...}再逐行执行代码
------如果为真,就可以执行add()函数,否则就可以执行substract()函数-------if(true){var add=function(){...};}else{var substract=function(){...};}函数是在预解析之后再赋值的:var add=undefined;var substract=undefined;再逐行执行代码------B:JS中没有块级作用域,所以不会在if中发生预解析,在外部预解析的时候,if中声明的所有函数都会被提前,所以无法达到按需定义的目的。C:方法的调用必须指定对象,一般通过 对象.函数名() 的方式调用D:内部函数可以访问外部函数的变量(作用域链的机制)------
4,函数作为对象的属性值:<script>var person={name:"zheng",age:18,address:"China",setAddress:function(address){this.address=address;}};console.log(person.name);//输出:zhengconsole.log(person.name="liang");//输出:liangperson.setName=function(name){this.name=name;}//添加设置修改姓名的方法person.setName("zhu");//重新把name设置为:zhuconsole.log(person.name);//输出:zhuconsole.log(person.address);//输出:Chinaperson.setAddress("American");//重新把address设置为:Americanconsole.log(person.address);//输出:American</script><script>//如果输入两个数字类型,就相加,否则提示请输入数字类型的参数var add=function(a,b){if (isNumber(a) && isNumber(b)) {return parseInt(a)+parseInt(b);//等价:return +a + +b; 一元运算符: +取正,-取负 !取反}else{return "请输入数字类型的参数";}}function isNumber(a){return isNaN(a)?false:true;//如果isNaN(a)=true,那么返回false ,否则返回true}console.log(add("333","bbb"));console.log("33","22");</script>
//------函数的调用------<script>//命名函数的调用function add(a,b){return a*b;}add();//命名函数的调用
//匿名函数的调用//1,使用 变量名+() 进行调用var add=function(a,b){return a*b;}add();//
//2,匿名函数自我执行/*function(){console.log(1);}();在预解析时:function后面一定要跟上一个函数名称,但这里没有函数名称,所以会报错。解决办法如下:*///匿名函数自执行方法一://把匿名函数自我执行后的结果赋值给变量a即可,函数名称+()表示立即执行函数本体。/*var a =function(a,b){return 3*4}();console.log(a);
//匿名函数自执行方法二,三效果一模一样//匿名函数自执行方法二:(function(){console.log(2)}());//匿名函数自执行方法三:(function(){console.log(3)})()//匿名函数自执行方法四://!表示取反,+表示取正,-表示取负数,只要不让匿名函数的function打头,那就可以匿名函数自执行!function(){console.log(4)}();+function(){console.log(4)}();-function(){console.log(4)}();!+~-function(){console.log(4)}();//匿名函数自执行方法五:console.log(function(){return 5;}());*/
<script>(function(){function add(a,b){return a+b;}console.log(add(1,3));//而这里返回的4})();console.log(add(1,3));//这里调用报错,因为add函数是在匿名函数的作用域内,不可以当做全局变量来使用</script>
//------递归函数------5的阶乘:5*4*3*2*1//递归函数,类似于循环//1,一定有一个终结点退出函数执行//2,同理一直进行自我调用<script>function factorial(num){if (num<=1) return 1;return num*factorial(num-1);}console.log(factorial(5));
//上面的递归等同于下面的函数:/*5*4*3*2*15!5*4!5*4*3!*/var sum=1;function a(num){var i=1;while (i<=num) {sum=sum*i;i++;}return sum;}console.log(a(5));</script>
<script>//求阶乘,这里没有终止条件,值域溢出,所以死循环function factorial(num){return num*factorial(num-1);}factorial(5);</script>
<!-- 对象调用方法 --><script>var operation={//加法add:function(a,b){return a+b;},//减法substract:function(a,b){return a-b;},//乘法multiply:function(a,b){return a*b;},//除法divide:function(a,b){return a/b;},//使用不合法的字符串时,只能使用:对象["@"]()运行函数"@":function(){console.log("999");alert("1");}}//使用合法字符串命名,可以使用以下两种方法进行调用函数console.log(operation["add"](3,6));console.log(operation.add(3,6));//使用不合法的字符串时,只能使用: 对象["@"]() 运行函数operation["@"]();
var key="add";// []方括号中,有双引号的表示字符串,没有双引号的表示变量,谨记console.log(operation[key](1,3));//返回:4  这里的是变量:key="add"console.log(operation["key"]());// 返回:key  这里的key是对象operation中的方法。
//-------链式调用方法-------// $("p").html("love you forever").css("backgrond","red")...var operation={//加法add:function(a,b){console.log(a+b);return this;//返回的是operation对象},//减法substract:function(a,b){console.log(a-b);return this;//返回的是operation对象}}// operation.add(2,3); 返回的是 operation 对象// operation.substract; 返回的是 operation 对象//所以可以使用下面的链式调用,否则是不可以的。operation.add(2,3).substract(33,3);</script><script>//这是需要鼠标点击才可以调用点击方法document.onclick=function(){alert("1");}//不用点击直接调用方法,任意方法直接在方法名称后面添加 (),就会立马执行该方法document.onclick();</script><script>//什么是构造函数//普通函数有return 则返回 return后面的值,如果没有return,则返回undefined//函数名称小写用于区分:普通函数,不是严格规定//函数名称大写的用于区分:构造函数,不是严格规定 function add(a,b){return a+b;}//普通函数的调用:函数名称()add(3,4);// function Person(){...}//new Person() 用于实例化构造函数// var Obj=new Person();//Person();这么调用就是普通函数//Array();这是普通函数//Object();这是普通函数console.log(Array());//返回 []console.log(Object());//返回 {}var arr=new Array();//实例化一个数组 返回的永远是对象var obj=new Object();//实例化一个对象 返回的永远是对象
////-------实例化一个Person--------/////构造函数,顾名思义:被构造的对象也必须是一个函数。function Person(){this.name="zheng";//这里一定要使用this.属性,否则后面输出都是undefined.this.age=18;//这里一定要使用this.属性,否则后面输出都是undefined.var address="China";//实例化后,输出为undefined}var xm=new Person();//实例化一个Person对象console.log(xm);//Person {name: "zheng", age: 18} address定义错误不是属性console.log(xm.name);//输出 zhengconsole.log(xm.age);//输出 18console.log(xm.address);//输出 undefined</script>
<script>//创建一个空的Person对象var Person=function(){};//实例化Person对象var per=new Person();//给对象添加属性per.name="zheng";per.age="18";per.sex="male";//实例化一个数组var arr=new Array();//给数组arr添加属性arr[0]="zheng";arr[1]="liang";//遍历per对象并输出属性及其属性值for(var p in per){console.log(p+":"+per[p]);}//遍历数组arr并输出值for (var i = 0; i < arr.length; i++) {console.log(arr[i]);}</script><script>//------间接调用--------var name="xm";var person={};person.name="xh";person.getName=function(){return this.name;}console.log(person.getName());//输出:xh//这里的window用于改变person.getName里面的this变成:window,即返回window.name的值console.log(person.getName.call(window));//输出:xm//这里的window用于改变person.getName里面的this变成:window,即返回window.name的值console.log(person.getName.apply(window));//输出:xm
var arr=[2,5];function add(a,b){return a+b;}//直接调用console.log(add(3,6));//使用了间接调用,call(指定作用域对象,argument1,argumen2...)console.log(add.call(window,2,5));//这里间接调用了window下面的arr的数组值, apply(指定作用域对象,数组)console.log(add.apply(window,arr));//间接调用://1,对象没有call和apply方法,只有函数有//2,apply可以将数组和类数组一次性的传递进函数中,call只能一个一个的传</script>//------arguments 参数------//参数分为:实参,形参1,当参数为基本数据类型时,只是进行了复制操作,不不会修改原来的值。2,当参数为引用类型时,因为两个引用地址相同,指向同一个值。如果修改其中一个,另一个也会被修改。//三种情况:1,实参=形参<script>//函数中的参数:形式参数 实际参数function add(a,b){//这里的 a,b是形式参数,占位符的作用return a+b;}add(3,8);//这里的3 ,8 是实际参数//本质上就是复制一个副本:  形参=实参 ,对于原来的值是不改变的。// var a=3;  var b=8;
//参数为对象时,参数为引用类型,那么传递的是地址。修改一个同时也会修改另一个var person={};var setName=function(obj){//这里的参数是对象,给指定对象设置name属性obj.name="zheng";}setName(person);//这里的person是对象,给person对象设置name属性console.log(person.name);</script>
2,实参<形参<script>//求数的幂  Math.pow(base,power);function pow(base,power){return Math.pow(base,power);}console.log(pow(3,4));//返回 81console.log(pow(3,2));//返回 9
function pow(base,power){// if (!power) power=2;//如果b为空:!power=true,如果b不存在为真的,那么返回b=2.//短路操作power=power || 2;//或逻辑 一个为真即为真 如果power=power返回true,那么power=power,否则b=2;return Math.pow(base,power);}console.log(pow(4));//返回 16console.log(pow(3));//返回 9//$("p");//默认省略document//在JQuery中的参数: $("p",document):表示在文档中查找P标签。//也可指定某个对象:$("p",document.getElementById("box")),//指定id="box"的对象下面查找p标签。</script>
3,实参>形参<script>function add(){//任何函数都有返回值,返回return后面的值,如果省略return或者return后面没有值,则返回undefinedif (arguments.length==0) return;var sum=0;for (var i = 0; i < arguments.length; i++) {sum+=arguments[i];}return sum;}console.log(add()); // 返回 undefinedconsole.log(add(1,3,4));//返回 8</script><script>// 输入任意个数字参数,输出最小值function mix(){var len=arguments.length;if (len==0) return;if (len==1) return arguments[0];var mi=0;for (var i = 1; i < len; i++) {//思路决定出路// 这里是精华所在,前后对比,把较小的一个赋值给arguments[i]arguments[i]= arguments[i-1]<arguments[i]?arguments[i-1]:arguments[i];mi = arguments[i];}return mi;}console.log(mix(1,3,444,2,5245,7373,2452,-11,-23432,-234,-245));console.log(mix());console.log(mix(888))</script>
//arguments//参数是每个函数都有的,是一个局部变量//类数组对象,但不是数组的实例。可以使用arguments[index]进行取值.<script>//合法标识符:不能以数字,关键字,保留字开头,以字母,数字,下划线组成的字符串;//这里arguments的索引是 "0" 到 "5" ,数字是不合法的标识符,所以只能使用双引号。//以下就是类数组对象:var arguments={"0":"argument1","1":"argument2","2":"argument3","3":"argument4","4":"argument5","5":"argument6"};//遍历arguments类数组对象for(var p in arguments){console.log(p+":"+arguments[p]);}
//1.对象的长度不能用.length获取,用js原生的Object.keys可以获取到console.log(arguments.length);//返回 undefinedvar keys=Object.keys(arguments)//使用原生Object.keys,获取键值对中键的集合,都是数组var values=Object.values(arguments)//使用原生Object.values,获取键值对中值的集合,都是数组console.log(keys.length);//两种都可以获得对象的长度console.log(values.length);//两种都可以获得对象的长度//但是,如果arguments作为函数中的参数,是可以通过arguments.length获得实际参数个数。//函数是一个特殊对象,也可以通过add.length 获得形式参数个数<script>function add(a,b,c){console.log(arguments.length);//返回 5 调用函数是写入的实际参数console.log(add.length);//返回 3,定函数时,定义的形式参数console.log(arguments.callee.length);//返回 3 形式参数,函数固定的形式参数长度return +a + +b + +c;//一元运算符,+取正,-取负,!取反}// console.log(add(1,3,5));console.log(add(1,3,6,7,8));//返回:10 只对前面3个参数进行相加
</script>//------function fn(arguments){console.log(argument);function fn1(arguments){console.log(argument);}fn1(2);//输出2}fn(1);//输出1//arguments是每个函数中独有的,不同作用域不同//预解析:/*fn函数作用域:var argument=undefined;fn1函数作用:var argument=undefined;*/</script>//--------// "use strict" //表示使用严格模式// var num=1;//这样定义num变正确// num=1;//这样定义num变就会报错</script><script>//判断传入参数是否等于实际参数function add(a,b){//console.log(arguments.length);//返回 5实际参数,我们实际传入的参数//console.log(arguments.callee.length);//返回 2 形式参数,函数固定的形式参数// console.log(add.length);返回 2 //形式参数,函数固定的形式参数,可以在函数外面进行调用if (arguments.length!==add.length) throw new Error("请输入:"+add.length+"个参数");return a+b;}// console.log(add(2,4));//返回 6console.log(add(1,3,4,5,6));//参数不对,参数过多。返回:text2.html:13 Uncaught Error: 请输入:2个参数</script>//---------------<body>    <p id="test" style="background-color: red; color: blue;">我是一个段落!</p><script type="text/javascript"> //在使用参数给对象设置CSS属性时,都是用p.style[property]=value,这样绝对没错//如果使用p.style.property=value。读取时使用,设置时有可能会报错。var p=document.getElementById('test');function css(value,property){//必要参数一定要放在第一个,可传可不传放在后面if (arguments.length<=0 || arguments.length>=3) throw new Error("请输入:"+arguments.length+"参数");if (property==undefined) p.style.backgroundColor=value;if (arguments.length==2) p.style[property]=value;}css("orange");//第二个参数省略,默认 property=undefined// css("green","backgroundColor");</script> </body> <script type="text/javascript"> //-----什么可以当做变量-------//1,什么都不传var a=2;function fn(){function(){alert(a);}}//2,数字function fn(num){console.log(num);}fn(2);//3,字符串//4,booleanfunction a(){}function b(){}//如果传进来的是布尔值,一定使用要把细节封装成a,b函数。经验之谈。function fn(boolean){if (true) {a();}else{b();}}//5,undefinedfunction add(a,b){if (b==undefined) return a;return a+b;}console.log(add(6,undefined));//返回 NaN,非数字function pow(bace,power){//短路操作,如果power=power=true则power=power  power=undefined=false 则power=2。power=power || 2;return Math.pow(bace,power);}console.log(pow(3,6));//6,null//以上都是单个参数传递////7,传多个参数,如数组:[1,2,3,4,5]$.each([1,2,3,4,5], function(index, val) {console.log(index);console.log(val);});for (var i = 0; i < [1,2,3,4,5].length; i++) {console.log(index);console.log(val);}//8,传对象:{"a":"1","b":"2","c":"3"}$.each({"a":"1","b":"2","c":"3"}, function(index, val) {console.log(index);console.log(val);});
//下面代码使用对象作为参数进行代码优化:function setPerson(name,sex,age,add,phone){var person={};person.name=name;person.sex=sex;person.age=age;person.add=add;person.phone=phone;}//可读性,可写性不强,很容易弄错参数顺序导致错误,所以下面可以使用对象代替setPerson("zhengl","male",18,"中国China","182...");
//当参数超过三个或者三个以上,建议适用对象进行代码优化如下:var person={};function setPerson(obj){person.name=obj.name || "xh";//如果没有设置该属性,则设置一个默认值person.age=obj.age || 18;//如果没有设置该属性,则设置一个默认值person.add=obj.add || "中国China";//如果没有设置该属性,则设置一个默认值person.sex=obj.sex || "male";//如果没有设置该属性,则设置一个默认值person.phone=obj.phone || "110";//如果没有设置该属性,则设置一个默认值}//经过代码优化:对象属性不用按顺序进行书写,甚至不写都不会报错。setPerson({name:"zheng",age:18,sex:"male"// add:"中国China", 两个属性值没写,使用默认值// phone:"187" 两个属性值没写,使用默认值});console.log(person.age);console.log(person.add);console.log(person.phone);
//9,函数作为参数,就叫回调函数$.each(obj,function(){...})setInterval(function(){},1000)</script> <script type="text/javascript"> /*//--------返回值:-------- return 1,表示 函数的结束。2,表示 返回return 后面的值。如果后面没有值,则返回undefined
return 表示在函数中使用,函数返回一个值。
continue 用于循环,表示跳出本次循环,执行下一次循环
break  跳出整个循环,执行循环以外的代码*/
//1,没有返回值: 默认undefinedfunction fn(){}function fn1 () {return;//表示返回值为undefined}function fn2(a,b){if (b<0) return;//表示函数结束执行return a/b;//表示返回值}console.log(fn());//返回 undefinedconsole.log(fn1());//返回 undefined//2,数字做返回值//3,字符串作为返回值alert(1,2,3,4);返回字符串:1,2,3 alert([1,2,3,4]);//返回字符串:1,2,3 默认会隐式转换:[1,2,3,4].toString();alert([1,2,3,4].toString());返回字符串:1,2,3//4,boolea  return true/false//5,null//6,数组 返回多个值function fn(a,b){return [a+b,a,b];}//7,对象function getPerson(){return {//不用创建对象了,直接返回一个对象即可name:"zheng",age:18};}console.log(getPerson());//{name: "zheng", age: 18}
//一下代码风格要小心,return在解析时,系统会自动给return添加分号;,从而报错。/*function getPerson(){return //return在解析时,系统会自动给return添加分号;,从而报错。{name:"zheng",age:18};}console.log(getPerson());//{name: "zheng", age: 18}*///8,函数function fn(){return function (){console.log("one");}}// 返回:// ƒ fn(){// return function (){// console.log("one");// }// }console.log(fn);//返回:ƒ (){ console.log("one"); }console.log(fn());//返回:oneconsole.log(fn()());//------document.write([1,3,5]);//返回 1,3,5 进行了隐式转换[1,3,5].toString();document.write({"name":"zheng","age":18,toString:function(){document.write("love");}});//返回:[object Object]console.log({"name":"zheng","age":18,function(){document.write("love");}});//返回:{name: "zheng", age: 18, function: ƒ}
/*为了写出更优雅的函数,会将函数作为参数传递到另一个函数中,组成一个新功能的函数:两个功能:1,传进来函数的功能。2,接收函数的功能。一个函数实现一个功能,把多个函数组合成一个新的函数,就实现了一个复合的功能。*/</script>    //------关于局部作用域,调用一次就创建一次,也删除一次-------<script type="text/javascript"> function count(){ var num=1; return function(){ return num++;//先返回 num,再num+1 // return ++num;//先num+1,再返回 num } } console.log(count()());//每次调用普通函数,都会创建一个新的局部作用域,函数执行完连被删除 console.log(count()());//每次调用普通函数,都会创建一个新的局部作用域,函数执行完连被删除 console.log(count()());//每次调用普通函数,都会创建一个新的局部作用域,函数执行完连被删除 var fn=count();//这里只调用一次函数,只开辟一个局部作用域,所以里面的num执行几次就会加1几次。 console.log(fn());//fn()=count()(); console.log(fn());//fn()=count()(); console.log(fn());//fn()=count()(); //返回:1 ,1 ,1 ,1 ,2 ,3  // 1、 count()()这样调用,每次都会创建一个新的局部作用域,num的值会不断地被初始化为1
 // 2、 return num++表示先返回num的值,再将num加1
 // 3、 先将count()赋给fn,此时count()只调用了一次,接下来多次调用fn()的时候,count函数并没有多次调用,num只会在count函数调用的时候被初始化,所以多次调用fn()的时候num不会被多次初始化;由于fn相当于count函数的内层函数(var fn=count();这行代码执行后,就调用了count(),调用count后就将里面的函数赋值给了fn,所以说fn就相当于函数的内层函数了。),可以访问count中的变量num,所以多次调用fn函数,会将num的值累加;</script> 

原文地址:https://www.cnblogs.com/Knowledge-is-infinite/p/11311575.html