Skip to content

一、如何在不改变下面代码的情况下,修改obj对象

js
   var o = (function () {
      var obj = {
        a: 1,
        b: 2,
      };
      return {
        get: function (k) {
            return obj[k];
        }
      }    
   })();

题解:

  • 以上程序的目的,主要是屏蔽obj,不可让外面直接访问它,只能读取它的某个属性,这样保护了这个对象的完整。相当于一个第三方库, 提供的获取的api,屏蔽了它内部的一些东西,不被外界直接访问。
  • 以上的代码,能不能就使用它提供的api达到破坏它的目的呢? 其实是可以做到的。
  • 以上的代码,提供的api实际上有点权限过大了,可以通过api访问到这obj的任何成员,除了他自身的成员之外,还可以访问原型上的成员,obj的原型不就是 Object.prototype,同时根据对象上的valueOf返回自身的特性,obj.valueOf返回的就是obj这个对象本身,那是不是可以使用o.get('valueOf')() 调用这个函数,会发现报错Cannot convert undefined or null to object,这就涉及到this的指向问题了,o.get('valueOf')()调用,this的 指向全局,也就是在严格模式下会指向undefined。根源在于get函数里面直接返回的是某个成员,如果这边直接是函数调用的话,return obj[k](),那就没问题了。
  • js里有没有一种可能,当读取某个对象属性的时候,就直接是一个函数调用。有可能,当这个属性是一个访问器的时候。
    js
       Object.defineProperty(Object.prototype, 'abc', {
          get() {
              return this;
          }
      })
  • 通过这个漏洞,我们就可以拿到这个对象
    js
      var obj2 = o.get('abc');
      obj2.c = 2;
      console.log(o.get('c'))
  • 保护措施
    • 方案一:获取的时候判断是否是对象本身的属性
      js
       var o = (function () {
        var obj = {
          a: 1,
          b: 2,
        };
        return {
          get: function (k) {
              if (obj.hasOwnProperty(k)) {
                  return obj[k];
              }   
              return undefined;
          }
        }    
       })();
    • 方案二:没有使用到原型,直接将原型设置为空
      js
       var o = (function () {
        var obj = {
          a: 1,
          b: 2,
        };
        Object.setPrototypeOf(obj, null);
        return {
          get: function (k) {
              return obj[k];
          }
        }    
       })();

Released under the MIT License.