[Effective JavaScript note] 45th: Use the hasOwnProperty method to avoid prototype contamination

Source: Internet
Author: User
Tags hasownproperty

The previous 43 and 44 discussed the enumeration of attributes, but none of them completely solved the problem of property lookup for Zhongyuan pollution. Take a look at some of the following dictionary operations

‘zhangsan‘ in dict;dict.zhangsan;dict.zhangsan=22;

The object operation of JS always works in an inherited way. Even an empty object literal inherits the Object.protoype attribute.

var dict={};‘zhangsan‘ in dict;//false‘lisi‘ in dict;//false‘wangwu‘ in dict;//false‘toString‘ in dict;//true‘valueOf‘ in dict;//true

You cannot avoid inheriting methods from Object.prototype objects.

Removal of prototype contamination

Object.prototype provides the hasOwnProperty method. When you test a dictionary entry, it avoids prototype contamination, which can solve the problem before. Look at a piece of code

dict.hasOwnProperty(‘zhangsan‘);//falsedict.hasOwnProperty(‘toString‘);//falsedict.hasOwnProperty(‘valueOf‘);//false

You can use the attributes of the above code to find property lookups to avoid being contaminated by the prototype.

dict.hasOwnProperty(‘zhangsan‘)?dict.hasOwnProperty(‘zhangsan‘):undefined;dict.hasOwnProperty(‘x‘)?dict.hasOwnProperty(‘x‘):undefined;

Here is another problem, we are using the Dict object hasOwnProperty method, but in fact, it does not have this method, but it inherits from the Object.prototype object. If the Dict Dictionary object has a property of the same name as "hasOwnProperty", then the hasOwnProperty method in the prototype is not accessed. This will take precedence over the properties it contains, and it will not be found in the prototype chain.

dict.hasOwnProperty=10;dict.hasOwnProperty(‘zhangsan‘);//这里会产生一个错误

Although dictionaries rarely store such property names. But small probability events also occur because you do not know whether the processed data is coming from a third party. Here's a safe way to do this without making any assumptions. There is no use of a Dictionary object to access the hasOwnProperty method, which may be rewritten.

Using Object.prototpye.hasOwnProperty

The hasOwnProperty method in Object.prototype is used directly, and then the function's call method is used to bind the receiver of the function to the Dictionary object.
First, we first extract the hasOwnProperty method

var hasOwn=Object.prototype.hasOwnProperty;

Or

var hasOwn={}.hasOwnProperty;

Then, determine the recipient of the function run, using the call method to specify

hasOwn.call(dict,‘zhangsan‘);

Here it is safe to call the Object.prototype.hasOwnProperty method to detect the property name of the Dictionary object.

var dict={};dict.zhangsan=12;hasOwn.call(dict,‘hasOwnProperty‘);//falsehasOwn.call(dict,‘zhangsan‘);//truedict.hasOwnProperty=10;hasOwn.call(dict,‘hasOwnProperty‘);//truehasOwn.call(dict,‘zhangsan‘);//true

In order to avoid the insertion of the above detection code, the pattern can be abstracted as a dict method.

Dict Primary Edition

The Dict constructor encapsulates all the technical details of writing a robust dictionary in a single data type definition. The code is good.

function Dict(elements){    this.elements=elements||{};}Dict.prototype.has=function(key){    return {}.prototype.hasOwnProperty.call(this.elements,key);};Dict.prototype.get=function(key){    return this.has(key)?this.elements[key]:undefined;};Dict.prototype.set=function(key,val){    this.elements[key]=val;};Dict.prototype.remove=function(key){    delete this.elements[key];};

This implementation is more robust than using the JS default object syntax and is equally easy to use.

var dict=new Dict({    zhangsan:12,    lisi:23,    wangwu:40});dict.has(‘zhangsang‘);//truedict.has(‘lisi‘);//truedict.has(‘toString‘);//false
__proto__ Self-contamination

Previously mentioned in the 44 article, in some special JS environment, special attribute name __proto__ may lead to its own pollution problem. In some environments, __proto__ simply inherits from Object.prototype, so empty objects are really empty objects.
Under some circumstances

var empty=Object.create(null);‘__proto__‘ in empty;//falsevar hasOwn={}.hasOwnProperty;hasOwn.call(empty,‘__proto__‘);//false

In other environments

var empty=Object.create(null);‘__proto__‘ in empty;//truevar hasOwn={}.hasOwnProperty;hasOwn.call(empty,‘__proto__‘);//false

Under certain circumstances
Because there is an instance attribute __proto__ and permanently polluting all objects

var empty=Object.create(null);‘__proto__‘ in empty;//truevar hasOwn={}.hasOwnProperty;hasOwn.call(empty,‘__proto__‘);//true

In different environments, the value of __proto__ cannot be determined

var dict=new Dict();dict.has(‘__proto__‘);//无法确定

To achieve the portability and security of the code, you can only add some action to the __PROTO__ keyword.

Dict final version

Here's a more secure, more complex final implementation of Dict.

function Dict(elements){    this.elements=elements||{};    this.hasSpecialProto=false;    this.specialProto=undefined;}Dict.prototype.has=function(key){    if(key === ‘__proto__‘){        return this.hasSpecialProto;    }    return {}.prototype.hasOwnProperty.call(this.elements,key);};Dict.prototype.get=function(key){    if(key === ‘__proto__‘){       return this.specialProto;    }    return this.has(key)?this.elements[key]:undefined;};Dict.prototype.set=function(key,val){    if(key === ‘__proto__‘){        this.hasSpecialProto=true;        this.specialProto=val;    }else{        this.elements[key]=val;    }};Dict.prototype.remove=function(key){    if(key === ‘__proto__‘){        this.hasSpecialProto=false;        this.specialProto=undefined;    }else{        delete this.elements[key];    }    };

The above code works regardless of the environment where the __proto__ attribute is not handled.

var dict=new Dict();dict.has(‘__proto__‘);//false
Tips
    • Use the hasOwnProperty method to avoid prototype contamination

    • Using lexical scopes and call methods to avoid overwriting hasownproperty methods

    • Consider implementing a dictionary operation in a class that encapsulates hasOwnProperty test boilerplate code

    • Use the dictionary class to avoid using ' __proto__' as key

[Effective JavaScript note] 45th: Use the hasOwnProperty method to avoid prototype contamination

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.