Heim > Web-Frontend > js-Tutorial > Implementieren Sie Aufruf, Bindung und Instanz von manuell in js

Implementieren Sie Aufruf, Bindung und Instanz von manuell in js

angryTom
Freigeben: 2020-02-15 17:56:13
nach vorne
2659 Leute haben es durchsucht

In js kann call den Sinn ändern, bind kann den Sinn ändern und eine Funktion zurückgeben. Dieser Artikel führt Sie Schritt für Schritt durch die Implementierung dieser Funktionen und ich hoffe, dass er Freunden, die JavaScript lernen, hilfreich sein wird.

Implementieren Sie Aufruf, Bindung und Instanz von manuell in js

Vorwort

Heutzutage wird die Front-End-Schwelle immer höher, und das ist sie auch nicht mehr nur schreiben. Die Seite ist so einfach. Modularisierung, Automatisierung, Cross-End-Entwicklung usw. werden nach und nach zu Anforderungen, die jedoch auf unserem soliden Fundament aufgebaut werden müssen. Unabhängig davon, wie sich Rahmen und Modell ändern, können wir uns nur durch die Festlegung der Grundprinzipien schnell an Marktveränderungen anpassen. Hier sind einige häufig verwendete Quellcode-Implementierungen:

Aufrufimplementierung

Bind-Implementierung

Neue Implementierung

Instanz der Implementierung

Objekt .create-Implementierung

Deep-Copy-Implementierung

Veröffentlichungs- und Abonnementmodus

Aufruf

Aufruf wird zum Ändern verwendet die Funktion, auf die this zeigt, und führen Sie die Funktion aus

(empfehlen Sie js-Tutorial, willkommen zum Lernen!)

Im Allgemeinen gilt: Wer die Funktion aufruft, ist dies der Funktion zeigt auf wen. Wenn Sie diese Funktion nutzen, indem Sie die Funktion als Attribut des Objekts verwenden und vom Objekt aus aufrufen, können Sie diesen Punkt der Funktion ändern. Dies wird als implizite Bindung bezeichnet. Apply implementiert dieselbe Methode, ändert lediglich die Eingabeparameterform.

let obj = {
  name: 'JoJo'
}
function foo(){
  console.log(this.name)
}
obj.fn = foo
obj.fn() // log: JOJO
Nach dem Login kopieren

implementiert

Function.prototype.mycall = function () {
  if(typeof this !== 'function'){
    throw 'caller must be a function'
  }
  let othis = arguments[0] || window
  othis._fn = this
  let arg = [...arguments].slice(1)
  let res = othis._fn(...arg)
  Reflect.deleteProperty(othis, '_fn') //删除_fn属性
  return res
}
Nach dem Login kopieren

mit

let obj = {
  name: 'JoJo'
}
function foo(){
  console.log(this.name)
}
foo.mycall(obj) // JoJo
Nach dem Login kopieren

bind

bind wird verwendet, um diesen Punkt der Funktion zu ändern und a zurückzugeben Funktion

Hinweis:

Dies als Konstruktoraufruf verweist auf

Beibehalten der Prototypenkette

Function.prototype.mybind = function (oThis) {
  if(typeof this != 'function'){
    throw 'caller must be a function'
  }
  let fThis = this
  //Array.prototype.slice.call 将类数组转为数组
  let arg = Array.prototype.slice.call(arguments,1)
  let NOP = function(){}
  let fBound = function(){
    let arg_ = Array.prototype.slice.call(arguments)
    // new 绑定等级高于显式绑定
    // 作为构造函数调用时,保留指向不做修改
    // 使用 instanceof 判断是否为构造函数调用
    return fThis.apply(this instanceof fBound ? this : oThis, arg.concat(arg_))
  }
  // 维护原型
  if(this.prototype){
    NOP.prototype = this.prototype
  }
  fBound.prototype = new NOP()
  return fBound
}
Nach dem Login kopieren

Verwenden Sie

let obj = {
  msg: 'JoJo'
}
function foo(msg){
  console.log(msg + '' + this.msg)
}
let f = foo.mybind(obj)
f('hello') // hello JoJo
Nach dem Login kopieren

new

new verwendet den Konstruktor, um ein Instanzobjekt zu erstellen und fügt dieses Attribut und diese Methode zum Instanzobjekt hinzu. Der Prozess von

new:

Neues Objekt erstellen

