1、函数基本知识
通过函数可以封装任意条语句,在任何地方调用,js中用function关键字来声明,
???????//基本格式,函数名,传递参数,代码块 ???????function functionName(arg0,arg1,arg2,……,argN){ ????????????statements ???????} ???????????????//实例 ???????function sayHi(name,message){ ?????????????console.log("hello "+name+","+message) ???????} ???????sayHi("double","how are you") ???//普通的函数名调用函数 ???????function sum(numb1,numb2){ ????????????return numb1+numb2; ????????????console.log("find me ?") ???//因为之前有return,所以不会再执行 ???????} ???????var result=sum(1,2); ????????????//声明变量的做法来调用函数 ???????function summ(numb1,numb2){ ?????????????return; ???????????????????//return可以不带任何返回值,这时候会返回undefined ?????????????console.log("hello") ???????} ???????function diff(numb1,numb2){ ?????//一个简单的比较函数 ????????????if(numb1<numb2){ ?????????????????return numb2-numb1; ????????????} ????????????else{ ?????????????????return numb1-numb2; ????????????} ???????}
1.1理解参数
js中的参数在其内部使用一个数组表示,所以无论参数的数据类型,个数都没关系,而且参数也不一定会用上的。
函数体内可以通过arguments对象访问到参数的数组,从而获得每一个参数。arguments对象和数组相似,可以中括号表示,有length;
参数名不是必须的,为了方便而已,也可以通过arguments[0]访问到
???????function change(){ ???????????console.log(arguments.length) ???????} ???????var zero=change() ????????//0 ?????可以通过length来展现 ???????var one=change("one") ????//1 ???????var two=change("two",2) ??//2 ???????????????//没有参数名 ???????function doAdd(){ ???????????if(arguments.length==1){ ???????????????console.log(arguments[0]+10); ???????????}else if(arguments.length==2){ ???????????????console.log(arguments[0]+arguments[1]) ???????????} ???????} ???????doAdd(1) ?????//11 ???????doAdd(1,2) ???//3 ???????//有参数名 ???????function anotherAdd(num1,num2){ ???????????if(arguments.length==1){ ????????????????console.log(num1+10); ???????????}else if(arguments.length==2){ ????????????????console.log(num1+num2) ???????????} ???????} ???????anotherAdd(1) ???//11 ???????anotherAdd(1,2) ?//3 ???????function again(num1,num2){ ???????????arguments[1]=10; ???????//这里num2的值也就变成10,arguments的值与对应命名参数的值保持同步,内存空间还是独立的;没有传递值得命名参数为undefined ?????????????????????console.log(arguments[0]+num2) ???????}
1.2没有重载
所谓的没有重载就是说,不可以为函数两个定义,因为js的参数是数组,没有签名,做不到真正的重载。两个相同的函数则以后一个为准。
Function类型
也是引用类型,每个函数就是Function类型的实例,都与其他引用类型具有相同的属性和方法。函数为对象,所以函数名只是指向函数对象的指针。
声明变量有两种方式。看例子吧。
?????function sum(num1,num2){ ????//函数声明来定义函数 ???????????return num1+num2 ?????} ?????var sum=function(num1,num2){ ?//函数表达式定义函数 ???????????return num1+num2 ?????} ?????//函数名仅仅为指针;所以也能理解上面所说的函数没有重载 ?????function one(num1,num2){ ??????????return num1+num2 ?????} ?????var two=one ?????var one=null ?????console.log(two(1,2)) ???//3 ?即使one为null
函数声明和函数表达式之间的相爱相杀
解析器对他们两个态度可是不同的
对于函数声明,解析器会优先读取,对其有个函数声明提升的过程(function declaration hoisting)
对于函数表达式,解析器可就不会优先了,只有读取到其,才会被解释执行
?????console.log(sum(1,2)) ???????//3 ?????function sum(num1,num2){ ????????????????return num1+num2 ?????} ?????console.log(another(1,2)) ???//another is not a function ?????var another=function(num1,num2){ ???????????return num1+num2 ?????}
当然还有构造函数法,不推荐使用,导致代码的二次解析,一次是常规js的,一次是构造函数的
也就是函数可以作为值传参
????function sum(someFunction,value){ ???????//基本的函数中的嵌套 ????????????return someFunction(value) ????} ????function multiplys(num){ ????????????????//内部的函数 ???????????return num*num ????} ????console.log(sum(multiplys,2)) ???????????//调用函数,访问内部函数的指针,不需要()调用
利用作为值得函数,可以按照某一属性对数组进行排序
????function compare(value){ ????????????????//想要通过比较obj的属性,这里的value只是参数,没有被实例化;而在简单的数组中都已经被实例化了 ??????????return function(obj1,obj2){ ?????????????var value1=obj1[value] ?????????????var value2=obj2[value] ?????????????return value1-value2 ??????????} ????} ????var data=[{name:"double",age:24},{name:"zom",age:23},{name:"mike",age:32}] ????data.sort(compare("age")) ????console.log(data) ????????//23,,24,32来排序
2、函数内部的属性
在函数的内部,一般有两个对象
this对象:this引用的是函数执行的环境对象,即this值(在全局环境中,this则代表的是window)
arguments对象:类数组对象,保存函数参数;有个callee属性,此属性是个指针,指向拥有arguments对象的函数
ES5规定了另个一个函数对象的属性caller,保存着调用当前函数的函数引用,在全局作用域中调用当前函数则为null
????//递归函数 ????function sum(num){ ?????????if(num<=1){ ?????????????return 1 ?????????} ?????????else{ ?????????????return num*arguments.callee(num-1) ????//消除紧紧耦合,保证完成递归函数,所以用callee属性 ?????????} ????} ????var summ=sum; ????sum=null ????console.log(summ(10)) ???//this ???window.color="red" ???function sayColor(){ ????????console.log(this.color) ???} ???sayColor() ???????????????????//red ???var another={color:"blue"} ??????another.putColor=sayColor ????//函数名只是个指针 ???another.putColor() ???????????//blue ?//函数对象属性caller ?function outer(){ ?????inner() ?} /* ?function inner(){ ?????console.log(inner.caller) ?}*/ ?function inner(){ ?????console.log(arguments.callee.caller) ???//减少耦合 ?} ?outer() ????????????//outer()函数
3、函数的属性和方法
每个函数有两个属性
length属性:表示函数的参数名个数
prototype属性:保存引用类型所有实例方法,不可枚举,用for-in无法实现
每个函数都包含两个非继承的方法;都是在特定的作用域中调用函数,实际等于设置函数体内this对象的值
apply()方法:接受两个参数,一为在其中运行函数的作用域,一为参数数组(Array的实例或者arguments对象)
call()方法:接受的第一个参数是this值没变化,第二个不是数组了,直接传递给参数即可,看例子吧
??function sum(num1,num2){ ??????return num1+num2 ??} ??function oneSum(num1,num2){ ??????return sum.apply(this,arguments) ????????//arguments对象 ??} ??function twoSum(num1,num2){ ??????return sum.apply(this,[num1,num2]) ??????//数组 ??} ??console.log(oneSum(1,2)) ??console.log(twoSum(1,2)) ??function three(num1,num2){ ??????return sum.call(this,num1,num2) ?????????//参数直接传递 ??} ??console.log(three(1,2,3)) ??????//apply()和call()方法可以扩充函数的作用域 ?window.color="red" ?var one={color:"red"} ?function sayColor(){ ?????console.log(this.color) ?} ??sayColor() ?????????????????//red ?sayColor.call(this) ????????//red ?sayColor.call(window) ??????//red ?sayColor.call(one) ?????????//blue ??这里的作用域为one中的了,不需要再将函数放到one中等操作
ES5规定还规定一个方法bind(),创建一个函数实例,其this值被绑定到传给bind()函数的值,
?window.color="red" ?var one={color:"blue"} ?function sayColor(){ ?????console.log(this.color) ?} ?var another=sayColor.bind(one) ????//ES5的函数方法,创造一个函数实例了,并且绑定的this值传递给函数了 ?another() ?????????????????????????//blue
js函数知识
原文地址:https://www.cnblogs.com/iDouble/p/8372468.html