this与箭头函数

简介: 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()();
相关文章
|
2月前
|
自然语言处理 JavaScript 前端开发
说说箭头函数的特点
说说箭头函数的特点
43 0
|
2月前
|
开发者
箭头函数
认识箭头函数
42 4
|
2月前
箭头函数是什么
箭头函数是什么
36 0
|
2月前
|
JavaScript 前端开发 开发者
箭头函数的意义和函数的二义性
这篇文章介绍了箭头函数的特点以及与普通函数的区别。它指出了箭头函数没有this、arguments对象和prototype原型的特点,因此不能作为构造函数使用。文章还解释了函数的二义性问题,即函数可以有多种调用方式,这在JS设计上存在缺陷。最后,文章指出箭头函数不再依赖面向对象的概念,因此没有this和原型的概念。
|
23天前
箭头函数和普通函数的区别
箭头函数和普通函数的区别
9 0
|
2月前
|
存储
箭头函数多个函数体
箭头函数多个函数体
|
2月前
|
JavaScript 网络架构
箭头函数详解
箭头函数详解
15 1
|
11月前
|
前端开发
面试官:箭头函数和普通函数的区别?箭头函数的this指向哪里?(二)
面试官:箭头函数和普通函数的区别?箭头函数的this指向哪里?(二)
|
8月前
|
JavaScript
什么是箭头函数
什么是箭头函数
55 1
|
8月前
|
JavaScript 前端开发
箭头函数和普通函数有什么区别
箭头函数和普通函数有什么区别
43 1