Der Unterschied zwischen JavaScript-Aufruf, Aufgerufenem, Aufrufer, Anwenden und Binden

(Die Realität ist dieses Ufer, der Traum ist das andere Ufer, getrennt durch einen turbulenten Fluss, und die Handlung ist eine Brücke über den Fluss. - Krylov)

Fügen Sie hier eine Bildbeschreibung ein

Forderung

Die call()-Methode ruft eine Funktion mit einem angegebenen this-Wert und einem oder mehreren individuell angegebenen Argumenten auf.
MDN-Link

Die Aufrufmethode kann eine Objekteigenschaft als Kontext einer anderen Objektmethode verwenden, beispielsweise im folgenden Code.

const obj = {
    
    
  name: '张三',
  age: 20,
  getData: function () {
    
    
    return `${
      
      this.name}的年龄是${
      
      this.age}`
  }
};
const obj2 = {
    
    
  name: '李四',
  age: 50,
  getData: function () {
    
    
    return `${
      
      this.name}的年龄已经${
      
      this.age}岁了`
  },
  getData2: function (sex, address) {
    
    
    return `${
      
      this.name}的年龄已经${
      
      this.age},性别${
      
      sex}, 他家住在${
      
      address}`;
  }
};
console.log(obj.getData()); // 使用自身属性和方法执行
console.log(obj.getData.call(obj2)); // 将obj2作为obj.getData方法的上下文来执行
console.log(obj2.getData2.call(obj, '男', '北京市')); // 将obj作为obj2.getData2方法的上下文来执行

Die Aufrufmethode kann den Kontext einer Funktion als Kontext einer anderen Funktion verwenden, um den Zweck der Vererbung zu erreichen

const Father = function () {
    
    
  this.name = '父亲';
  this.age = 60;
  this.address = '北京市';
  this.sex = '男';
  this.getData = function () {
    
    
    return `名称:${
      
      this.name} - 年龄:${
      
      this.age} - 地址:${
      
      this.address} - 性别:${
      
      this.sex}`;
  };
  this.getData2 = function (hobby) {
    
    
    return `名称:${
      
      this.name} - 年龄:${
      
      this.age} - 地址:${
      
      this.address} - 性别:${
      
      this.sex} - 爱好:${
      
      hobby}`;
  };
};
const father = new Father();
console.log(father.getData()); // 输入父函数自己的上下文
const Daughter = function () {
    
    
  // 此处call要写在第一行,这样避免其他的初始化被call覆盖
  // 此处call用意为继承Father对象的上下文
  Father.call(this);
  this.name = '女儿';
  this.age = 12;
  this.address = '河南';
  this.sex = '女';
};
const daughter = new Daughter();
console.log(daughter.getData()); // 虽然Daughter函数没有getData方法,但因为使用call,this指向了Father,所以就可以使用父函数的getData方法

Die Aufrufmethode kann einen Objektkontext als Kontext einer anderen Funktion verwenden

const obj = {
    
    
  name: '张三',
  getName: function () {
    
    
    return this.name;
  }
};
const Fun = function () {
    
    
  const data = ['姓名', this.getName()].join('');
  console.log(data);
};
Fun.call(obj); // 姓名张三

Schweigen

Der aufgerufene MDN-Link
ist eine Eigenschaft des Argumentobjekts. Es kann verwendet werden, um auf die aktuell ausgeführte Funktion innerhalb des Funktionskörpers dieser Funktion zu verweisen.

Wenn wir eine rekursive Berechnungsfunktion wie den folgenden Code schreiben möchten, ändert sich mit der Änderung des Funktionsnamens auch der Funktionsname des internen Codes. Und wenn es sich um eine anonyme Funktion handelt, ist eine Rekursion nicht möglich.

const fun = function (x) {
    
    
  if (x === 0) {
    
    
    return;
  } else {
    
    
    return fun(x - 1);
  }
};

Wenn der Aufrufer angezeigt wird, kann er sich auf den Funktionskontext beziehen, der derzeit im Funktionskörper der Funktion ausgeführt wird, z. B. auf den folgenden Code. Der Zweck der Rekursion kann auch durch Aufzeichnen des internen Kontexts erreicht werden.

const fun2 = function (x) {
    
    
  if (x === 0) {
    
    
    return;
  } else {
    
    
    return arguments.callee(x - 1);
  }
};

Aber warum ist der Aufgerufene im strengen ES5-Modus deaktiviert?

const global = this;
const sillyFunction = function (recursed) {
    
    
  if (!recursed)
    return arguments.callee(true);
  if (this !== global)
    console.log("This is: " + this);
  else
    console.log("This is the global");
}
sillyFunction();

Aus den obigen Codeergebnissen wissen wir, dass der von jedem Aufrufer erhaltene This unterschiedlich ist, und wenn in einem Unternehmen mehrere verschachtelte Argumente vorhanden sind, sind auch die Wartungskosten enorm.
Schaden des Aufgerufenen
Der beste Weg besteht also darin, Geschäftsvorgänge durch Benennen von Funktionen durchzuführen. Obwohl dies problematischer ist, werden die Wartungskosten späterer Codes erheblich reduziert und die Leistung wird höher sein.

Anrufer

Gibt die Funktion zurück, die die angegebene Funktion aufruft, z. B. den folgenden Code.


