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.
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
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 }
mit
let obj = { name: 'JoJo' } function foo(){ console.log(this.name) } foo.mycall(obj) // JoJo
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 }
Verwenden Sie
let obj = { msg: 'JoJo' } function foo(msg){ console.log(msg + '' + this.msg) } let f = foo.mybind(obj) f('hello') // hello JoJo
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 }
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 }
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 }
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 }
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) } }
Verwenden Sie
let bus = new EventBus() bus.on('add', function(a,b){ console.log(a+b) }) bus.emit('add', 10, 20) //30
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!