首页 > 其他分享 >【博学谷学习记录】超强总结,用心分享 | this/call/apply/bind

【博学谷学习记录】超强总结,用心分享 | this/call/apply/bind

时间:2023-02-20 21:15:09浏览次数:41  
标签:function console log bind call apply var obj 函数

this的指向问题

在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。

简单例子

  var a = 1
  const demo = {
    a: 2,
    func: function() {
      return this.a
    }
  }
  console.log(demo.func()) // 2
  console.log(this.a) // 1

以上简单例子,demo.func()中this的指向是对象demo, 而this.a的指向是window

全局上下文

在函数内部,this的值取决于函数被调用的方式。例如上面的this.a,声明var a,就是在全局环境下声明了a,在浏览器中,全局对象是window,this.a就是读取了window对象下a的值

在非严格模式下

 this === window // true
 
 function b() {
    return this
  }
 b() === window // true

两个效果是一致的

在严格模式下,我们调用b()函数的时候是直接调用的,并没有通过window来调用,this就会保持为undefined

function b() {
   return this // undefined
 }
 console.log(b() === undefined) // true

类上下文

在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中

class Example {
    constructor() {
      const proto = Object.getPrototypeOf(this)
      console.log(Object.getOwnPropertyNames(proto))
    }
    a(){}
    b(){}
    static c() {}
}
new Example() // ['constructor', 'a', 'b']

派生类

派生类的构造函数没有初始的 this 绑定。在构造函数中调用 [super()]会生成一个 this 绑定,并相当于执行如下代码,Base为基类:

this = new Base()

派生类不能在调用 super() 之前返回,除非其构造函数返回的是一个对象,或者根本没有构造函数。

  class A {}
  class B extends A {}
  class C extends A {
    constructor() {
      return { a: 5}
    }
  }
  class D extends A {
    constructor() {}
  }
  new B()
  new C()
  new D() // ReferenceError

例子:

var a = { b: 1}
var b = 2
function whatsThis() {
    return this.b
}

这里有个有趣的现象,this.b输出的值取决于函数的调用方式,在我们正常调用的情况下,得到的值就是2,取到的是window下的a的属性,但是通过call或者apply绑定,我们获得得就是1了

whatsThis.call(a) // 1
whatsThis.apply(a) // 1

在非严格模式下使用 call 和 apply 时,如果用作 this 的值不是对象,则会被尝试转换为对象。null 和 undefined 被转换为全局对象。

如下

  function getType() {
    console.log(Object.prototype.toString.call(this));
  }

  getType.call(1);     // [object Number]
  getType.call('1'); // [object String]
  getType.call(undefined); // [object global]
  getType.call(true); // [object Boolean]

this和对象的转换

 function add(c, d) {
    console.log(this.a + this.b + c + d)
  }

  var o = {a: 1, b: 3};

  // 第一个参数是用作“this”的对象
  // 其余参数用作函数的参数
  add.call(o, 5, 7); // 16

  // 第一个参数是用作“this”的对象
  // 第二个参数是一个数组,数组中的两个成员用作函数参数
  add.apply(o, [10, 20]); // 34

bind

调用bind(someObject)会创建一个与函数具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。

  function b() {
    return this.a
  }
  let a1 = b.bind({a: 1})
  console.log(a1()) // 1
  let a2 = a1.bind({a: 2})
  console.log(a2()) // 2
  let e = {a:3, b:b, a1:a1, a2:a2}
  console.log(e.a, e.b(), e.a1(), e.a2()) // 3 3 1 1

箭头函数

在[箭头函数]中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象

 
 var globalThis = this
  var foo = (() => this)
  console.log(foo() === globalThis) // true

  var obj = { foo: foo}
  console.log(obj.foo() === globalThis) // true

  console.log(foo.call(obj) === globalThis) // true

  foo = foo.bind(obj)
  console.log(foo() === globalThis)// true

作为对象的方法

当函数作为对象里的方法被调用时,this 被设置为调用该函数的对象。

  var obj = {
    data: 1,
    f: function() {
      return this.data
    }
  }
  console.log(obj.f()) // 1