const Fun = function () {
    
    
  this.fun2 = function () {
    
    
    console.log(this.fun2.caller.name);
  }
};
(function Test () {
    
    
  new Fun().fun2(); // Test
})();

Der Aufrufer ist in der Regel bei der Verfolgung geschäftlicher Aufrufketten nützlich, er kann den Funktionsnamen und den Funktionstext ausdrucken

anwenden

Die Funktion von apply ist dieselbe wie die von call, außer dass der zweite Parameter ein Array und nicht mehrere ist.

const obj = {
    
    
  name: '张三',
  age: 20,
  getData: function () {
    
    
    return `${
      
      this.name}的年龄是${
      
      this.age}`
  }
};
const obj2 = {
    
    
  name: '李四',
  age: 50,
  getData: function () {
    
    
    return `${
      
      this.name}的年龄已经${
      
      this.age}岁了`
  },
  getData2: function (sex, address) {
    
    
    return `${
      
      this.name}的年龄已经${
      
      this.age},性别${
      
      sex}, 他家住在${
      
      address}`;
  }
};
console.log(obj.getData()); // 使用自身属性和方法执行
console.log(obj.getData.apply(obj2)); // 将obj2作为obj.getData方法的上下文来执行
console.log(obj2.getData2.apply(obj, ['男', '北京市'])); // 将obj作为obj2.getData2方法的上下文来执行

binden

Die bind()-Methode erstellt eine neue Funktion. Wenn bind() aufgerufen wird, wird dies dieser neuen Funktion als erster Parameter von bind() angegeben und die verbleibenden Parameter werden als Parameter der neuen Funktion zum Aufrufen verwendet. Zum Beispiel der folgende Code

MDN-Link

global.x = -1;
const data = {
    
    
  x: 42,
  getX: function () {
    
    
    return this.x;
  }
};
console.log(data.getX()); // 42
const unboundGetX = data.getX;
console.log(unboundGetX());
// undefind 因为函数被赋值给unboundGetX时并没有执行,再次执行时,使用的上下文就是全局的了

const boundGetX = unboundGetX.bind(data);
// 那么为了解决this指向的问题,就可以使用.bind 通过指定参数的形式来指定this指向

console.log(boundGetX()); // 42

Anwendung des Bind-in-Timers

function LateBloomer() {
    
    
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
    
    
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
    
    
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒钟后,调用 'declare' 方法

Anwendung von Bind in asynchronen Versprechen

Wenn es ein Geschäftsszenario für asynchrone parallele Abfragen gibt, reduzieren Sie die Speicher- und CPU-Auslastung, um die Häufigkeit zu steuern. Daher ist es notwendig, die auszuführenden asynchronen Funktionen zu trennen und sie zur Ausführung in den asynchronen Pool zu stellen.

const queryAll = async () => {
    
    
  const dbCollection = {
    
    }; // mysql or mongodb
  const getUser = async function () {
    
     dbCollection.get };
  const getMobile = async function  () {
    
     dbCollection.get };
  const getAddress = async function () {
    
     dbCollection.get };
  const getSex = async function () {
    
     dbCollection.get };
  const getHeight = async function () {
    
     dbCollection.get };
  const getWeight = async function () {
    
     dbCollection.get };
  // 每两个一组放入异步池,实际情况可能需要遍历并编写分组代码
  const pool= [
    [
      getUser.bind(this),
      getMobile.bind(this)
    ],
    [
      getAddress.bind(this),
      getSex.bind(this)
    ],
    [
      getHeight.bind(this),
      getWeight.bind(this),
    ]
  ];
  for (const item of pool) {
    
    
    const result = await Promise.all(item);
    // ....一些集合处理
  }
};

Bind-Parameterübergabe

Sowohl bind als auch call können Parameter übergeben.

const data = {
    
    
  x: 42,
  getX: function (y, z) {
    
    
    return this.x + (y || 0) + (z || 0);
  }
};
const data2 = {
    
    
  x: 10,
  getX: function (y, z) {
    
    
    return this.x + (y || 0) + (z || 0);
  }
};
const unboundGetX = data.getX;
const boundGetX = unboundGetX.bind(data2, 1, 2);
console.log(boundGetX()); // 45

bind löst das Problem der gewöhnlichen Funktion dieses Zeigens


const Persion = function () {
    
     //定义构造函数
  this.age = 0; // 定义age
  setInterval(function () {
    
    
    this.age++; // 这个时候输出为NaN 因为setInterval的this指向的是全局
    console.log(this.age);
  }, 1000)

}
new Persion();

// 那么为了解决this问题,就可以使用提前赋值this的方式

const Persion2 = function () {
    
     //定义构造函数
  this.age = 0; // 定义age
  const that = this;
  setInterval(function () {
    
    
    that.age++; // 这个时候输出为NaN 因为setInterval的this指向的是全局
    console.log(that.age);
  }, 1000)

}
new Persion2();

// 也可以使用bind的方式
const Persion3 = function () {
    
     //定义构造函数
  this.age = 0; // 定义age
  setInterval(function () {
    
    
    this.age++; // 这个时候输出为NaN 因为setInterval的this指向的是全局
    console.log(this.age);
  }.bind(this), 1000);
}
new Persion3();

Guess you like

Origin blog.csdn.net/qq_42427109/article/details/130511055