zoukankan      html  css  js  c++  java
  • JavaScript学习笔记(二) 函数

    在 JavaScript 中函数是一种特殊的对象类型

    1、函数定义

    (1)认识函数字面量

    函数字面量是定义函数的最简单、最直接的方式,它一般包含四个部分:

    • 关键字 function
    • 函数名称:函数名称用于标识函数,但是它也可以省略
    • 包含在圆括号中的一组参数:参数定义为函数中的变量,在函数调用时初始化为实际提供的值
    • 包含在花括号中的一组语句:语句是函数的主体,它们在函数被调用时执行

    (2)定义函数

    应用函数字面量,在 JavaScript 中提供两种方式定义函数:

    • 函数声明语句:函数声明语句是函数字面量的简单应用,实际上也是我们定义函数比较常用的方式
    // 定义一个计算两数相加的函数
    function add(a, b) {
        return a + b
    }
    
    // 定义一个计算阶乘的递归函数
    function factorial(x) {
        return (x <= 1) ? 1 : x * factorial(x - 1)
    }
    
    • 函数定义表达式:在 JavaScript 中,函数也是一个对象,所以我们可以把函数的定义赋值给一个变量
    // 定义一个计算两数相加的函数,为了使得代码结构更加紧凑,这里的函数字面量一般省略函数名称
    var add = function(a, b) {
        return a + b
    }
    
    // 定义一个计算阶乘的递归函数,为了方便函数调用自身,这里的函数字面量需要加上函数名称
    var factorial = function fact(x) {
        return (x <= 1) ? 1 : x * fact(x - 1)
    }
    

    (3)对比两种定义函数的方式

    两种定义函数的方式(函数声明语句和函数定义表达式)有什么不同呢?

    • 声明时机

      函数声明语句只能出现在全局代码或内嵌在其它函数中,不能出现在条件判断等语句中

      而函数定义表达式可以出现在代码中的任意地方

    • 调用时机

      以函数声明语句定义的函数,在编译时被提前到函数作用域的顶部,所以它可以在定义之前被调用

      对于函数定义表达式,虽然变量的声明会提前,但是变量的赋值不会提前,所以只能在函数定义后才能调用

    2、函数调用

    (1)隐式参数

    在函数调用时,除了显式传入函数的实参,每个函数还会接受两个隐式参数:this 和 arguments

    参数 this 的值取决于函数的调用模式;而参数 arguments 可以用于获取传入函数的所有实参

    (2)函数调用方式与 this 取值

    调用 JavaScript 函数常见的有三种方式,分别是函数调用、方法调用以及构造函数调用

    • 作为函数调用

    最简单的一种情况,函数作为一个普通函数被调用,此时 this 被绑定到全局对象

    > // 定义一个普通函数
    > var add = function(a, b) {
        // 此时 this 被绑定到全局对象(在这里可以输出 this 观察一下)
        // this 的取值可能根据 JavaScript 运行环境的不同而不同
        return a + b
    }
    > // add 函数作为函数被调用,this 被绑定到全局对象
    > // 函数调用方式:function(argument, ...)
    > add(1, 1)
    

    实际上,在函数作为普通函数被调用时,this 被绑定到全局对象是一个不太合理的设计

    在《JavaScript语言精髓》一书中甚至称其为 “语言设计上的一个错误”,因为这样子容易造成全局对象的污染

    • 作为方法调用

    当函数作为对象的一个属性存在时,它被称为方法,此时 this 被绑定到该对象

    > // 定义一个 counter 对象
    > var counter = {
        value: 0,
        // 定义 increment 函数作为方法(counter 对象的一个属性)
        increment: function() {
            // 当 increment 函数作为方法被调用时,会自动得到一个隐式参数 this,指向对象本身
            this.value += 1
        }
    }
    > // increment 函数作为方法被调用,this 绑定到 counter 对象
    > // 方法调用方式:object.function(argument, ...)
    > counter.increment()
    > counter.value
    // 1
    
    • 作为构造函数调用

    构造函数的定义方法和普通函数完全一致,只是在命名上约定构造函数以大写字母开头

    此时 this 被绑定到构造函数返回的新对象上

    // 定义 Message 函数作为构造函数
    > var Message = function(descrition) {
        // 当 Message 函数作为构造函数被调用时,会自动得到一个隐式参数 this,绑定到新对象
        this.detail = descrition
    }
    > // Message 函数作为构造函数被调用,this 绑定到 message 对象
    > // 构造函数调用方式:new Function(argument, ...)
    > var message = new Message('Hello')
    > message.detail
    // 'Hello'
    

    这里存在一个严重的问题,如果说我们不小心把构造函数当成普通函数调用,想想会发生什么

    此时 this 会绑定到全局对象,也就是说我们给新对象添加的属性都会添加到全局对象上,造成全局对象的污染

    所以我们不得不要做额外的工作来保证构造函数被正常调用

    > var Message = function(descrition) {
        // 先判断 this 是否指向当前对象
        // 如果是,则说明函数是通过构造函数的方式调用的,这时可以安心进行初始化对象的工作
        if (this instanceof Message) {
            this.detail = descrition
        }
        // 如果不是,那就说明函数可能是通过错误的方式调用的,需要以正确的方式重新调用构造函数
        else {
            return new Message(descrition)
        }
    }
    

    (3)函数参数与 arguments

    在 JavaScript 中,没有要求传入的实参个数与函数定义时指定的形参个数一致,这样就会出现一些有趣的现象

    • 当实参个数小于形参个数

    如果实参个数小于形参个数,多余的形参将会被设置为 undefined

    这时,可以给传入函数的参数设置一个合适的默认值,以防止程序出现意想不到的错误

    > function add(a ,b) {
        a = a || 0
        b = b || 0
        return a + b
    }
    > add(5, 7)
    // 12
    > add(9)
    // 9
    > add()
    // 0
    
    • 当实参个数大于形参个数

    如果实参个数大于形参个数,多余的实参也会正常传入函数,只是无法获取它们的引用罢了

    这时,可以用隐式传入的参数 arguments 获取传入函数的所有实参

    > function add() {
        var total = 0
        for (let curr = 0, len = arguments.length; curr < len; curr++) {
    		total += arguments[curr]
        }
        return total
    }
    > add(1, 2, 3, 4, 5)
    // 15
    

    【 阅读更多 JavaScript 系列文章,请看 JavaScript学习笔记

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    总有段迷惑的人生
    codepage的重要性【转】
    开通博客
    js 正则常用方法
    关于小程序scrollview组件添加enableflex后布局失效的解决方案
    关于小程序使用async/await报错regeneratorRuntime is not defined的解决方案
    IE6中,一个Button同时打开两个下载窗口,并且可以自动关闭
    Create User
    Oracle: import tables use .dmp file in PL/SQL Developer
    VS在进行调试时,不能调试的原因列举如下
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/11722321.html
Copyright © 2011-2022 走看看