• 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__)
    //"值"
  • 相关阅读:
    体检套餐管理系统
    在这个与金沂同桌的日子里,我在北大青鸟学习了 第四章 深入类的方法 下面是我的上机3
    总结
    今天晚上雨夹雪,爱人狠心把我撇。今夜孤独一个人,只好来把代码写。 欢迎阅读我的第四章笔记 深入类的方法
    我在北京写代码 写出心中悲与喜 写出人间的悲欢离合 欢迎阅读 我的第三章 使用集合组织相关数据(泛型集合)
    在那个春暖花开的季节 今天微微的小雨 伴着轻轻的晚风我们一起来编写 员工考勤信息管理
    非泛型集合
    经理评分系统
    模仿魔兽登录界面 编程小练习
    【BZOJ 3524】【Poi2014】Couriers 可持久化线段树
  • 原文地址:https://www.cnblogs.com/ziyunfei/p/2733748.html
Copyright © 2020-2023  润新知