Home  >  Article  >  Web Front-end  >  JavaScript anti-colliization this [Translation]_javascript skills

JavaScript anti-colliization this [Translation]_javascript skills

WBOY
WBOYOriginal
2016-05-16 17:49:531037browse

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:

Copy code The code is as follows:

// Actual Simplified version of implementation:
Array.prototype.forEach = function (callback) {
for(var i=0; iif (i in this) {
callback(this[i], i);
}
}
};

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:

Copy code The code is as follows:

function printArgs() {
Array.prototype. forEach.call(arguments, function (elem, index) {
     console.log(index ". " elem);
  });
}

forEach.call( ) has one more parameter than the forEach() method: its first parameter is the specified this value:
Copy code The code is as follows :

> printArgs("a", "b")
0. a
1. b

There are several similar ones in JavaScript Common methods can be called in this way, and most of these methods come from Array.prototype.

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:

Copy the code The code is as follows:

> var toUpperCase = String.prototype.toUpperCase.uncurryThis();
> [ "foo", "bar", "baz" ].map(toUpperCase)
[ 'FOO', 'BAR', 'BAZ' ]

Use case 2: Convert a general method into a function. Use decurrying this to convert a method into a function with simpler usage. For example:
Copy code The code is as follows:

Array.forEach = Array.prototype.forEach.uncurryThis();
function printArgs( ) {
Array.forEach(arguments, function (elem, index) {
console.log(index ". " elem);
});
}

There are already many similar array methods in future versions of the ECMAScript specification recommendations.
Translator’s Note: Firefox has already implemented 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>
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn