一个前端开发者的救赎之路-JS基础回顾(三)-Function函数

函数的声明

  1. 赋值式:var func = function() {}
  2. 声明式:function func() {}
  3. 箭头函数:()=>{}
  4. 三者之间的区别
    a. 声明式可以在函数声明前去调用,赋值式不可以
    b. 箭头函数,他们从定义自己的环境继承上下文,而不是像以其他方式定义的函数那样定义自己的调用上下文
    c. 箭头函数没有prototype属性,所以它不能作为新类的构造函数

函数的调用

  • 作为函数:

    • 注意这个说法,函数是通过调用表达式被作为函数或方法调用的。

    • 调用表达式包括求值为函数对象的函数表达式,后跟一对圆括号,圆括号中是逗号分隔的零或多个参数表达式列表

    • this指向:

      • 非严格模式:全局对象
      • 严格模式:undefined
      • 注意 箭头函数又有不同:它们总是继承自身定义所在环境的this值(这里即使是严格模式,this也是window
      • 下面的代码可以用来判断是不是处于严格模式
      js 复制代码
      // 定义并调用函数,以确定当前是不是严格模式
      const strict = (function() { return !this }())
      • 我有一篇文章,这里面有一个自己遇到的有趣的this指向和作用域的问题
    • 这里注意条件式调用:

      • 在Es2020中,可以在函数表达式的后面、圆括号的前面插入?.,从而只在函数不是null或undefined的情况下调用。
      • 在没有副作用的前提下:f?.()<=>(f !== null && f !== undefined ? f() : undefined)
  • 作为方法:

    • this关键字不具有变量那样的作用域机制,除了箭头函数,嵌套函数不会继承包含函数的this值。如果嵌套函数被当做方法来用,那它的this就是调用它的对象。如果嵌套函数(不是箭头函数)被当做函数来调用,则它的this值要么是全局对象(非严格模式),要么是undefined(严格模式)

      js 复制代码
      let o = {
          a: 1,
          b: 2,
          m: function() {
              let self = this;
              console.log(this.a); // 1
              f();
      
              function f() {
                  console.log(this.b); // undefined
              }
              
              const g = () => {
                  console.log(this.b); // 2
              }
              
              g();
          }
      }
      o.m();
  • 作为构造函数

    • 作为构造函数调用,上下文是这个新对象
  • 通过call()或apply()方法调用

    • 这两个方法允许我们指定调用时的this,这意味着可以将任意函数作为任意对象的方法来调用
    • call()方法使用自己的参数列表作为函数的参数,而apply()方法则期待数组值作为参数。
  • 通过JavaScript语言隐式调用

    • 这里在开发中排查bug,很关键,就是我们引用了别人的三方库或者代码都有可能出现这个隐式调用

函数的参数

  • 函数调用时所传的实参,可以少于形参也可以多于形参,
  • 函数定义式可以用一个剩余参数来接收多余的参数,剩余参数必须作为最后一个参数,并且是...args这种形式,剩余参数永远是一个数组,不会是undefined,即使没有传对应的实参,因此不需要给剩余参数默认值

JS预解析

  • 对于函数的预解析和普通变量不一样,函数预解析是直接把整个函数提到顶部作用域,在预解析时会提前定义,只是不会立即执行。
  • 普通变量只是把声明提升到所在作用域顶部,而不进行初始化。
  • 因此,上面函数定义的时候,如果使用字面量的方式会把这个变量提升到顶部作用域并赋值undefined,所以在定义前调用的时候会报错。
  • letconst 会提升(hoisting),但由于 TDZ(暂时性死区) 机制,在声明前访问会报错

作用域

  • 作用域在定义的时候,一个函数就会形成一个内部作用域,后来引入了let/const又有了块级作用域
  • 作用域在访问的时候,是从下往上找,一直找到顶级作用域,找不到就报is not defined
  • 在赋值的时候不是,如果一直到最顶级都未声明,那他就是直接在全局定义域声明并且赋值这个变量。所以即使在vue中的某一个函数直接使用xxx=来进行操作,也是会在全局作用域添加一个全局变量xxx(内存泄漏),千万不要这样干

函数的方法和属性

  1. length属性:返回声明时声明的形参的个数(不包含剩余参数),只读
  2. name属性:表示定义函数时使用的名字(如果是用名字定义的),如果是未命名的函数,表示在第一次创建这个函数时赋给该函数的变量名或属性名。这个属性主要用于记录调试或排错信息。只读
  3. prototype属性:箭头函数没有
  4. call()和apply()方法:箭头函数的this不会被修改
  5. bind()方法:bind()方法主要目的是把函数绑定到对象,箭头函数不起作用
  6. toString()方法:
    • ECMAScript规定返回一个符合函数声明语句的字符串
    • 实际上,多数(不是全部),都是返回函数完整源代码
    • 内置函数返回的字符串中通常包含"[native code]",表示函数体
  7. Function()构造函数:
    • Function()构造函数可以接收任意多个字符串参数 ,其中最后一个参数函数体的文本。这个函数体 文本中可以包含任意JavaScript语句,相互以分号分隔。传给构造函数的其他字符串参数,将作为这个新函数的的形参。
    • 注意:Function()构造函数不接受任何指定新函数名字的参数。与函数字面量一样,Function()构造函数创建的也是匿名函数
相关推荐
Mintopia7 分钟前
Next.js 全栈开发基础:在 pages/api/*.ts 中创建接口的艺术
前端·javascript·next.js
小妖66610 分钟前
react-router 怎么设置 basepath 设置网站基础路径
前端·react.js·前端框架
xvmingjiang16 分钟前
Element Plus 中 el-input 限制为数值输入的方法
前端·javascript·vue.js
XboxYan33 分钟前
借助CSS实现自适应屏幕边缘的tooltip
前端·css
极客小俊34 分钟前
iconfont 阿里巴巴免费矢量图标库超级好用!
前端
小杨 想拼41 分钟前
使用js完成抽奖项目 效果和内容自定义,可以模仿游戏抽奖页面
前端·游戏
yvvvy44 分钟前
🐙 Git 从入门到面试能吹的那些事
前端·trae
狂炫一碗大米饭44 分钟前
事件委托的深层逻辑:当冒泡不够时⁉️
javascript·面试
张柏慈1 小时前
JavaScript性能优化30招
开发语言·javascript·性能优化
EmmaGuo20151 小时前
flutter3.7.12版本设置TextField的contextMenuBuilder的文字颜色
前端·flutter