Prototype Pollution and Monkey-Patching, monkeypatching

Source: Internet
Author: User

Prototype Pollution and Monkey-Patching, monkeypatching

The previous two articles introduce prototype objects and prototype links:

JavaScript Object Creation Mode: http://blog.csdn.net/hongse_zxl/article/details/44595809

A deep understanding of the prototype object of JavaScript: http://blog.csdn.net/hongse_zxl/article/details/44622997

The prototype object is the soul of JavaScript simulation class and inheritance. This article introduces two typical problems: Prototype contamination and monkey patching.

Prototype Pollution

Let's take a look at an example:

Function Person () {}// first define an empty function (the empty function also has a prototype object) // declare two methods in the prototype object, one count and one otherFuncPerson. prototype. count = function () {// count the number of attributes in the prototype object and the method var I = 0; for (var prop in this) {I ++ ;} return I ;}; Person. prototype. otherFunc = function () {}; // define an empty method, named otherFuncvar p = new Person (); p. name = "Jack"; // Add two attributes for the object: name and agep. age = 32; alert (p. count (); // 4

With the foundation of the first two articles, we should be able to understand why the final result is 4 instead of 2. Object p has two attributes: name and age, while Person is an empty function. Expected result 2 is returned. But the actual result returned is 4. During enumeration, the object attributes (name, age) and the methods (count, otherFunc) in the prototype object are included. This is prototype pollution.

Prototype contamination refers to some properties and methods that are not expected in the prototype object when enumeration entries are involved.

The above example only introduces the concept of prototype pollution and does not have much practical significance. A more practical example:

Var book = new Array (); book. name = "Love in the Time of Cholera"; // book in the whole life after reading "Love in the Age of Cholera. author = "Garcia Marquez"; // Garcia Marquez. In addition, we recommend "Hundred Years of loneliness", always makong multi book. date = "1985"; alert (book. name); // Love in the Time of Cholera

Defines an Array object for managing books. The results are correct. It seems that there is no problem, but the code is very fragile. If you are not careful, you will encounter the prototype pollution problem: 

// Add two methods for Array: first and last (monkey patch will be introduced later) Array. prototype. first = function () {// obtain the first return this [0] ;}; Array. prototype. last = function () {// get the last return this [this. length-1] ;}; var bookAttributes = []; // an array for defining the attributes of a book (var v in book) {// obtain the attributes of the previously created Array object book one by one and add bookAttributes to the Array. push (v);} alert (bookAttributes); // name, author, date, first, last
We have defined a book object with three attributes: name, author, and date publication date. After adding the three attributes to the bookAttributes Array through enumeration, it is found that not only these three attributes, but the methods in the Array's prototype object are also added to the Array, this is not what we want to see

You can use the hasOwnProperty method to test whether a property comes from an object rather than a prototype object:

Var bookAttributes = []; for (var v in book) {if (dict. hasOwnProperty (v) {// test bookAttributes for adding hasOwnProperty to each attribute. push (v); // only attributes of the object are added to the array} alert (bookAttributes); // name, author, date
Of course, the better way is to simply use the direct instance of the Object as the dictionary, instead of the Array or subclass of the Object (for example, the above Person, the function itself is also an Object ):

Var book ={}; // equivalent to var book = new Object (), not new Array () book. name = "Love in the Time of Cholera"; book. author = "Garcia Marquez"; book. date = "1985"; var bookAttributes = []; for (var v in book) {bookAttributes. push (v);} alert (bookAttributes); // name, author, date this avoids prototype pollution

Of course, you may wonder: You can still add attributes to Object. prototype like adding monkey patches to Array. prototype. Will this still cause prototype pollution? This is true, but the Object is the root Object of JavaScript. Even if it can be implemented technically, you should never make any modifications to the Object.

If you are working on a business project, the above is enough to prevent prototype pollution. However, if you want to develop a common library, you need to consider some additional issues.

For example, if your Library provides the has method to determine whether the object has this attribute (not from the properties of the prototype object), you may do this:

function Book(elements) {    this.elements = elements || {};}Book.prototype.has = function(key) {    return this.elements.hasOwnProperty(key);};var b = new Book({    name : "Love in the Time of Cholera",    author : "García Márquez",    date : "1985"});alert(b.has("author"));  //truealert(b.has("has"));     //false
You have added the has Method to the prototype object of the Book to determine whether the passed property is an object's own property. If yes, true is returned. If not (such as the property from the prototype object) returns false. The result indicates that author comes from the object, so true is returned, and has comes from the prototype object, so false is returned.

Everything is perfect, but in case someone has a custom hasOwnProperty property with the same name in the Object, this will overwrite the Object. hasOwnProperty provided by ES5. Of course, you will think that no one will name an attribute hasOwnProperty. But as a general interface, you 'd better not make any assumptions. You can use the call Method to Improve It:

Book.prototype.has = function(key) {    return {}.hasOwnProperty.call(this.elements, key);};
The running result is the same as before the improvement, but now, even if someone defines the hasOwnProperty attribute with the same name in the Object, the has method still correctly calls the Object. hasOwnProperty method provided by ES5.

Monkey patch Monkey-Patching

The attraction of monkey patch is convenience. Is an array missing a useful method? Add one:

Array.prototype.split = function(i) {     return [this.slice(0, i), this.slice(i)];};
The environment is too old. New Methods of Array in ES5, such as forEach, map, and filter? Add:

If (typeof Array. prototype. map! = "Function") {// ensure that the Array is not overwritten if it exists. prototype. map = function (f, thisArg) {var result = []; for (var I = 0, n = this. length; I <n; I ++) {result [I] = f. call (thisArg, this [I], I) ;}return result ;};}
However, when multiple libraries patch the same prototype with a monkey, the problem may occur. For example, another library in the project also has an Array split method, but it is different from the above implementation:

Array.prototype.split = function() {    var i = Math.floor(this.length / 2);    return [this.slice(0, i), this.slice(i)];};
Now there is a 50% error in calling the split method on the Array, depending on which database version is first loaded (assuming there is no dependency between them.
The solution is to encapsulate the desired version:
function addArrayMethods() {    Array.prototype.split = function(i) {        return [this.slice(0, i), this.slice(i)];    };};
When you need to call the split method, you can call the encapsulated function to avoid errors.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.