一、定义函数的3种方式
1、定义命名函数的语法格式如下:
function functionName(parmeter-list)
{
statements
}
函数可以有返回值,也可以没有返回值。函数的返回值使用return语句返回,在函数的允许过程中,一旦遇到第一条return语句,函数就返回返回值,函数运行结束。
2、定义匿名函数
创建匿名函数的语法格式如下:
function (parmeter-list)
{
statements
};
这种函数定义语法无须指定函数名,而是将参数列表紧跟function关键字,但是最后要跟一个分号(;)。
例:
<script type="text/javascript">
var a = function(name){
document.writeln('你好'+name);
};
a('yeeku');
</script>
定义一个匿名函数,也就是定义了一个Function对象;接下来将这个函数赋值给另一个变量a,后面就可以通过a来调用这个匿名函数了,这种语法可读性非常好;如果将有名字的函数赋值给某个变量,那么原来为该函数定义的名字将会被忽略。
3、使用Function类匿名函数
JavaScript提供了一个Function类,该类也可以用于定义函数,Function类的构造器(方法)的参数个数可以不受限制,Function可以接受一系列的字符串参数,其中最后一个字符串参数是函数的执行体,执行体的各语句以分号(;)隔开,二前面的个字符串参数则是函数的参数(可读性不好,当执行体语句过多时,会很臃肿,不建议使用)
二、递归函数
递归函数时一种特殊的函数,递归函数允许在函数定义中调用函数本身。
例:
<script type="text/javascript">
var factorial = function(n){
if(typeof(n) == "number"){
if(n==1){
return 1;
}
else{
return n * factorial(n-1);
}
}
else{
alert("参数类型不对");
}
}
alert(factorial(5));
</script>
三、局部变量和局部函数
局部函数就是在函数里定义,只在包含此局部函数的函数内部有效。
四、函数、方法、对象、变量、和类
定义一个Person的函数,也就是定义了一个Person的类,该Person函数也会作为Person类的唯一构造器
例:
<script type="text/javascript">
function Person(name,age){
this.name = name;
this.age = age;
this.info = function(){
document.writeln("我的名字是:" + this.name + "
");
document.writeln("我的年纪是:" + this.age + "
");
};
}
var p = new Person('yeeku',29);
p.info();
</script>
五、函数的实例属性和类属性
(实例属性是单个对象所有,必须通过对象来访问;类属性是一个类(函数)中本身的,所以必须通过类(函数)来访问)
例:
<script type="text/javascript">
function Person(national,age){
this.age = age;
Person.national = national;
var bb = 0;
}
var p1 = new Person('中国',29);
document.writeln("创建一个Person对象
");
document.writeln("p1的age属性为" + p1.age + "
");
document.writeln("p1的national属性为"+p1.national+"
");
document.writeln("创建一个Person对象
");
document.writeln("通过Person访问静态national属性为"+Person.national +"
");
document.writeln("p1的bb属性为"+p1.bb+"
");
var p2 = new Person('美国',32);
document.writeln("创建两个Person对象之后
");
document.writeln("p1的age属性为" + p1.age + "
");
document.writeln("p1的national属性为"+p1.national+"
");
document.writeln("p2的age属性为" + p2.age + "
");
document.writeln("p2的national属性为"+p2.national+"
");
document.writeln("通过Person访问静态national属性为"+Person.national +"
");
</script>
JavaScript是一种动态语言,它允许随时为对象增加属性和方法,当直接为对象的某个属性赋值是,就可以看成个对象增加属性
六、调用函数的3种方式
1、直接调用函数
例:
//调用window对象的alert方法
window.alert("测试代码");
//调用p对象的walk方法
p.walk()
(当程序使用window对象来调用方法时,可以省略前面的window调用者)
2、以call()方法调用函数
call()方法调用函数的格式:
函数引用.call(调用者,参数1,参数2...)
直接调用函数与call()方法调用函数的关系如下:
调用者.函数(参数1,参数2...) = 函数.call(调用者,参数1,参数2...)
例:
<script type="text/javascript">
var each = function(array,fn){
for(var index in array){
fn.call(window,index,array[index]);
}
}
each([4,20,3],function(index,ele){
document.write("第" + index + "个元素是:" + ele + "
");
});
</script>
3、以apply()方法调用函数
apply()方法与call()方法基本类似,但有两点区别:
通过call()调用函数时,必须在括号中详细的列出每个参数。
通过apply()动态的调用函数时,需要以数组形式一次性传入所有调用参数。
apply()方法与call()方法的对应关系如下:
函数引用.call(调用者,参数1,参数2...) = 函数引用.apply(调用者,[参数1,参数2...])
七、函数的独立性
JavaScript的函数永远是独立的,函数永远不会从属其他类、对象。
例:
<script type="text/javascript">
function Person(name){
this.name = name;
this.info = function(){
alert("我的name是:"+this.name);
}
}
var p = new Person("yeeku");
p.info();
var name = "测试名称";
p.info.call(window);
</script>
结果:
当使用匿名内嵌函数定义某个类的方法时,该内嵌函数一样是独立存在的,该函数也不是作为该类实例的附庸存在,这些内嵌函数也可以被分离出来独立使用,包括另一个对象的函数。
八、函数提升
在JavaScript中允许先调用函数,然后在定义函数;如果是匿名函数的话,函数提升只会提升被赋值的变量,而函数本身不会被提升,局部匿名函数同理(注意,如果匿名函数被赋值的变量没有使用var声明,那么该变量就会是一个全局变量,因此该函数就昂辉变成一个全局函数);
如果变量名和函数名同名了,会出现以下两种结果:
1、定义变量时只用了var定义,没给初始值,这个时候函数的优先级高,函数会覆盖变量;
2、定义变量时给初始值了,变量的优先级就会更高,变量就会覆盖函数。
(无论是先定义函数还是先定义变量,都遵循以上两种结果)
九、箭头函数
箭头函数的语法格式如下:
(paraml1,paraml2,...,paramlN) => {statements}
相当于定义了以下函数:
function(paraml1,paraml2,...,paramlN)
{
statements
}
如果箭头函数只有一条return语句,就可以省略函数执行体的花括号和return关键字,如下:
(paraml1,paraml2,...,paramlN) => expression
//等同于:(paraml1,paraml2,...,paramlN) => { return expression;}
如果箭头函数的形参列表只有一个参数,则允许省略形参列表的圆括号。
(singleParam) => {statements}
//等同于:singleParam => {statements}
例:
<script type="text/javascript">
var arr = ["yeeku","fkit", "leegang", "crazyit"];
var newArrl = arr.map(function(ele){
return ele.length;
});
var newArr2 = arr.map((ele) => {
return ele.length;
});
var newArr3 = arr.map(ele => ele.length);
console.log(newArr3);
arr.forEach(function(ele){
console.log(ele);
});
arr.forEach((ele) => {
console.log(ele);
});
arr.forEach(ele => console.log(ele));
</script>
结果:
F12查看结果
(如果函数不需要形参,那么箭头函数的形参列表的圆括号不可以省略)
与普通函数不同的是,箭头函数并不拥有自己的this关键字,箭头函数中的this总是代表包含箭头函数的上下文;
例:
<script type="text/javascript">
function Person() {
this.age = 0;
setInterval(() => {
console.log(this === window);
this.age++;
},1000);
}
var p = new Person();
setInterval(function(){
console.log(p.age);
},1000);
</script>
(如果直接在全局范围内定义箭头函数,那么箭头函数的上下文就是window本身)
箭头函数并不绑定arguments,因此不能再箭头函数中通过arguments来访问调用箭头函数的参数。箭头函数中的arguments总是引用当前上下文的arguments。
例:
<script type="text/javascript">
var arguments = "yeeku";
var arr = () => arguments;
console.log(arr());
function foo()
{
var f = (i) => 'Hello,' + arguments[0];
return f(2);
}
console.log(foo("yeeku", "fkit"));
</script>
箭头函数容易导致如下错误:
1、程序会将对象的花括号当成函数解析体的花括号,索引需要给对象加上圆括号。
2、箭头函数不允许在形参列表和箭头直接包含换行。
3、当有运算符时,需要把箭头函数放在圆括号里,避免和运算符混淆