Home  >  Article  >  Web Front-end  >  Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

coldplay.xixi
coldplay.xixiforward
2021-03-16 09:56:112498browse

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

Contents

  • Preface Questions
  • 1. The point of this
  • 2. Call and apply
  • 3. Simulate a call
  • 4. Bind
  • 5. Ending

Preface Thought Questions

I remember that when I was looking for an internship, I would always add a sentence on my resume-familiar with JS, such as this, call, apply, etc...

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

(Free learning recommendation: javascript video tutorial)

And every time When submitting my resume, I will go through the following steps

  • Before the interview, ask Du Niang - what types of directions can this be divided into? What is the difference between call and apply? My confidence has soared from 0% to 50%;
  • During the interview, the interviewer throws a few questions at random, and I can give "firm" answers, but the results are always unsatisfactory...
  • After the interview, I will delete this item on my resume in shame. And when I submitted my resume later, I added this item again...

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

Thinking Questions

The following questions are what I searched on the Internet If you can answer the hot questions easily and have clear ideas, you might as well give them a like (after all, it consumes a lot of brain cells). If you can give me some advice in the comments One or two, even better! ! !

Fill in the blank:

  • Executing the [ ] function in Javascript will create a new function, which has the same characteristics as the called function With the same function body, when the target function is called, the this value points to the first parameter.

Q&A:

  • Could you please talk about the types of pointing functions that change the this pointer inside a function, and what are their differences?
  • What kind of points can this be divided into?

Code analysis questions:

var name = 'window'var person1 = {
  name: 'person1',
  show1: function () {
    console.log(this.name)
  },
  show2: () => console.log(this.name),
  show3: function () {
    return function () {
      console.log(this.name)
    }
  },
  show4: function () {
    return () => console.log(this.name)
  }}var person2 = { name: 'person2' }person1.show1()person1.show1.call(person2)person1.show2()person1.show2.call(person2)person1.show3()()person1.show3().call(person2)person1.show3.call(person2)()person1.show4()()person1.show4().call(person2)person1.show4.call(person2)()

1. The point of this

Enter "this on Baidu and Google There must be thousands of articles with the "pointing to" keyword, but you don't have to read all the articles in order to master it in all aspects and without blind spots, right? So it’s better to sort out a solid framework and fill it in according to our ideas.

Mind Map

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

The essence of this section:

  • this always points to an object (in non-strict mode). The specific object pointed to is dynamically bound based on the function's execution environment at runtime, rather than the environment when the function is declared;
  • Except for the uncommon with and eval situations, In practical applications, this point can be roughly divided into four types:
    • as an object method call;
    • as an ordinary function call;
    • constructor call;
    • call or apply call;
    • In the arrow function, this points to this in the upper scope of the function;
  • Constructor and The difference between ordinary functions lies in the way is called;
  • A,call(B) => can be understood as calling the A method within the scope of B;

Analysis

1. Calling a method as an object

When a function is called as a method of an object, this points to the Object

var obj = {
    a: 'yuguang',
    getName: function(){
        console.log(this === obj);
        console.log(this.a);
    }};obj.getName(); // true yuguang

2. Called as an ordinary function

When the function is not called as a property of the object, but as an ordinary function, this is always Point to the global object (in the browser, usually the Window object)

window.name = 'yuguang';var getName = function(){
    console.log(this.name);};getName(); // yuguang

or the following confusing code:

window.name = '老王'var obj = {
    name: 'yuguang',
    getName: function(){
        console.log(this.name);
    }};var getNew = obj.getName;getNew(); // 老王

In the strict mode of ES5, this is specified as not Will point to the global object, but undefined

3. Constructor call

Except for some built-in functions, most functions in Js can Become constructors, they are no different from ordinary functions

The difference between constructors and normal functions is the wayis called:
When the new operator calls a function, it always returns an object, and this usually points to this object

var MyClass = function(){
    this.name = 'yuguang';}var obj = new MyClass();obj.name; // yuguang

However, if an object object is explicitly returned, the result of this operation will eventually return this object.

var MyClass = function () {
    this.name = 1;
    return {
        name: 2
    }}var myClass = new MyClass(); console.log('myClass:', myClass); // { name: 2}

As long as the constructor does not return any data explicitly, or returns non-object type data, the above problems will not occur.

4. Call or apply

Compared with ordinary function calls, call and apply can dynamically change the this of the function

var obj1 = {
    name: 1,
    getName: function (num = '') {
        return this.name + num;
    }};var obj2 = {
    name: 2,};// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数console.log(obj1.getName()); // 1console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4

5. Arrow function

The arrow function will not create its own this, it will only inherit this from the upper level of its own scope chain.

因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

this.val = 2;var obj = {
    val: 1,
    getVal: () => {
        console.log(this.val);
    }}obj.getVal(); // 2

常见的坑

就像标题一样,有的时候this会指向undefined

情况一

var obj = {
    name: '1',
    getName: function (params) {
        console.log(this.name)
    }};obj.getName();var getName2 = obj.getName;getName2();

这个时候,getName2()作为普通函数被调用时,this指向全局对象——window。

情况二

当我们希望自己封装Dom方法,来精简代码时:

