函数,函数,function,function,go go go!
创建函数:
第一种:function aa(){alert(1)};
第二种:var aa=function(){alert(1)};
其实对于使用没有太大的区别,第一个是用函数关键字创建,第二个是创建变量,然后赋值为一个函数。
同样我们还可以创建匿名函数
function(){alert(1)};
函数的里面可以传递参数arg
function aa(arg){alert(arg)};
function aa(arg1,arg2){var num=arg1+arg2;alert(num)};
调用函数:
aa();
其他的调用方式
立即执行函数
(function aa(){alert(1)})();
给定义的函数套上(),后面再加上(),函数就会被立即执行了
有参数的也是一样
立即执行匿名函数
(function(){alert(1)})();
函数参数:
定义函数的参数我们叫他形参,相当于变量的作用,调用函数,里面的就是实参,具体的内容
我们来一段测试:
function aa(arg1){ alert(arg1) }; aa(123);
我们定义函数aa,里面用arg1这个形参接受调用函数实参的内容,执行后,弹出123;
参数除了是js提供的字符和数字外,我们在做一个测试:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <style type="text/css"> *{ margin:0; padding:0;} .fou{ color:#fff;} </style> <script src="js/jquery-min.js"></script> <title>demo</title> </head> <body> <div class="demo">demo</div> </body> <script type="text/javascript"> function aa(arg1){ alert(arg1.html()); }; aa($(".demo")); </script> </html>
看来可以传入dom对象,假如不可以,js就不会有dom、bom、es组成了。
这次我传入一个函数试试,函数里面执行参数函数,代码
function aa(arg1){ arg1(); }; aa(function(){alert(111)});
调用aa的时候,我们传入的函数成功执行了,看来参数可以是函数
我们介绍函数内部自动产生的新对象 arguments
参数对象是伪数组类型,我们看成数组就行了,具有length属性,输出参数的个数,
arguments[0] 第一个参数
arguments[1] 第二个参数
arguments[2] 第三个参数
arguments[3] 第n各参数
我们可以看出,我们函数定义的形参,会自动赋给arguments,按照顺序;我们看代码
function aa(arg1){ alert(arguments[0]) }; aa(123);
借助参数对象,我们把实参内容成功输出,我们多几个参数,代码如下
function aa(arg1,arg2,arg3){ alert(arguments[2]) alert(arguments.length) }; aa(123,456,789);
参数对象下标为2是第三个参数内容,同样长度也是3个,全部正确
我们知道参数对象具有length属性,可以判断函数参数的参数个数,它还具有一个指针属性,arguments.callee
函数内部调用此属性,指向函数本身,也就是得到了本身函数,我们看下面代码:
function aa(arg1){ if(arg1>8){ arguments.callee(arg1-1); }else{ alert(arg1) }; }; aa(9);
我们的函数是输出参数内容,我们如果不满足条件,执行里面
arguments.callee(arg1-1);
最后输出了8,可见这个属性的调用代表了函数本身,我们再看一段代码
function aa(arg1){ if(arg1<1){ return 1; }else{ return arg1+arguments.callee(arg1-1); }; }; alert(aa(9));
实现了1-9的相加,这就是递归函数,根据条件的临界,去不断调用函数本身
函数集合:
我们把定义的n个函数,放在一个数组里
var arrayfun=[]; arrayfun[0]=function(){}; arrayfun[1]=function(){}; arrayfun[2]=function(){};
这样做其实是很少见的,
我们这么写的用意就是表示这些函数具有类似的处理功能,不过过几天可能就忘记哪个是哪个了,谁让下标是0 1 2,我们在定义函数的时候,函数名往往就是功能的拼写,我们借助object对象,实现函数的关系相同整合
var cumputer={} cumputer.add=function(){}; cumputer.inc=function(){}; cumputer.chu=function(){}; cumputer.cheng=function(){};
首先,这一组函数用于就是计算,然后定义了加减乘除,这里面的cumpter就相当于一个钩子,我们用什么了,通过这个钩子去调用。
构造函数(类):
最基本的构造函数定义,构造函数的首字母大写,这不是必须的,但是为了区别普通函数我们还是最好大写
function Perple(name,sex){ this.name=name; this.sex=sex; this.showname=function(){ alert(this.name) }; }; var people1=new Perple("jack","男"); alert(people1.name); alert(people1.sex); people1.showname();
我们创建了people构造函数,也就是俗称的类。我们通过构造函数实例化对象,是通过new关键字
this作为构造函数的指针,会指向我们new的对象,这样new的对象就可以调用类里面的属性和方法。
我们结合jq,做一个改变标签宽度构造函数
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <style type="text/css"> *{ margin:0; padding:0;} .fou{ color:#fff;} </style> <script src="js/jquery-min.js"></script> <title>demo</title> </head> <body> <div class="dd" style="width:200px; height:50px;background:#ffa;">我的宽度是200</div> </body> <script type="text/javascript"> function Gwidth(obj,width){ this.obj=obj; this.width=width; this.ggwidth=function(){ obj.css('width',this.width); }; }; var Gwidth1=new Gwidth($('.dd'),'300'); Gwidth1.ggwidth(); </script> </html>
这样我我们就可以做指定的处理了,针对jq的dom元素
构造函数-原型:
函数会有一个prototype属性,就是原型属性,这个原型属性指向原型对象,原型对象具有constructor属性,这个属性指向构造函数;
我们通过原型属性,可以添加共享的属性和方法,看代码
function Gwidth(obj,width,height){ this.obj=obj; this.width=width; this.height=height; this.ggwidth=function(){ this.obj.css('width',this.width); }; }; Gwidth.prototype.ggheight=function(){ this.obj.css('height',this.width); }; var Gwidth1=new Gwidth($('.dd'),'300','200'); Gwidth1.ggheight();
我们利用原型属性,添加了改变高度的方法,我们同样新建对象,可以调用它。
我们输出新建对象的构建者属性,看看是否指向了Gwidth函数
alert(Gwidth1.constructor)
输出了整个构造函数,下面我们输出原型属性得到的原型属性的构建者属性
alert(typeof Gwidth.prototype) alert(Gwidth.prototype.constructor)
发现,函数的原型属性是一个对象,证明了调用原型属性,得到了原型对象
我们输出原型属性的构建者属性,返回了构造函数,构造函数新建的对象的构建者属性也会返回构造函数,说明原型属性得到的对象和新建的而对象通过构建者属性,指向了同一个地方,进而得到了,给原型添加属性和方法相当于同样给新建对象添加了属性和方法。从而证明了给原型属性添加的属性和方法,其实会先得到原型对象,自动调用构造者属性,指向了构造函数,所以添加的属性和方法也就相当于添加到了构造函数上,我们新建实例,就可以调用通过构造函数的属性和方法,同理也可以调用了原型属性的方法和属性。
并且通过原型属性添加的属性和方法放构造函数外!
我们运用学到的构造函数和原型,封装一个类似jq的类库,不过我们的会非常的单一化:
我们只能进行id的选择,选择提供显示和隐藏还有内容的设置,就这这么简单,我们先做第一步,
提供id的选择,毫无疑问,id就是我们的参数,构造函数执行就会返回id的dom节点,代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <style type="text/css"> *{ margin:0; padding:0;} .fou{ color:#fff;} </style> <script src="js/jquery-min.js"></script> <title>demo</title> </head> <body> <div id="ida" style="width:200px; height:50px;background:#ffa;">我我我</div> </body> <script type="text/javascript"> function Jseo(id){ this.obj=document.getElementById(id); }; var ida=new Jseo("ida"); alert(ida.obj.innerHTML) </script> </html>
我们测试发现,新建对象后,调用他的obj属性就得到了我们div元素,我们通过原型给他加点操作函数。比如把display设置为none的hide()和设置为block的show()方法
js部分下:
function Jseo(id){ this.obj=document.getElementById(id); }; Jseo.prototype.show=function(){ this.obj.style.display="block"; }; Jseo.prototype.hide=function(){ this.obj.style.display="none"; }; var ida=new Jseo("ida"); ida.hide();
默认情况下div是显示的,我们调用了自己方法,在开始就让他none掉了,
对象+事件+方法才是最常用的操作,我们里面还需要把事件封装进去,我们就封装一个click事件,做实例演示;代码
function Jseo(id){ this.obj=document.getElementById(id); }; Jseo.prototype.show=function(){ this.obj.style.display="block"; }; Jseo.prototype.hide=function(){ this.obj.style.display="none"; }; Jseo.prototype.on=function(ev,fun){ this.obj.addEventListener(ev, fun); }; var ida=new Jseo("ida"); ida.on("click",function(){ alert(1) });
添加一个click事件,我们点击弹出了1;我们要更复杂的操作,结合前面的方法,我们再点击后让自己none,看代码
function Jseo(id){ this.obj=document.getElementById(id); }; Jseo.prototype.show=function(){ this.obj.style.display="block"; }; Jseo.prototype.hide=function(){ this.obj.style.display="none"; }; Jseo.prototype.on=function(ev,fun){ this.obj.addEventListener(ev, fun); }; var ida=new Jseo("ida"); ida.on("click",function(){ ida.hide(); });
实现了,点击使我们的封装,这个none也是自己的封装,我们再添加改变里面内容的方法,叫html(),不断靠近jq的使用方式
function Jseo(id){ this.obj=document.getElementById(id); }; Jseo.prototype.show=function(){ this.obj.style.display="block"; }; Jseo.prototype.hide=function(){ this.obj.style.display="none"; }; Jseo.prototype.html=function(text){ this.obj.innerHTML=text; }; Jseo.prototype.on=function(ev,fun){ this.obj.addEventListener(ev, fun); }; var ida=new Jseo("ida"); ida.on("click",function(){ ida.html("666"); });
点击后内容变为设置的值。
函数继承:
我们通过原型属性,可以给函数实现继承,还有另外2个方法,可是实现继承call和apply
call 方法
调用一个对象的一个方法,以另一个对象替换当前对象。
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
参数
thisObj
可选项。将被用作当前对象的对象。
arg1, arg2, , argN
可选项。将被传递方法参数序列。
说明
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
第一个参数是对象,也就是我们的替换对象,这个可选,不写的话就为null;我们测试一次
我们创建一个people的构造函数,里面具有showname的方法,我们创建一个man方法,里面没有方法,我们通过call去继承前面people提供的方法
function People(name){ this.name=name; this.showname=function(){ alert(this.name) } }; var peo1=new People("tom"); peo1.showname();
构造函数成功添加showname,我们创建第二个构造函数,新建对象
function Man(name){ this.name=name; }; var man1=new Man("joke");
我想要显示出man1的名字,我们call一次,
function People(name){ this.name=name; this.showname=function(){ alert(this.name) } }; var peo1=new People("tom"); function Man(name){ this.name=name; }; var man1=new Man("joke"); peo1.showname.call(man1);
成功弹出joke,我们新建了man,并且通过call替换了前面的peo1调用他的showname方法成功。
其实call的这个时候,可以看成代码变成这样了:
function Man(name){
this.name=name;
this.showname=function(){
alert(this.name)
}
};
我们知道,call可以传入参数,我们做个测试
function People(name){ this.name=name; this.showname=function(con){ alert(con) } }; var peo1=new People("tom"); function Man(name){ this.name=name; }; var man1=new Man("joke"); peo1.showname.call(man1,123);
原来call的参数,就相当于给调用的方法加了参数,
apply与call的区别就在参数,一个是正常的,一个是数组的形式,我们看下面apply的实例
function People(name){ this.name=name; this.showname=function(con1,con2,con3){ alert(con3) } }; var peo1=new People("tom"); function Man(name){ this.name=name; }; var man1=new Man("joke"); peo1.showname.apply(man1,[123,456,789]);
这感觉和,隔开没有区别,其实参数是数组,可以看出,最后也要分割成,隔开的样子,不然我们的con3就不可能代表数组第三项789了。
原生构造函数:
什么叫原生,当然就是写好的,让我们直接可以用的,正如我说的,构造函数在js里面就是类的作用,原生构造就是已经定义了的类,类我们也管他叫类型,js的类型有数字,字符串,布尔,null,undifind,还有数组和object类型
var num=123; 创建数字对象
var str="women" 创建字符串对象
var array=[123,456] 创建数组对象
var obj={con:"llll",show:function(){alert(1)}} 创建object对象
这是我们最常见的创建方式,同样,我们还应该看见过
var array=new (123,456)和
var obj=new object(); 的形式去创建数组和object类型
看到这里是不是和我们上面介绍的创建构造函数,去实例对象一样了。
new Array();和 new Object(); 就是在实例对象,可以创建的时候赋值,也可以随后赋值
我们先以数组的实例化为案例,随后处理object类型
我们用new的方式新建一个数组
var arr=new Array(123,456,789); alert(arr[1])
我们知道数组有一个slice获取子数组方法,我们输出
var arr=new Array(123,456,789); var arr1=arr.slice(0,1) alert(arr1)
我们知道数组提供了很多的方法,我们现在要实现一个数组排序后,获取从0开始,长度为2的子数组
当然我们可以这样做
var arr=new Array(333,111,222,999,555,666); arr.sort(); var arr1=arr.slice(0,2) alert(arr1)
看起来没问题,确实没问题的,不过我希望和sort一样,数组的有一个sortslice方法,
我们知道构造函数可以通过原型属性继承和添加共享的方法,以前都是在自定义构造函数中,其实对于这样原生构造函数同样适用
看下面代码:
Array.prototype.sortslice=function(){ this.sort(); var arr1=this.slice(0,2) alert(arr1) } var arr=new Array(333,111,222,999,555,666); arr.sortslice();
通过对array类型的原型属性添加,我们实现了理想的操作
原型定义的函数里面,this作为指针,同样指向实例的对象,就是arr了。
我们其实常见的对数组操作还有求出最大值和最小值,其实我们排序后比较也可以出来,不过js有一个Math对象,他天生就有求最大值和最小值的方法
Math.max(arg1,arg2...argn) 求出参数中的最大值或最小值
Math.min(arg1,arg2...argn)
alert(Math.max(123,4,789,852));
输出了852,既然这里有了,我们在对数组去写,就有些多此一举了,我们知道call和apply可是实现这种继承的调用,既然是数组,我们肯定选择apply了,他的参数就是数组
var arr=[123,8888,955,44]; alert(Math.max.apply(null,arr))
我们运用apply只是使用math的最大方法,没有什么新对象和就对象的替换处理,第一个参数还必须写,我们就用null做空站位,他爱指向谁指向谁去吧!
有人会说我很不理解,新对象为啥为null,好了,我们按着思路处理,就是array的对象替换math好了,
var arr=[123,8888,955,44]; alert(Math.max.apply(arr,arr))
我们知道对数组循环采用的是for循环
var arr=[123,8888,955,44]; for(var i=0;i<arr.length;i++){ alert(arr[i]) }
除了for的循环输出,js还提供了更高级的for in处理
var arr=[123,8888,955,44]; for(var i in arr){ alert(arr[i]) }
比for要简洁的多,in关键字前面定义的变量会接收到每一个遍历到的下标
我们介绍的主要目的就是实现对object类型的循环处理
我们定义一个object对象,输出
var obj={name:"tom",sex:"男",year:"1991"}; for(var i in obj){ alert(obj[i]) }
函数模式:
其实我们已经介绍到大部分函数模式了,我们回忆以前并添加最新的常用模式
构造模式:
function Perple(name,sex){ this.name=name; this.sex=sex; this.showname=function(){ alert(this.name) }; };
构造加原型继承模式:
function Gwidth(obj,width,height){ this.obj=obj; this.width=width; this.height=height; this.ggwidth=function(){ this.obj.css('width',this.width); }; }; Gwidth.prototype.ggheight=function(){ this.obj.css('height',this.width); }; var Gwidth1=new Gwidth($('.dd'),'300','200'); Gwidth1.ggheight();
伪对象模式:
var cumputer={} cumputer.add=function(){}; cumputer.inc=function(){}; cumputer.chu=function(){}; cumputer.cheng=function(){};
这里需要介绍一下this指针,我们知道添加事件生成的this指向添加事件的节点,构造函数的this指向新建对象
object对象的this指向的就是object对象本身
我们测试代码:
var obj={name:"tom",sex:"男",year:"1991"}; obj.showname=function(){ alert(this.name); } obj.showname();
输出了obj的name键值
工厂模式:
工厂模式在函数内部新建object对象,返回object对象;看代码:
function gc(name,sex){ var obj=new Object(); obj.name=name; obj.sex=sex; return obj; } var gc1=gc("dom","男") alert(gc1.name)
门脸模式:
我们先写一个构造函数,并且实例化
function Perple(name,sex){ this.name=name; this.sex=sex; this.showname=function(){ alert(this.name) }; }; var peo1=new Perple("joke","男"); peo1.showname();
我们是不是看见new感觉很不顺眼,一直的new啊,new啊,我们门脸模式就是用函数屏蔽掉这个new,还能正确执行
function people(name,sex){ function Perple(name,sex){ this.name=name; this.sex=sex; this.showname=function(){ alert(this.name) }; }; var peo=new Perple("joke","男"); return peo; }; var peo1=people("joke","男"); peo1.showname();
我们在门脸函数内部,定义构造函数,然后实例化对象,返回出这个new的对象,同样参数也是通过门脸函数传递下去
这样我们在执行门脸函数同时就获取了实例的对象,就可以屏蔽掉new关键字了,在调用的部分。
函数还有很多模式,如单例模式等!