Heim > Web-Frontend > js-Tutorial > Eine interessante Zeile JS-Code

Eine interessante Zeile JS-Code

coldplay.xixi
Freigeben: 2020-10-29 17:07:42
nach vorne
2172 Leute haben es durchsucht

In der Spalte

Javascript wird ein Codesatz im Detail vorgestellt.

Eine interessante Zeile JS-Code

Wir sehen im Quellcode auf Framework-Ebene oft einen Code ähnlich dem folgenden, wie zum Beispiel:

var toStr1 = Function.prototype.call.bind(Object.prototype.toString);复制代码
Nach dem Login kopieren

In diesem Code werden anscheinend sowohl die Aufrufmethode als auch die Bindungsmethode verwendet ein bisschen schwindelig! Was um alles in der Welt willst du tun?

Kein Problem, rufen wir es auf und versuchen, verschiedene Typen zu übergeben. Der Effekt ist wie folgt:

console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"复制代码
Nach dem Login kopieren

Sie können den Ergebnissen entnehmen, dass die Hauptfunktion dieser Methode darin besteht, den Typ des Objekts zu erkennen. Normalerweise sehen wir zur Typerkennung jedoch häufiger die folgende Codeimplementierung:

var toStr2 = obj => Object.prototype.toString.call(obj);console.log(toStr2({}));      // "[object Object]"console.log(toStr2([]));      // "[object Array]"console.log(toStr2(123));     // "[object Number]"console.log(toStr2("abc"));   // "[object String]"console.log(toStr2("abc"));   // "[object String]"console.log(toStr2(new Date));// "[object Date]"复制代码
Nach dem Login kopieren

Studenten, die mit Bind und Call vertraut sind, sollten wissen, dass die beiden Methoden im Wesentlichen gleich sind und die zweite Methode prägnanter ist und nur einen Aufruf verwendet Wir können die gewünschten Funktionen erhalten und die Codelogik ist klarer und leichter zu verstehen. Aber warum wird die erste unter vielen Frameworks häufiger verwendet?

Tatsächlich besteht der Hauptgrund darin, die Verschmutzung durch Prototypen zu verhindern. Wenn wir beispielsweise die Methode Object.prototype.toString im Geschäftscode überschreiben, ist dies der zweite Weg Das Schreiben wird nicht korrekt sein. Das Ergebnis ist, dass die erste Schreibweise immer noch möglich ist. Versuchen wir es mit dem Code: 防止原型污染,比如我们在业务代码中覆写了Object.prototype.toString方法,第二种写法将得不到正确的结果,而第一种写法仍然可以。我们用代码来来试试:

var toStr1 = Function.prototype.call.bind(Object.prototype.toString);var toStr2 = obj => Object.prototype.toString.call(obj);Object.prototype.toString = function(){  return'toString方法被覆盖!';
}// 接着我们再调用上述方法// toStr1调用结果如下:console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"// toStr2调用结果如下:console.log(toStr2({}));      // "toString方法被覆盖!"console.log(toStr2([]));      // "toString方法被覆盖!"console.log(toStr2(123));     // "toString方法被覆盖!"console.log(toStr2("abc"));   // "toString方法被覆盖!"console.log(toStr2("abc"));   // "toString方法被覆盖!"console.log(toStr2(new Date));// "toString方法被覆盖!"复制代码
Nach dem Login kopieren

Eine interessante Zeile JS-Code

Eine interessante Zeile JS-Code

结果很明显。第一种方法仍然能正确得到结果,而第二种则不行!那么为什么会这样呢?我们知道bind函数返回结果是一个函数,这个函数是函数内部的函数,会被延迟执行,那么很自然联想到这里可能存在闭包!因为闭包可以保持内部函数执行时的上下文状态