Neues Objekt __proto__ zeigt auf Konstruktorprototyp

Neues Objekt fügt Attributmethode hinzu (dies zeigt auf)

Gibt ein neues Objekt zurück, auf das verwiesen wird this

function new_(){
  let fn = Array.prototype.shift.call(arguments)
  if(typeof fn != 'function'){
    throw fn + ' is not a constructor'
  }
  let obj = {}
  obj.__proto__ = fn.prototype
  let res = fn.apply(obj, arguments)
  return typeof res === 'object' ? res : obj
}
Nach dem Login kopieren

instanceof

instanceof bestimmt, ob der Prototyp links in der Prototypenkette rechts vorhanden ist.

Implementierungsidee: Suchen Sie den Prototyp Schicht für Schicht. Wenn der endgültige Prototyp null ist, beweist dies, dass er nicht in der Prototypkette vorhanden ist.

function instanceof_(left, right){
  left = left.__proto__
  while(left !== right.prototype){
    left = left.__proto__ // 查找原型,再次while判断
    if(left === null){
      return false
    }
  }
  return true
}
Nach dem Login kopieren

Object.create

Object.create erstellt ein neues Objekt und verwendet ein vorhandenes Objekt, um das __proto__ des neu erstellten Objekts bereitzustellen. Der zweite optionale Parameter ist Das Attributbeschreibungsobjekt

function objectCreate_(proto, propertiesObject = {}){
  if(typeof proto !== 'object' || typeof proto !== 'function' || proto !== null){
    throw('Object prototype may only be an Object or null:'+proto)
  }
  let res = {}
  res.__proto__ = proto
  Object.defineProperties(res, propertiesObject)
  return res
}
Nach dem Login kopieren

Deep copy

Deep copy erstellt eine identische Kopie des Objekts, aber die Referenzadressen der beiden sind unterschiedlich. Deep Copy ist eine gute Wahl, wenn Sie ein Objekt verwenden, das Originalobjekt jedoch nicht ändern möchten. Hier ist eine Basisversion implementiert, die nur tiefe Kopien von Objekten und Arrays erstellt.

Implementierungsidee: Objekte durchqueren, Rekursion verwenden, um Referenztypen weiter zu kopieren und Basistypen direkt zuweisen

function deepClone(origin) {
  let toStr = Object.prototype.toString
  let isInvalid = toStr.call(origin) !== '[object Object]' && toStr.call(origin) !== '[object Array]'
  if (isInvalid) {
    return origin
  }
  let target = toStr.call(origin) === '[object Object]' ? {} : []
  for (const key in origin) {
    if (origin.hasOwnProperty(key)) {
      const item = origin[key];
      if (typeof item === 'object' && item !== null) {
        target[key] = deepClone(item)
      } else {
        target[key] = item
      }
    }
  }
  return target
}
Nach dem Login kopieren

Veröffentlichungs- und Abonnementmodus

Veröffentlichen und Abonnementmodus in der Praxis Während der Entwicklung kann eine vollständige Entkopplung zwischen Modulen erreicht werden, und Module müssen sich nur auf die Registrierung und Auslösung von Ereignissen konzentrieren.

Das Veröffentlichungs- und Abonnementmodell implementiert EventBus:

class EventBus{
  constructor(){
    this.task = {}
  }

  on(name, cb){
    if(!this.task[name]){
      this.task[name] = []
    }
    typeof cb === 'function' && this.task[name].push(cb)
  }

  emit(name, ...arg){
    let taskQueen = this.task[name]
    if(taskQueen && taskQueen.length > 0){
      taskQueen.forEach(cb=>{
        cb(...arg)
      })
    }
  }

  off(name, cb){
    let taskQueen = this.task[name]
    if(taskQueen && taskQueen.length > 0){
      let index = taskQueen.indexOf(cb)
      index != -1 && taskQueen.splice(index, 1)
    }
  }

  once(name, cb){
    function callback(...arg){
      this.off(name, cb)
      cb(...arg)
    }
    typeof cb === 'function' && this.on(name, callback)
  }
}
Nach dem Login kopieren

Verwenden Sie

let bus = new EventBus()
bus.on('add', function(a,b){
  console.log(a+b)
})
bus.emit('add', 10, 20) //30
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonImplementieren Sie Aufruf, Bindung und Instanz von manuell in js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:cnblogs.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage