• 【JavaScript进阶之旅 ES6篇 第六章】函数默认值、this、箭头函数、箭头函数结合函数参数解构赋值、rest运算符


    一、函数默认值

    1、函数形参的length

    function test(a, b, c) {}
    console.log(test.length); // 3
    
    function test(a, b = 1, c) {}
    console.log(test.length); // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 函数形参的length等于从左到第一个有默认值的参数的个数

    2、函数实参的length

    function test(a, b, c) {
      console.log(arguments.length); // 2
    }
    test(1, 2);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • arguments.length

    3、函数的默认值对函数的length的影响

    • 更改函数参数默认值,会引起函数的属性length变化
    • length根据默认值的位置确定,只包含默认值之前的参数的长度

    4、函数的默认值导致形参和实参的映射关系不存在

    • 函数的形参和实参是相互映射的关系
    function test(a, b, c) {
      arguments[1] = 3;
      console.log(b); // 3
    }
    test(1, 2);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    指定函数的默认值后:

    function test(a, b = 5, c) {
      arguments[1] = 3;
      console.log(arguments); // [1, 3]
      
      console.log(b); // 2
    }
    test(1, 2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 任何一个参数给了默认值后,形参跟实参的映射关系将不存在
    • 函数内部更改实参的值,能够更改实参,但是对形参没有任何影响

    5、给解构赋值一个默认值

    function foo({x, y = 5}) {
      console.log(x, y);
    }
    
    foo({}); // undefined 5
    foo({x: 1}); // 1 5
    foo({x: 1, y: 2}); // 1 2
    
    foo(); // 报错 因为他没有属性则没有包装类,匹配不上{},所以报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上述不传值的解决办法:

    function foo({x, y = 5} = {}) { // 解构赋值依然有默认值 {}
      console.log(x, y);
    }
    
    // 参数是undefined的时候会找默认值为空对象的默认值,从而达到匹配
    foo(); // undefined 5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6、fetch

    // 简写方式
    function fetch(
      url,
      {
        body = "",
        method = "GET",
        header = {}
      }
    ) {
      console.log(method);
    }
    
    // 完整方式
    function fetch(
      url,
      {
        body: body = "",
        method: method = "GET",
        header: header = {}
      }
    ) {
      console.log(method); // GET
    }
    
    fetch('http://www.baidu.com', {});
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    调用fetch的时候,不想手动传第二个参数,那么我们就可以给他的解构赋值赋一个默认值:

    function fetch(
      url,
      {
        body = "",
        method = "GET",
        header = {}
      } = {}
    ) {
      console.log(method);
    }
    
    fetch('http://www.baidu.com'); // GET
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7、作用域问题

    var a = 1;
    var a = 2; // var存在变量提升,可以重新赋值,覆盖
    console.log(a); // 2
    
    var x = x; // x声明到全局,没有赋值
    console.log(x); // undefined 
    
    let b = 1;
    let b = 2; // let不存在变量提升,不可以重新赋值,报错
    
    let c = c; // c没有声明 报错 c is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // x还没有定义,不可以在初始化之前调用x 
    function foo(x = x) { // Cannot access 'x' before initialization
    }
    
    foo();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    8、默认值给一个function

    • 调用栈:函数调用的时候会创建一个栈针,记录着当前的函数是在哪个地方调用的,以栈的方式存储
    var x = 1;
    // 当给函数默认值的时候,就已经给了一个块级作用域 let x,y
    function foo(x, y = function() {
      x = 2;
      console.log(x); // 2
    }, z = function() {
      console.log(x);
    }) {
      var x = 3;
      y(); // 2
      console.log(x); // 3
      z(); // 1
    }
    
    foo();
    console.log(x); // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    二、普通函数的this指向

    1、默认绑定规则

    • 非严格模式下默认指向:window
    • 严格模式在指向:undefined
    a();
    function a () {
      console.log(this); // window
    }
    
    • 1
    • 2
    • 3
    • 4
    a();
    function a () {
      'use strict';
      console.log(this); // undefined
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、隐式绑定规则

    • 谁调用,指向谁
    function foo() {
      console.log(this.a);
    }
    
    var obj = {
      a: 2,
      foo: foo
    }
    
    obj.foo(); // 2
    
    var bar = obj.foo;
    bar(); // window.bar(); -> window上没有,则为undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、显示绑定

    • call、apply、bind绑定

    4、new

    在new的时候将this转变成实例化的对象

    • new的时候改变了this指向

    5、优先级:4>3>2>1

    三、箭头函数

    1、箭头函数写法

    • 说到箭头函数一定是箭头函数表达式(因为箭头函数没有函数名只能赋值给变量)

    函数参数只有一个:括号可以省略

    let f = a => { 
      return a;
    }
    
    // 相当于
    let f = function(a) {
      return a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    函数体只return一个表达式:大括号可以省略,return可以省略

    let f = a => a;
    
    // 相当于
    let f = function(a) {
      return a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    函数没有参数的话:括号不可以省略

    let f = () => a;
    
    // 相当于
    let f = function() {
      return a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    函数体有多条语句: 括号不可省略

    • 箭头函数不指定返回值默认返回undefined
    let f = function() {
      let a = 1,
          b = 2;
    
      console.log(a + b);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2、箭头函数结合函数参数的解构赋值

    // 函数参数的解构赋值
    const full = ({f, l} = {}) => f + '' + l;
    
    function full({f, l} = {}) { // 相当于
      return f + '' + l;
    }
    
    console.log(full({f: 'l', l: 'yb'})); // lyb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、箭头函数没有arguments

    var sum = (a, b) => {
      console.log(arguments); //  arguments is not defined
    }
    sum();
    
    • 1
    • 2
    • 3
    • 4
    • 证明:=>function本质上是两个东西,不是function的简写

    4、rest运算符(展开或者收集)

    • 箭头函数中arguments的替代品: …|spread|rest运算符

    收集实参

    // args: 随便定义,但是我们习惯使用args
    
    var sum = (...args) => {
      console.log(args); // [1, 2]
    }
    sum(1, 2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 拓展收集运算符必须是最后一位
    let fn = (a, b, ...c) => {
      console.log(a, b, c);
    }
    
    // let fn = (...c, a, b) => { // 报错
    //   console.log(a, b, c);
    // }
    
    fn(1, 2, 3, 4, 5, 6); // 1 2 [3, 4, 5, 6]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    展开参数

    function foo(a, b, c) {
      console.log(a, b, c);
    }
    
    foo(...[1, 2, 3]); // 1 2 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 展开运算符实质是用apply实现的
    function foo(a, b, c) {
      console.log(a, b, c);
      console.log(this);
    }
    
    foo.apply(null, [1, 2, 3]); // 1 2 3  window
    foo.apply(undefined, [1, 2, 3]); // 1 2 3  window
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 展开数组,并合并
    let a = [1, 2, 3];
    let b = [0, ...a, 4];
    console.log(b); // [0, 1, 2, 3, 4]
    
    • 1
    • 2
    • 3

    函数中使用了 … 运算符,函数的长度将不再准确

    console.log((function(a){}).length); // 1
    
    console.log((function(...a){}).length); // 0
    
    console.log((function(a, b, ...c){}).length); // 2
    
    console.log((function(a, b = 1, ...c){}).length); // 1
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    CF1781F Bracket Insertion(2700*) 题解(括号匹配DP)
    js逆向基础篇-某音乐网站-xx音乐
    OAuth2.0详细介绍与实践(通俗易懂)
    xxl-job集成钉钉群告警
    成都理工大学_Python程序设计_第7章
    Ai项目十四:基于 LeNet5 的手写数字识别及训练
    面试__编程
    leetcode《图解数据结构》刷题日志【第四周】(2022/11/07-2022/11/20)
    【安全篇】Spring Boot 整合 Spring Authorization Server
    七夕来袭——属于程序员的浪漫
  • 原文地址:https://blog.csdn.net/Lyb__/article/details/125420014