JavaScript函数

函数

函数实际上是对象

  • 在ECMAScript中,函数实际上是对象,每个函数都是Function类型的实例。

  • 因为函数是对象,所以函数名就是指向函数对象的指针。(和其他引用类型一样)。

函数的3种定义方式

  • 函数声明的方式定义函数

  • 函数表达式的方式定义函数

  • 使用箭头函数定义函数(ES6新增)

箭头函数(ES6新增)

ES6新增了使用胖箭头(=>)定义函数表达式的语法。

  • 任何可以使用函数表达式定义函数的地方都可以使用箭头函数。

如果只有一个参数,那么箭头函数可以不使用括号,只有在没有参数或有多个参数的情况下,才必须使用括号。

箭头函数也可以不使用大括号,但这样会改变函数的行为。

  • 使用大括号,就表示包含函数体,和平常的函数没有什么区别。(使用大括号,想要返回值,必须加上return)。
  • 不使用大括号,那么箭头之后只能包含一行代码,并且会隐式返回这行代码的值。(不使用大括号不需要为这一行代码加上return,就会隐式返回)。

箭头函数不适用的情况

  • 箭头函数不能使用arguments、super、new.target。
  • 箭头函数不能作为构造函数。
  • 箭头函数没有prototype属性。(箭头函数没有原型对象)。

函数名

因为函数名就是指向函数的指针,所以它们和其他包含对象指针的变量具有相同的行为,这使得一个函数可能具有多个名称。(可以把包含指向函数指针的变量赋给另外的变量,这样另一个变量也会包含指向函数的指针。)

  • 原因是不带括号的函数名会访问函数指针,而不会调用函数。

所有ES6的函数对象都会暴露一个只读的name属性。

  • 多数情况下,这个name属性中保存的是一个函数标识符(字符串化的函数名)。
  • 如果函数没有名称,那么name属性会显示为空字符串。
  • 如果函数是使用Function创建的,那么name属性会显示为"anonymous"。

理解参数

ECMAScript函数既不关心传入参数的个数,也不关心这些参数的数据类型。(因此ECMAScript不存在函数签名)。

  • 定义函数时要接收两个参数,并不意味着调用时就要传入两个参数,可以传入一个参数、三个参数甚至不传参数,解释器都不会报错。

  • 原因是ECMAScirpt函数的参数在函数内部表现为一个数组,函数并不关心这个数组包含什么。

    • 在使用function关键字定义函数的时候,可以在函数内部访问arguments对象,从中取得传进来的每个参数值。(箭头函数不行)。

arguments对象

  • arguments对象是一个类数组对象(但不是Array的实例,类数组是可迭代或具有可索引元素的结构),要确定传进来的参数个数可以访问arguments.length。

    • arguments对象可以和命名参数一起使用。(命名参数和arguments对象一一对应,第一个命名参数保存着和arguments[0]相同的值)。
  • 如果重写arguments[1]的值,那么这个改变也会同步到第二个命名参数。

    • 但这并不表示两者指向同一个内存空间,命名参数和arguments指向不同的内存空间,只是改变会同步。
    • 严格模式下,修改arguments[1]不会同步到命名参数,且在严格模式下修改arguments对象会报错。
  • 如果是箭头函数,那么传给函数的参数不能通过arguments对象访问,只能通过命名参数访问。

没有重载

ECMAScript函数不能像传统编程那样重载。

  • 什么是重载

    • 重载是多个函数函数名相同而参数列表不同,重载要求函数签名不同,因为ECMAScript传入的参数只表现为一个数组,所以没有函数签名,也就没有重载。
  • 如果ECMAScript定义了两个同名函数,那么后定义的会覆盖先定义的。

  • 可以通过arguments对象检查传入参数的数量和类型来模拟函数重载。

函数声明与函数表达式

函数声明和函数表达式的区别

  • JavaScript在任何代码执行之前,会先读取函数声明添加到执行上下文。

    • 所以函数声明可以在代码执行到它那一行之前调用函数,这个过程叫做函数声明提升。
  • 函数表达式必须等到代码执行到它那一行,才会在执行上下文中生成函数定义。

