JS初识函数

函数

我们再看函数前,先来看一个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
  • 实参不定时(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,该变量只能在这个环境中访问到

下图中的矩形代表特定执行环境内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境任何变量和函数,这些环境之间的联系是线性 有次序的.每个环境都可以向上搜索作用域链,以查询变量和函数名.任何环境都不能通过向下搜索作用域链而进入另一个执行环境

image.png

函数作为对象属性

对象属性

看上图,如果我们修改变量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);

其实,今天所写的这些都是对函数一个简单的介绍,并不是很深入,只需要理解就好了,后面我会整理一下,函数进阶的东西

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容