Home > Article > Web Front-end > JavaScript anti-colliization this [Translation]_javascript skills
This article mainly talks about the methods of curating and de-coring this in JavaScript. The topic comes from a tweet.
1. Anti- Currying (Uncurrying) this
Uncurrying this means: converting a method with the following signature:
obj.foo(arg1, arg2) into another one A function with the following signature:
foo(obj, arg1, arg2) If you want to know the use of this, we first have to understand the general method.
2. General method ( Generic methods)
Usually, a specific method can only be used on a certain type of object instance. However, there are some methods that can also be used on other types of object instances. If so, that would be very useful, for example:
This can be regarded as the implicit parameter of the forEach() method. Objects that meet the following three rules can call the forEach() method and can be used as the implicit this:
•Has length attribute: this.length
•Ability to access object elements by index: this[i]
•Ability to check the existence of attributes: i in this
arguments object (contains a function All actual parameters of the call) are not an Array instance, so it cannot directly call the forEach() method. But it meets the three conditions for calling the forEach method. In order for the object to call the forEach() method, we only need to make the hidden Contains the this parameter as an explicit parameter. Fortunately, every function has a call() method that allows us to do something:
3. Several uses of anti-corrying this
Use case 1: Call a method through map(). The Array.prototype.map() method allows you to call a function on each element in an array. But what if you want to call a method instead of a function? Yes Use anti-colliization to do this:
Array.map
, Array.forEach and other methods.<br><br><strong>4. Implement uncurryThis() <br></strong>The following are three ways to implement the uncurryThis method. <br><br>Implementation 1: Written by Brendan Eich<br><div class="codetitle">
<span><a style="CURSOR: pointer" data="60855" class="copybut" id="copybut60855" onclick="doCopy('code60855')"><u>Copy code</u></a></span> The code is as follows:</div>
<div class="codebody" id="code60855"> <br>Function.prototype.uncurryThis = function () { <br>var f = this; <br>return function () { <br>var a = arguments; <br>return f.apply(a[0], [].slice.call(a, 1)); <br>}; <br>}; <br>
</div>
<br>Implementation 2: Calling an anti-curried function is equivalent to calling its call() method on the original method. We can borrow this call() method through the bind() method: <br><div class="codetitle">
<span><a style="CURSOR: pointer" data="87558" class="copybut" id="copybut87558" onclick="doCopy('code87558')"><u>Copy code</u></a></span> The code is as follows:</div>
<div class="codebody" id="code87558"> <br>Function.prototype.uncurryThis = function () { <br>return this. call.bind(this); <br>}; <br>
</div> <br>Implementation 3: The defined standard method is best not to rely on too many external methods. In addition, the bind() method is only available in ECMAScript 5 .So we rewrote the above implementation 2 as follows: <br><br><div class="codetitle">
<span><a style="CURSOR: pointer" data="7449" class="copybut" id="copybut7449" onclick="doCopy('code7449')"><u>Copy code </u></a></span> The code is as follows: </div>
<div class="codebody" id="code7449"> <br>Function.prototype.uncurryThis = function () { <br>var f = this; <br>return function () { <br>return f.call.apply(f, arguments) <br>}; <br>}; <br>
</div> <br>The above code still implicitly borrows the call() method. <br><br><strong>5. The reverse operation is also very useful - corrify this <br></strong>The reverse operation of uncurryThis() is called curryThis(). It converts the first parameter of the original function into the implicit this parameter. If there is an original function: <br><div class="codetitle">
<span><a style="CURSOR: pointer" data="74336" class="copybut" id="copybut74336" onclick="doCopy('code74336')"><u>Copy code</u></a></span> The code is as follows:</div>
<div class="codebody" id="code74336"> <br>function(self, arg) { <br>return self.foo arg; <br> } <br>
</div> <br>After currying this, it becomes: <br><div class="codetitle">
<span><a style="CURSOR: pointer" data="73673" class="copybut" id="copybut73673" onclick="doCopy('code73673')"><u>Copy the code</u></a></span> The code is as follows:</div>
<div class="codebody" id="code73673"> <br>function(arg) { <br>return this.foo arg; <br>} <br>
</div> <br>Use case: Let a method pass its this value to an embedded function. Original writing: <br><div class="codetitle">
<span><a style="CURSOR: pointer" data="49106" class="copybut" id="copybut49106" onclick="doCopy('code49106')"><u> Copy code </u></a></span> The code is as follows: </div>
<div class="codebody" id="code49106">
<br>var obj = {<br> method : function (arg) {<br> var self = this; // Let the nested function access this<br> someFunction(..., function() {<br> var self = this; // Let the nested function access this<br> });<br> },<br> otherMethod: function (arg) { ... }<br>}<br>
</div>
<br>After currying, you can write like this:<br><div class="codetitle"> <span><a style="CURSOR: pointer" data="22807" class="copybut" id="copybut22807" onclick="doCopy('code22807')"><u>Copy code</u></a></span> The code is as follows:</div>
<div class="codebody" id="code22807">
<br>var obj = {<br> method: function (self, arg) { // Additional parameters `self`<br> 🎜> otherMethod: function (arg) { ... }<br>}<br><br><br>We convert the implicit parameter this into the explicit parameter self. In other words: we convert a dynamic This is converted into a static variable self. If this is always used as an explicit parameter, JavaScript will become simpler.<br>
<br>Implement curryThis():</div>
<br><p><br>Copy code</p>
<div class="codetitle">
<span><a style="CURSOR: pointer" data="75145" class="copybut" id="copybut75145" onclick="doCopy('code75145')"> The code is as follows:<u></u></a>Function.prototype. curryThis = function () {</span> var f = this;</div> return function () {<div class="codebody" id="code75145"> var a = Array.prototype.slice.call(arguments);<br> a.unshift(this);<br> return f.apply(null, a);<br> };<br>};<br><br><br>
<br><br>6. If you don’t want to extend the function prototype </div>
<p>The methods implemented above are all added to the prototype of the built-in constructor Function(). You should be able to easily rewrite them as independent functions.<strong></strong></p>
<p><br>Copy code</p>
<div class="codetitle"><span><a style="CURSOR: pointer" data="18130" class="copybut" id="copybut18130" onclick="doCopy('code18130')"> The code is as follows:<u><div class="codebody" id="code18130">
<br>function uncurryThis(f) {<br> return function () {<br> return f.call.apply(f, arguments)<br> };<br>}<br>function curryThis(f ) {<br> return function () {<br> var a = Array.prototype.slice.call(arguments);<br> a.unshift(this);<br> return f.apply(null, a); <br> };<br>}<br>
</div>
</u><p><strong>7. Use uncurryThis() safely in existing untrusted code </strong></p>
<p>Mark Miller<tt>explained uncurryThis() as an example</tt>"<a href="http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming" target="_blank">Safe metaprogramming</a>":<br><br>Translator's Note: Currying this is to convert the function The first parameter is converted into this in the method. Decurrying this is to convert this in the method into the first parameter of the function. </p></a></span></div>