JS杂谈系列-函数知识、函数模式

函数,函数,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个方法,可是实现继承callapply

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关键字了,在调用的部分。

函数还有很多模式,如单例模式等!

你可能感兴趣的:(js,函数定义,函数模式)