zoukankan      html  css  js  c++  java
  • JavaScript:继续理解__proto__

    __proto__属性未来会成为ES6标准的一部分,目前,该属性在各个浏览器下的实现差别也许比较大.本文我们只讨论它在Firefox最新版本中的表现,因为Firefox是最先实现的这个魔法属性(magic property)的浏览器(同类的属性还有__parent__和__count__等,但这两个已经被废弃了.),而且该属性在Firefox中的表现也最有望能成为标准.

    首先要说的是,我们通常用的__proto__属性都是从Object.prototype上继承下来的,该属性是个访问器属性:

    >uneval(Object.getOwnPropertyDescriptor(Object.prototype,"__proto__"))
    
    "({
        configurable: true,
        enumerable: false,
        get: function () {
            [native code]
        },
        set: function () {
            [native code]
        }
    })"

    可以看到,该属性是可以配置的.那就意味着我们可以删除它.

    console.log((function(){}).__proto__ === Function.prototype)  //true,__proto__可以读取到一个对象的原型
    
    delete Object.prototype.__proto__          //true,可以删除__proto__属性
    
    console.log((function(){}).__proto__)      //undefined,__proto__不复存在,但仍然可以使用Object.getPrototypeOf方法获取到一个对象的原型

    我们还可以修改该属性的表现,比如禁止它的写操作.

    console.log(Object.getPrototypeOf({__proto__:null}))      //null,可以使用__proto__指定某个新建对象的原型,相当于Object.create(null)
    
    window.__proto__ = null //重写已有对象的属性,这个功能无法用其他方法替代.因为我们没有Object.setPrototypeOf方法
    Object.defineProperty(Object.prototype,"__proto__",{set:function(){}}); //将__proto__属性的set访问器设置为一个空函数
    console.log(Object.getPrototypeOf({__proto__:null})) //返回Object.prototype,不能再使用__proto__来指定原型
    console.log({__proto__:null}.__proto__) //返回Object.prototype,还可以使用__proto__来读取原型

    我们甚至可利用__proto__的属性描述符复制一个一模一样功能的属性.

    Object.defineProperty(Object.prototype, "原型", Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"));   //复制一个属性"原型"
    
    delete Object.prototype.__proto__ //删除__proto__属性
    console.log(Object.原型) //返回Function.prototype

    其实最有用的方法就是__proto__属性描述符上的set(),假如我们想在禁用__proto__属性的前提下实现一个自定义的Object.setPrototypeOf方法,可以这样来做:

    (function () {
    var set = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set;
    delete Object.prototype.__proto__;
    Object.setPrototypeOf
    = function setPrototypeOf(object, prototype) {
    set.call(object, prototype)
    }
    })();

    var obj = {__proto__:"我是一个普通的属性"}; //__proto__和__xxoo__一样了,是个普通的属性,不会再有可能出现的冲突
    console.log(obj.__proto__); //"我是一个普通的属性"
    Object.setPrototypeOf(window,{}); //设置window对象的原型
    console.log(typeof alert) //undefined,window上什么都没了

     在不删除__proto__的前提下,我们难道就不能拥有"__proto__"这个普通的自定义属性了吗?可以的:

    var map = {};                            //一个普通对象
    
    map["__proto__"] = "值"; //添加键"__proto__"
    console.log(map.__proto__) //返回Object.prototype,上面的代码没有作用,获取到的是对象的原型
    Object.defineProperty(map,"__proto__",{value:"值"}) //定义一个自身属性"__proto__",则不会再继承原型链上的同名属性.

    console.log(map.__proto__)
    //"值"
  • 相关阅读:
    使用Subversion进行版本控制 针对 Subversion 1.4(根据r2866编译)-------<转载>这是重要的知识点
    UIImageView上添加Button不能响应点击事件[转]
    Unity3D基础学习篇Unity基本原理
    ObjectiveC基础知识-查漏补缺
    C# 参考之方法参数关键字:params、ref及out
    SQL SERVER 2000 创建挂起的文件操作 解决方法
    JavaScript trim函数大赏
    javascript的date对象的方法
    firefox getRangeAt
    ckeditor+ckfinder
  • 原文地址:https://www.cnblogs.com/ziyunfei/p/2733748.html
Copyright © 2011-2022 走看看