// 模拟实现call// ES6实现Function.prototype.mycall = function (context) {
  context = context ? Object(context) : window;  var fn = Symbol();
  context[fn] = this;  let args = [...arguments].slice(1);  let result = context[fn](...args);  delete context[fn]  return result;
}// 模拟实现bindFunction.prototype.mybind = function (context) {  if (typeof this !== "function") {    throw new Error("请使用函数对象调用我,谢谢!");
  }  var self = this;  var args = Array.prototype.slice.call(arguments, 1);  var fNOP = function () { };  var fBound = function () {    var bindArgs = Array.prototype.slice.call(arguments);    return self.myapply(this instanceof fNOP ? this : context, args.concat(bindArgs));
  }

  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();  return fBound;
}// 模拟实现apply// ES6实现Function.prototype.myapply = function (context, arr) {
    context = context ? Object(context) : window;    var fn = Symbol();
    context[fn] = this;    let result;    if (!arr) {
        result = context[fn]();
    } else {
        result = context[fn](...arr);
    }    delete context[fn]    return result;
}var toStr1 = Function.prototype.mycall.mybind(Object.prototype.toString);console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"复制代码
Nach dem Login kopieren
Nach dem Login kopieren
Eine interessante Zeile JS-Code🎜🎜Eine interessante Zeile JS-Code🎜🎜Die Ergebnisse sind offensichtlich. Die erste Methode liefert immer noch das richtige Ergebnis, die zweite jedoch nicht! Warum passiert das also? Wir wissen, dass das Rückgabeergebnis der Bindungsfunktion eine Funktion innerhalb der Funktion ist und in der Ausführung verzögert wird. Daher ist es natürlich, dass hier ein Abschluss vorliegt. Weil Abschlüsse den Kontextstatus beibehalten können, wenn interne Funktionen ausgeführt werden. In modernen Browsern wurden jedoch sowohl Aufruf als auch Bindung intern von der js-Engine implementiert, und wir haben keine Möglichkeit zum Debuggen! Aber wir können die interne Logik der Engine anhand des von polly-fill bereitgestellten ungefähren Implementierungsquellcodes verstehen. Das Folgende ist die in diesem Artikel debuggte Demo: 🎜
// 模拟实现call// ES6实现Function.prototype.mycall = function (context) {
  context = context ? Object(context) : window;  var fn = Symbol();
  context[fn] = this;  let args = [...arguments].slice(1);  let result = context[fn](...args);  delete context[fn]  return result;
}// 模拟实现bindFunction.prototype.mybind = function (context) {  if (typeof this !== "function") {    throw new Error("请使用函数对象调用我,谢谢!");
  }  var self = this;  var args = Array.prototype.slice.call(arguments, 1);  var fNOP = function () { };  var fBound = function () {    var bindArgs = Array.prototype.slice.call(arguments);    return self.myapply(this instanceof fNOP ? this : context, args.concat(bindArgs));
  }

  fNOP.prototype = this.prototype;
  fBound.prototype = new fNOP();  return fBound;
}// 模拟实现apply// ES6实现Function.prototype.myapply = function (context, arr) {
    context = context ? Object(context) : window;    var fn = Symbol();
    context[fn] = this;    let result;    if (!arr) {
        result = context[fn]();
    } else {
        result = context[fn](...arr);
    }    delete context[fn]    return result;
}var toStr1 = Function.prototype.mycall.mybind(Object.prototype.toString);console.log(toStr1({}));      // "[object Object]"console.log(toStr1([]));      // "[object Array]"console.log(toStr1(123));     // "[object Number]"console.log(toStr1("abc"));   // "[object String]"console.log(toStr1(new Date));// "[object Date]"复制代码
Nach dem Login kopieren
Nach dem Login kopieren

Eine interessante Zeile JS-Code

上述的实现略去一些健壮性的代码,仅保留核心逻辑,具体的实现细节这里不做解释,有兴趣的可以自己研究,从devtools我们看到mybind形成的闭包确实在函数对象toStr1的作用域上!

当然如果你对原型链有深刻理解的话,其实这句有趣的代码还可以写成如下方式:

var toStr3 = Function.call.bind(Object.prototype.toString);var toStr4 = Function.call.call.bind(Object.prototype.toString);var toStr5 = Function.call.call.call.bind(Object.prototype.toString);// 甚至可以这么写。。。var toStr6 = (()=>{}).call.bind(Object.prototype.toString);复制代码
Nach dem Login kopieren

-END-

相关免费学习推荐:javascript(视频)

Das obige ist der detaillierte Inhalt vonEine interessante Zeile JS-Code. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.im
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