函数
我们再看函数前,先来看一个demo,看看如果没有函数我们的代码量
var students1 = [{
name: '张',
gender: 1
}, {
name: '一',
gender: 1
}, {
name: '二',
gender: 0
}];
var students2 = [{
name: '三',
gender: 0
}, {
name: '四',
gender: 1
}, {
name: '五',
gender: 1
}, {
name: '六',
gender: 1
}];
// 求1班的男女比率
var maleCount1 = 0,
femaleCount1 = 0,
length1 = students1.length,
student1,
ratio1;
for (var i = 0; i < length1; i++) {
student1 = students1[i];
if (student1.gender === 1) {
maleCount1++;
} else {
femaleCount1++;
}
}
ratio1 = maleCount1 / femaleCount1;
alert('1班的男女比率为:' + ratio1);
// 求2班的男女比率
var maleCount2 = 0,
femaleCount2 = 0,
length2 = students2.length,
student2,
ratio2;
for (var i = 0; i < length2; i++) {
student2 = students2[i];
if (student2.gender === 1) {
maleCount2++;
} else {
femaleCount2++;
}
}
ratio2 = maleCount2 / femaleCount2;
alert('2班的男女比率为:' + ratio2);
这是两个班级的,如果我们有十个班级,就需要写十个这么长的代码,怎么解决的,我们就用到函数了,我们再来看看函数怎么写
/**
* 求学生的男女比率
* @param {Array} students 学生列表
* @return {Number} 男女比率
*/
function ratio(students) {
var maleCount = 0,
femaleCount = 0,
length = students.length,
student,
ratio;
for (var i = 0; i < length; i++) {
student = students[i];
if (student.gender === 1) {
maleCount++;
} else {
femaleCount++;
}
}
ratio = maleCount / femaleCount;
return ratio;
}
alert('1班的男女比率为:' + ratio(students1));
alert('2班的男女比率为:' + ratio(students2));
我们需要哪个班级调用就可以了
函数语法
ECMAScript中的函数使用关键字function关键字来声明,后跟一组参数以及函数体
语法:
function functionName(arg0, arg1,...,argn){
statements
}
function 函数名([形参列表]){
执行代码
}
函数名([实参列表]) //函数调用
示例:
function sayHi(name, message){
alert("Hello" + name + "," + message);
}
sayHi("yym" ,"how are you today");
//这个函数可以通过其函数名来调用,后面加上一对圆括号和参数(参数如果多个,用逗号隔开)
ECMAScript中的函数在定义时不必指定是否具有返回值.实际上,任何函数在任何时候都可以通过return语句后跟要返回的值来实现返回值
function sum(num1, num2){
return num1 + num2;
}
//这个函数会在执行完return语句后停止并立即退出,因此,位于return之后的任何代码都不会执行.
function sum(number1, number2){
return number1 + number2;
alert("Hello World"); //永远不会执行
}
另外,return语句也可以不带有任何返回值,在这种情况下,函数停止执行后返回undefined,一般用在需要提前停止函数执行而又不需要返回值的情况下
函数定义的方式
- 函数声明
function add(number0, number1){
var sum = number0 + number1;
return sum;
} //函数声明
- 函数表达式
var add = function(number0, number1){
var sum = number0 + number1;
return sum;
} //函数表达式(把匿名函数赋值给变量)
- 函数调用的过程
function add(number0, number1){ //number0 = 2, number1 = 3
var sum = number0 + number1; //sum = 5
return sum; //返回sum
}
var x = add(2, 3); //x = 5
alert(x); // 弹出5
函数参数
ECMAScript函数的参数与大多数其他语言的参数不同.ECMAScript函数不介意传递进来多少参数,也不在乎什么数据类型,既是你定义的函数只接收两个参数,你也可以传递一个 三个甚至不传参数,解析器永远不会有怨言.之所以这样,js中的参数在内部用一个数组表示.函数接收的始终都是数组,而不关心数组中包含哪些参数.实际上,在函数体内可以通过arguments来访问这个参数数组,从而获取传递给函数的每一个参数.
- 实参数量少于形参
function add(number0, number1){ //number0 = 2, number1 = undefined
var sum = number0 + number1;
return sum;
}
var x = add(2);
alert(x) //NaN
- 实参数量多于形参
function add(number0, number1){ //number0=2, number1=3, 4=?
debugger;
var sum = number0 + number1;
return sum;
}
var x = add(2, 3, 4); //5
- 实参不定时(arguments)
function add() {
var length = arguments.length,
sum = 0,
parameter;
for (var i = 0; i < length; i++) {
parameter = arguments[i];
sum = sum + parameter;
}
return sum;
}
alert(add(2, 3)); // 5
alert(add(2, 3, 4)); // 9
alert(add(2, 3, 4, 5)); // 14
函数参数传递方式
ECMAScript中所有函数都是按值传递,也就是说,把函数外部的值赋值给函数内部的参数,就和把值从一个变量复制到另一个变量一样
参数为原始类型:值传递
function increment(number){
number = number + 1;
return number;
}
var a = 10;
var x = increment(a); //11
a; // 10
函数increment()有一个参数number,参数实际上是局部变量,调用时,变量a作为参数传递给函数,a的值被加1,这个变化不会影响函数外部的a变量,参数number与变量a互不相识,仅具有相同的值
参数为对象类型:值传递
function setName(obj){
obj.name = "yym";
}
var person = new Object();
setNmae(person);
alert(person.name); //"yym"
代码创建了对象,保存在变量person中,,这个变量被传递给setName()函数中复制给了obj,在函数内部,obj和person引用同一个对象,换句话说,既使这个变量按值传递,obj也会被引用来访问同一个对象,于是,在函数内部为obj添加name属性,外部person也有所反应;因为person指向的对象在堆内存中只有一个,而且是全局对象,有些人会认为是参数按照引用传递,让我们看修改的例子:
function setName(obj){
obj.name = "yym";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"yym"
和上面的例子区别,我们可以看到,如果person是引用传递,那么person会被修改为"Greg",但结果仍是"yym",说明即使在函数内部修改了参数的值,原始的引用仍然保持不变,实际上,在函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁
执行环境及作用域
-
执行环境(execution content)
定义了变量或函数有权访问的其他数据.每个执行环境都有一个与之关联的变量对象(variable object)
var zhoujielun = {
name: "周杰伦",
gender: 1
};
function class1() {
var zhoujielun = {
name: "周杰伦",
gender: 0
};
zhoujielun.name = "周杰";
zhoujielun.gender = 1;
}
class1();
console.log(zhoujielun); //访问不到内部的zhoujielun
再来看一个demo
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//这里可以访问color anotherColor和tempColor
}
//这里可以访问color和anotherColor,不能访问tempColor
swapColors();
}
//这里只能访问color
changeColor();
- 涉及了3个执行环境:全局环境,changeColor()的局部环境和swapColors()的局部环境.
- 全局环境中有一个变量color和一个函数changeColor()
- changeColor()的局部环境中有一个anotherColor变量和一个名为swapColors()的函数,但它也可以访问全局变量中的color
- swapColors()的局部环境中有一个变量tempColor,该变量只能在这个环境中访问到
下图中的矩形代表特定执行环境内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境任何变量和函数,这些环境之间的联系是线性 有次序的.每个环境都可以向上搜索作用域链,以查询变量和函数名.任何环境都不能通过向下搜索作用域链而进入另一个执行环境
函数作为对象属性
看上图,如果我们修改
变量point
是不是也要把函数里的point修改一下,不然的话无法运行,那我们又没有简单的方法呢?
可以把point修改为this
var point = {
x: 1,
y: 1,
move: function(stepX, stepY){
this.x += stepX;
this.y += stepY;
}
};
point.move(2, 1);
console.log(point);
其实,今天所写的这些都是对函数一个简单的介绍,并不是很深入,只需要理解就好了,后面我会整理一下,函数进阶的东西