JavaScript学习笔记(二) 函数

简介: 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



目录
相关文章
|
7月前
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
319 19
|
9月前
|
JavaScript
JS实现多条件搜索函数
JS封装的多条件搜索
|
11月前
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
255 32
|
10月前
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
JavaScript 前端开发
js教程——函数
js教程——函数
317 4
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
130 5
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
300 2