JavaScript高级—— this与箭头函数

1. this的指向

💡在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了,也就是说,this的指向完全取决于函数调用的位置, 即this是在执行的时候被绑定的。
  • 函数调用: 当一个函数不是一个对象的属性时,直接作为函数来调用时,this指向全局对象,立即执行函数,默认的定时器等函数,this也是指向window
  • 方法调用: 如果一个函数作为一个对象的方法来调用时,this指向这个对象。
  • 构造函数调用: this指向这个用new新创建的对象。
  • apply 、 call 和 bind 调用模式: 这三个方法都可以显示的指定调用函数的 this 指向。
  • 箭头函数的this: 指向声明时所在作用域下 this 的值,即箭头函数的this去他的上级作用域下寻找,任何方法都改变不了他的指向
隐式绑定
  // 严格模式:
  // 'use strict'

  // 1. 独立函数调用
  function foo() {
    console.log(this === window); //true
  }
  foo();

  // 2. 方法调用
  var obj = {
    name: "zgc",
    running: function () {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log(this);
    },
  };

  obj.running(); //obj对象

  var fn = obj.running;
  fn(); // window对象

  function bar() {
    console.log(this);
  }
  var baz = {
    name: "wf",
    bar: bar,
  };
  baz.bar(); // baz对象

  function test(fn) {
    fn();
  }
  test(baz.bar); // window对象

  // 3. 构造函数调用(new) 绑定
  function Student(name) {
    this.name = name;
    console.log("构造函数", this); // {name: 'zgc'}
  }
  const stu = new Student("zgc");

  // 4. 严格模式下, 独立函数调用this指向的是undefined
显式绑定(apply & call & bind)
  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
  • apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
  • apply是把参数放在一个数组里面作为它的第二个参数,而call、bind从第二个参数开始以参数列表的形式展现。
  • bind则是返回改变了this指向的一个函数,便于稍后调用;apply 、call 则是立即调用
  • bind方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数, 这个函数的 this指向除了使用new 时会被改变,其他情况下都不会改变
  var obj = {
    name: "zgc",
  };

  function foo(name, age) {
    console.log("foo", this, name, age);
  }

  // 让 foo的this指向obj
  // 1. call
  // 第一个参数, 绑定this
  // 第二个参数开始, 以参数列表的形式展现
  foo.call(obj, "zgc", 18); // foo {name: 'zgc'} zgc 18

  // 2. apply
  // 第一个参数, 绑定this
  // 第二个参数, 以数组的形式传入额外的实参
  foo.apply(obj, ["wf", 20]); // foo {name: 'zgc'} wf 20

  // 3. bind
  // 如果我们希望一个函数总是显示的绑定在一个对象上, 而不是每一次调用时再去绑定, 那么可以使用bind
  //  bind方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数, 便于稍后调用
  // 第一个参数, 绑定this
  // 第二个参数开始, 以参数列表的形式展现
  const baz = foo.bind(obj, "wlc", 22);
  baz(); // foo {name: 'zgc'} wlc 22]

  const bar = foo.bind(obj);
  bar("cx", 24); // foo {name: 'zgc'} cx 24
内置函数的this指向
 //  JavaScript的内置函数
  // 1. 定时器
  setTimeout(function () {
    console.log("定时器", this); // window
  }, 1000);

  // 2. 点击事件
  var btn = document.querySelector("button");
  // btn.onclick = function () {
  //   console.log("btn", this); // btn(<button>按钮</button>)
  // };
  btn.addEventListener("click", function () {
    console.log("btn", this); // btn(<button>按钮</button>)
  });

  // 3. forEach等方法
  //默认 window, 第二个参数可以绑定this
  var names = ["zgc", "wf"];
  var obj = { name: "zgc" };
  names.forEach(function () {
    console.log("forEach", this); // { name: "zgc" }
  }, obj);
  
  // 4. 补充: 立即执行函数this指向window
  (function () {
    console.log("立即执行函数", this);
  })();

2. this绑定的优先级

  function foo(age) {
    console.log(this);
    this.age = age;
  }

  var obj = {
    name: "zgc",
    foo: foo,
  };

  // 1. 隐式绑定(方法)的优先级高于默认绑定(独立函数调用)
  obj.foo(18); // obj: {name: 'zgc', age: 18, foo: ƒ}

  // 2. 显式绑定的优先级高于隐式绑定
  var bar = {
    name: "cx",
  };

  obj.foo.call(bar, 18); // bar: {name: 'cx', age: 18}

  // 3. new不可以和call/apply一起使用, 但绑定的优先级高于bind绑定
  var baz = obj.foo.bind(bar);

  var test = new baz(18);
  console.log(test); // test: {age: 18}

  // 4. bind的优先级高于 apply/call
  baz.call(obj); // bar: {name: 'cx', age: 18}

  // 5: 在显式绑定中, 如果我们的第一个参数为null和undefined, 那么这个显式绑定会被忽略, 使用默认规则
  obj.foo.call(null); // window

3. 箭头函数

💡ES6允许使用箭头(=>)定义函数,箭头函数多用于匿名函数的定义
  1. 如果形参只有一个,则小括号可以省略;
  2. 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果,return省略
  3. 箭头函数其实本身并没有绑定this,,即箭头函数的this去他的上级作用域下寻找,任何方法都改变不了他的指向
  4. 箭头函数是匿名函数,不能作为构造函数实例化;
  5. 不能使用 arguments,使用reset参数
  6. 当省略花括号与return, 并且返回值是一个对象时, 对象必须包一个小括号
  // 1. 箭头函数的定义
  // var foo = (参数1, 参数2) => { 代码块 };

  // 2. 当省略花括号与return, 并且返回值是一个对象时, 对象必须包一个小括号
  var num = () => 1;
  var obj = () => ({ name: "zgc" });
  console.log(num(), obj()); // 1 {name: 'zgc'}

  // 3. this的使用
  // 箭头函数其实本身并没有绑定this,,即箭头函数的this去他的上级作用域下寻找
  // 所以任何方法都无法改变该this的指向
  var foo = () => {
    console.log(this);
  };
  foo(); // window

  var obj = {
    name: "zgc",
    running: () => {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log("箭头函数", this); // window
    },
  };
  obj.running();

  var obj = {
    name: "wf",
    running: function () {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log("普通函数", this); // obj
      var bar = () => {
        console.log("bar", this); // obj
      };
      return bar;
    },
  };
  const fn1 = obj.running();
  fn1();

  var name = "xxxx";
  var obj = {
    name: "wf",
    running: function () {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log("普通函数", this); // window
      var bar = () => {
        console.log("bar", this, name); // window xxxx
      };
      return bar;
    },
  };
  const fn2 = obj.running;
  fn2();
  fn2()();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下次一定L_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值