var getDomById = function (id) {
    return document.getElementById(id);};getDomById('p1') //dom节点

那么我们看看这么写行不行?

var getDomById = document.getElementByIdgetDomById('p1') // Uncaught TypeError: Illegal invocation(非法调用)

这是因为:

  • 当我们去调用document对象的方法时,方法内的this指向document
  • 当我们用getId应用document内的方法,再以普通函数的方式调用,函数内容的this就指向了全局对象。

利用call和apply修正情况二

document.getElementById = (function (func) {
    return function(){
        return func.call(document, ...arguments)
    }})(document.getElementById) // 利用立即执行函数将document保存在作用域中

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

二、call和apply

不要因为它的“强大”而对它产生抗拒,了解并熟悉它是我们必须要做的,共勉!

思维导图

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

1.call和apply区别

先来看区别,是因为它们几乎没有区别,下文代码实例call和apply都可以轻易的切换。

当它们被设计出来时要做到的事情一摸一样,唯一的区别就在于传参的格式不一样

  • apply接受两个参数
    • 第一个参数指定了函数体内this对象的指向
    • 第二个参数为一个带下标的参数集合(可以是数组或者类数组)
  • call接受的参数不固定
    • 第一个参数指定了函数体内this对象的指向
    • 第二个参数及以后为函数调用的参数

因为在所有(非箭头)函数中都可以通过arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,它本身就是一个类数组,我们apply在实际使用中更常见一些。

call是包装在apply上面的语法糖,如果我们明确的知道参数数量,并且希望展示它们,可以使用call。

当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会默认指向宿主对象,在浏览器中则是window

借用其他对象的方法

我们可以直接传null来代替任意对象

Math.max.apply(null, [1, 2, 3, 4, 5])

2.call和apply能做什么?

使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数——来时MDN

  • 调用构造函数来实现继承;
  • 调用函数并且指定上下文的 this;
  • 调用函数并且不指定第一个参数;

1.调用构造函数来实现继承

通过“借用”的方式来达到继承的效果:

function Product(name, price) {
	this.name = name;
	this.price = price;}function Food(name, price) {
	Product.call(this, name, price); //
	this.category = food;}var hotDog = new Food('hotDog', 20);

2.调用函数并且指定上下文的 this

此时this被指向了obj

function showName() {
    console.log(this.id + ':' + this.name);};var obj = {
    id: 1,
    name: 'yuguang'};showName.call(obj)

3.使用call单纯的调用某个函数

Math.max.apply(null, [1,2,3,10,4,5]); // 10

Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article

三、模拟实现一个call

先来看一下call帮我们需要做什么?

var foo = {
	value: 1};function show() {
	console.log(this.value);};show.call(foo); //1

就像解方程,要在已知条件中寻找突破哦口:

  • call 使得this的指向变了,指向了foo;
  • show 函数被执行了;
  • 传入的参数应为 this + 参数列表;

第一版代码

上面提到的3点,仅仅完成了一点,且传入的参数

var foo = {
    value: 1};function show() {
    console.log(this.value);};Function.prototype.setCall = function (obj) {
    console.log(this); // 此时this指向show
    obj.func = this; // 将函数变成对象的内部属性
    obj.func(obj.value); // 指定函数
    delete obj.func // 删除函数,当做什么都没发生~}show.setCall(foo);

第二版代码

为了解决参数的问题,我们要能获取到参数,并且正确的传入:

var foo = {
    value: 1};function show(a, b) {
    console.log(this.value);
    console.log(a + b);};Function.prototype.setCall = function (obj) {
    obj.fn = this; // 将函数变成对象的内部属性
    var args = [];
    for(let i = 1; i <p>此时,我们就可以做到,传入多个参数的情况下使用call了,但是如果你仅想用某个方法呢?</p><p><strong>第三版代码</strong></p><pre class="brush:php;toolbar:false">Function.prototype.setCall = function (obj) {
    var obj = obj || window;
    obj.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i <p><strong>四、bind</strong></p><blockquote><p>bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用 —— MDN</p></blockquote><p>提到了<strong>call</strong>和<strong>apply</strong>,就绕不开<strong>bind</strong>。我们试着来模拟一个bind方法,以便加深我们的认识:</p><pre class="brush:php;toolbar:false">Function.prototype.bind = function (obj) {
    var _this = this; // 保存调用bind的函数
    var obj = obj || window; // 确定被指向的this,如果obj为空,执行作用域的this就需要顶上喽
    return function(){
        return _this.apply(obj, arguments); // 修正this的指向
    }};var obj = {
    name: 1,
    getName: function(){
        console.log(this.name)
    }};var func = function(){
    console.log(this.name);}.bind(obj);func(); // 1

这样看上去,返回一个原函数的拷贝,并拥有指定的 this 值,还是挺靠谱的哦~

写在最后

The first part of the basic part of JavaScript internal skills. To summarize, this series is greatly encouraged and inspired by Yan Yu. There will be about 15 articles in this series. They are all the ones we interview most frequently, but they are often criticized at work. Ignored.

Related free learning recommendations: javascript(Video)

The above is the detailed content of Detailed explanation of this pointer, allowing you to understand this, call, and apply in one article. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete