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__)
    //"值"
  • 相关阅读:
    css3 preserve-3d 的理解 注意IOS上的兼容
    javascript JSMpeg.js 播放视频解决不用全屏也能播放(也支持自动播放哦)
    linux写系统服务的方法
    mysql connect refuse解决方法
    SQLite-CONSTRAINTS(约束)
    Java集合
    自定义一个简单的SegmentedControl
    symbolicatecrash解析crash文件
    django应用的测试
    WordPress调用page页面内容方法
  • 原文地址:https://www.cnblogs.com/ziyunfei/p/2733748.html
Copyright © 2011-2022 走看看