函数
定义函数的3种方式
javascript 是弱类型语言,因此定义函数时既不需要声明函数返回值类型,也不需要声明函数的参数类型。
1.定义命名函数
语法格式如下:
function functionName(parameter-list)
{
statements
}
2.定义匿名函数
语法格式如下:
function(parameter-list)
{
statements
};
这种函数定义无需指定函数名,而是将参数列表紧跟function关键字。最后加分号。
通过这种方法定义函数后,实际上就是定义了一个函数对象,接下来可以将这个对象赋给另一个变量,如下:
var f=function(parameter-list)
{
statements
};
3.使用function类匿名函数
javascript提供了一个一个 Function类,该类也可以用于定义函数,Function类的构造器参数个数不受限制,Function 可以接受一系列的字符串参数,其中最后一个字符串参数是函数执行体。例句如下:
var f=new Function('name',"document.writeln('你好')"+"document.writeln('hello'+name)");
递归函数
递归函数是一种特殊函数,允许在函数定义中调用函数本身。
例:进行如下计算:n!=n*(n-1)*(n-2)…*1
代码如下:
var factorial=function(n)
{
if(typeof(n)=="number")
{
if(n==1)
{
return 1;
}
else
{
return n*factorial(n-1);
}
}
else
alert("参数类型不对");
}
函数、方法、对象、变量和类
函数是javascript的“一等公民”,是javascript编程里非常重要的概念。当使用javascript定义一个函数后,实际上可以得到如下四项:
- 函数
- 对象:定义一个函数时,系统也会创建一个对象,该对象是Function类的实例。
- 方法:定义一个函数时,该函数通常会附加给某个对象,作为该对象的方法。
- 变量:定义一个函数的同时,也是一个变量。
- 类:定义一个函数时,也得到了一个与函数同名的类。可用其创建对象。
如果直接输出函数本身(函数名不带括号),将会输出函数源代码。
因为函数也可看做变量,应尽量避免函数与变量重名。
函数的实例属性和类属性
- 局部变量:在函数中以 var 声明的变量。
- 实例属性:在函数中以 this 前缀修饰的变量。
- 类属性:在函数中以函数名前缀修饰的变量。
实例属性和类属性都是面向对象的概念,实例属性属于单个对象,必须通过对象访问;类属性是属于类本身的,必须通过类访问。
调用函数的3种方式
1.直接调用函数
直接调用函数是最常见的方式,直接以函数附加对象作为调用者,在函数后括号内传入参数来调用函数。代码如下:
window.alert("测试代码");
p.walk();
当使用对象调用方法时,可以省略window调用者。
2.以call()方法调用函数
直接调用函数简单、易用,但这种调用方式不够灵活。有时候调用函数需要动态的传入一个函数引用,此时就需要使用call()方法调用函数了。语法格式为:
函数引用.call(调用者,参数1,参数2...)
3.以apply()方法调用函数
语法格式:
函数引用.call(调用者,[参数1,参数2...])
apply()方法与call()方法功能基本相似,都可以动态的调用函数,区别如下:
- 通过call调用函数时,必须在括号中详细列出每个参数
- 通过apply调用函数时,需要以数组的形式一次性传入所有调用参数。
函数提升
在同一个<script…/>元素内,javascript会将全局函数提升到<script…/>元素的顶部定义。
局部函数会被提升到所在函数顶部。
箭头函数
箭头函数相当于其他语言的Lambda(匿名)表达式或闭包语法,箭头函数是普通函数的简化写法。语法格式如下:
(param1,param2,...,paramN)=>{statements}
如果箭头函数的执行体只有一条 return 语句,则可以省略花括号和 return 关键字
如果箭头函数的形参列表只有一个参数,则可省略形参列表的圆括号
如果函数不需要形参,则形参列表的圆括号不能省略
与普通函数不同,箭头函数并不拥有自己的 this 关键字,箭头函数中的 this 总是代表包含箭头函数的上下文。
箭头函数并不绑定 arguments ,因此不能通过 arguments 访问调用箭头函数的参数。箭头函数中的 arguments 总是引用当前上下文的arguments 。
箭头函数容易产生的错误:
- 函数返回对象错误
- 箭头函数不允许在形参列表和箭头之间包含换行。
- 解析顺序导致的错误:当箭头函数与其他运算符一起运算时,可能出现由于解析顺序导致的错误。
函数的参数处理
与java完全类似,javascript 的参数传递也采用值传递方式。
基本类型和复合类型的参数传递
对基本类型,javascript采用值传递方式,当通过实参调用函数时,传入参数里的并不是实参本身,而是实参副本,因此在函数中修改参数值不会改变实参本身。
对复合类型仍然是值传递,只是容易混淆。复合类型变量本身并不持有对象本身,复合类型的变量只是一个引用,该引用指向实际的 javascript 对象。当把复合类型变量传入函数时,传入的依然是变量的副本,只是该副本和原变量指向同一个 javascript 对象。
空参数
如果函数定义时定义了参数,但引用函数时没有传参数,在 javascript 中不会报错, javascript 会将参数自动设为 undefined值。
如果先后定义两个形参列表不同的同名函数,这也不是函数重载,这会导致后面的函数覆盖前面的函数。
面向对象
继承和prototype
javascript 虽然支持类、对象的概念,但没有继承的概念,只能通过特殊手段扩展原有的 javascript类。
javascript是一种动态语言,允许自由的为对象增加属性和方法,当程序为某个不存在的属性赋值时,即可认为是为该对象增加属性。
javascript的所有类都有一个 prototype 属性,如果为 prototype 属性增加属性、方法,则可视为对原有类的扩展。可理解为:增加了 prototype 属性的类继承了原有的类——这就是 javascript 的伪继承机制。
示例如下:
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log(this.name+"向你打招呼!");
}
将 prototype 设为父类实例,可实现javascript 语言的继承。如下:(Student类继承Person类)
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
console.log(this.name+"向你打招呼!");
}
function Student(grade){
this.grade=grade;
}
Student.prototype=new Person("未命名",0);
构造器实现伪继承
示例如下:
function Person(name,age){
this.name=name;
this.age=age;
this.info=function(){
console.log(this.name+"向你打招呼!");
}
}
function Student(grade){
this.grade=grade;
this.inherit=Person;
this.inherit(name,age);
}
this.inherit=Person; 以 this 为调用者,调用了Person构造器,这样 Person构造器中的 this 就全部换成了当前的 Student ,这样即可将 Person类中定义的实例属性、方法都移植到 Student 类中。
使用 apply或call 实现伪继承
上述伪继承方式完全可以用 apply或call 实现,只要在使用apply或call时指定 this 为调用者即可。
function Person(name,age){
this.name=name;
this.age=age;
this.info=function(){
console.log(this.name+"向你打招呼!");
}
}
function Student(grade){
this.grade=grade;
Person.call(this,name,age);
Person.apply(this,[name,age]);
}
使用JSON语法创建对象
JSON语法提供了一种更简单的方式创建对象:使用花括号,将每个属性写成“key:value”对的形式。
var p={
name:'yeeku',
gender:'male',
};