换一种方式

  var obj = { data: 1 }
  function independent() {
    return this.data
  }
  obj.f = independent;
  console.log(obj.f()) // 1

这里我们输出的还是1,原因是,f函数本身是没有data的,但是f绑定的是obj, this指向的是obj,所有拿到的data为1

this 的绑定只受最接近的成员引用的影响

  obj.b = {g: independent, data: 2};
  console.log(obj.b.g()); // 2

原型链中的 this

对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法就在这个对象上一样。

 var obj = {
    f: function() {
      return this.a + this.b;
    }
  };
  var p = Object.create(obj);
  p.a = 1;
  p.b = 4;

  console.log(p.f()); // 5

函数p本身是没有f函数的,f函数继承自它的原型。在p.f的引用中,函数的this指向了p.

getter 与 setter 中的 this

再次,相同的概念也适用于当函数在一个 getter 或者 setter 中被调用。用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。

  function sum () {
    return this.a + this.b + this.c
  }

  var obj = {
    a: 1,
    b: 2,
    c: 3,
    get average() {
      return (this.a + this.b + this.c)/3
    }

  }
  Object.defineProperty(obj, 'sum', {
    get: sum,
    enumerable: true,
    configurable: true
  })
  console.log(obj.average, obj.sum)

构造函数

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

  function obj(){
    this.a = 37;
  }

  var data1 = new obj();
  console.log(data1.a); // 37


  function obj2(){
    this.a = 37;
    return {a:38};
  }

  data1 = new obj2();
  console.log(data1.a); // 38

标签:function,console,log,bind,call,apply,var,obj,函数
From: https://www.cnblogs.com/neilniu/p/17138919.html

相关文章

  • 106、商城业务---消息队列---可靠抵达-发送端确认(ReturnCallback)
    1、编写配置#rabbitmq的抵达队列的发送端确认(ReturnCallback)spring.rabbitmq.publisher-returns=true#只要抵达队列,以异步方式优先回调我们这个returnconfirmspri......
  • 105、商城业务---消息队列---可靠抵达-发送端确认(ConfirmCallback)
    1、编写配置spring.rabbitmq.publisher-confirms=true2、在自己编写的Rabbit的配置类中重写RabbitTemplate......
  • Python报错TypeError: 'NoneType' object is not callable
    Python报错TypeError:'NoneType'objectisnotcallable 保存内容如下  检查src文件后没有发现问题,最终在公共方法找到原因注释掉return了,取消后问题解决 ......
  • this / call / apply /bind
    对this对象的理解this是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this的指向可以通过四种调用模式来判断。第一种是函数调用模式,当一个......
  • Cesium CallbackProperty(十五)
      Cesium中的entities可以随时间变化长度高度,主要依赖于CallbackProperty函数。因为使用CallbackProperty,cesium中一切可视化的要素都可以与时间联系起来。定义:new......
  • UF_CALL
    #defineUF_CALL(X)(report(__FILE__,__LINE__,#X,(X)))staticintreport(char*file,intline,char*call,intirc){ if(irc) { charmessg[133]; printf(......
  • Callable的基本使用和源码解读
    1使用java.util.concurrent.Callable是有返回值的多线程任务:publicinterfaceCallable<V>{Vcall()throwsException;}通过实现Callable接口,在call()方......
  • Android JetPack~ DataBinding(数据绑定)(一) 集成与使用
    近期将会梳理一下JetPack全家桶的使用,包括DataBinding,Room,ViewModel,LiveData,Navigation等。本来打算先写DataBinding的使用,没想到在17年的时候已经写过了,这里就补充一点......
  • malloc、calloc、realloc的区别
    malloc、calloc、realloc的区别1、C语言跟内存分配方式<1>从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量、stat......
  • Calling C++ Code From Go With SWIG
    http://zacg.github.io/blog/2013/06/06/calling-c-plus-plus-code-from-go-with-swig/ RecentlywhileworkingonaGobasedprojectIneededtousesomefunctio......