函数表达式的function关键字后面没有标识符,表明使用函数表达式创建的是匿名函数(匿名函数也叫拉姆达函数),匿名函数的name属性是空字符串。

函数作为值

因为在ECMAScript中函数名就是变量,所以意味着不仅可以把函数作为一个参数传给另一个函数,还可以在一个函数中返回另一个函数。

函数内部

ES5中函数内部存在2个特殊的对象(每个函数在被调用时都会自动创建这2个特殊对象)。

  • arguments

    • arguments对象是一个类数组对象,包含函数调用时传入的所有参数。(箭头函数没有arguments对象)。

      • arguments对象还有一个callee属性,是一个指向arguments对象所在的函数的指针。
  • this

    • this对象在标准函数和箭头函数中有不同的行为。

      • 在标准函数中,this对象引用的是 把函数当成方法来调用的上下文对象。(在网页的全局作用域调用函数,this对象指向windows)。

      • 在箭头函数中,this引用的是定义箭头函数的上下文。

        • 有时在事件回调或定时回调(setTimeout)中,this指向的并不是我们想要的对象,而这时只要把回调函数改成箭头函数就可以解决问题。

ES6中新增了一个函数内部的特殊对象

  • new.target

    • new.target属性用于检测函数是否是使用new操作符调用的,如果函数是正常调用的,那么new.target值是undefined,如果函数是使用new操作符调用的,那么new.target将引用被调用的构造函数。

函数属性与方法

ECMAScript中函数是对象,因此函数有属性和方法。

  • 每个函数都有2个属性

    • length

      • length属性保存的是函数定义的命名参数的个数。

        • 注意arguments对象的length属性保存的是函数传入的参数的个数。
    • prototype

      • prototype属性是实现原型链的基础。
  • 函数还有2个方法(这2个方法都会设置调用函数时,函数体内this对象的值)。

    • call()

      • call()的第一个参数是this值,而剩下要传给被调用函数的参数是逐个传递的。(使用call()向函数传参时,参数必须一个一个列出来)。

        • call()会将被调用函数体内的this值置为传入的this值。
    • apply()

      • apply()接受2个参数,第一个参数是函数内的this值,第二个参数是参数数组(参数数组可以是Array的实例,也可以是arguments对象)。

        • apply()将会把被调用函数体内的this值置为传入的this值。
  • ES5定义了一个新方法来设置函数的作用域(函数的执行上下文)。

    • bind()

      • bind()方法会创建一个新的函数实例,这个新函数实例的this值会被绑定到传给bind()的对象。

闭包

闭包是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。(闭包是函数)。

  • 理解闭包首先需要理解作用域链。

    • 什么是作用域链

      • 在调用一个函数时,会为这个函数创建一个执行上下文,并创建一个作用域链,然后用arguments对象和其他命名参数来初始化这个函数的活动对象,外部函数的活动对象是内部函数作用域链上的第二个对象,作用域链一直向外串起了所有函数的活动对象,直到全局上下文才终止。
    • 作用域链的作用

      • 函数在执行时,要从作用域链中查找变量,才能进行读写值。
  • 闭包的副作用

    • 闭包的包含函数的活动对象并不能在它执行完毕之后被销毁,因为闭包的作用域链还保留着对包含函数的活动对象(作用域)。(在包含函数执行完毕之后,它的作用域链会被销毁,但它的活动对象依然存在于内存,直到闭包被销毁才会被销毁)。

      • 因为闭包会保留它们的包含函数的作用域,所以闭包比一般函数更占内存。

在闭包中使用this对象

  • 闭包函数的this会指向window对象。(在严格模式下,this值是undefined)。

    • 因为闭包函数根本不可能访问到外层函数的this值,所以闭包的this不会被绑定到外层作用域的this。

      • 在闭包中this绑定为外层函数this的2个方法

        • 把外层函数的this赋值给变量,这样闭包就可以访问了。
        • 使用call()、apply()、bind()。

XMind: ZEN - Trial Version

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值