【问题标题】:How to intercept and modify a specific property for any Object如何拦截和修改任何对象的特定属性
【发布时间】:2017-03-05 17:38:04
【问题描述】:

对于任何未知数量的对象,如果需要,我想截取和更改某些属性。我尝试过 getter 和 setter,但我只能实现接近我想要的并且仅适用于已知对象。

以下是我想要达到的目标的示例:

在我的范围/闭包之外创建的对象

如您所见,这些是无法从外部访问的对象,我想做的是检查每个year_of_birth 属性,并在为任何未知对象创建或更改它时对其进行修改。我得到的最接近的是通过 getter/setter,但我必须传递对象,并且每次更改其值时它都会自行循环。

通过检查当前年份的年龄来尝试更正 year_of_birth 的示例

Object.defineProperty(unknown_object, 'year_of_birth', {
    set: function(year) {
        if (this.age && 2017 - this.age > year) {
            this.year_of_birth = 2017 - this.age;
        }
    }
});

或

Object.defineProperty(unknown_object, 'year_of_birth', {
    get: function(year) {
        if (this.age && 2017 - this.age > year) {
            return 2017 - this.age;
        }
    }
});

但仍然不能很好地工作,只能处理我可以直接访问的单个对象。

有没有办法做到这一点?请不要使用像 jQuery 这样的库/框架的解决方案。

编辑:片段示例,因为上面不够清楚:

// Here I define some sort of solution to manipulate any object property of name "year_of_birth"

// unknown_object or a sort of prototype/constructor that intercepts any object, regardless of its scope

Object.defineProperty(unknown_object, 'year_of_birth', {
    set: function(year) {
        if (this.age && 2017 - this.age > year) {
            this.year_of_birth = 2017 - this.age;
        }
    }
});

// or

Object.defineProperty(unknown_object, 'year_of_birth', {
    get: function(year) {
        if (this.age && 2017 - this.age > year) {
            return 2017 - this.age;
        }
    }
});


// I want to modify "year_of_birth" or any other object property that is inside the below scope
// I do not have access to that scope, I cannot modify the function to allow access to its scope, I cannot do anything to it besides trying to modify the objects from the outside through some method that I am trying to find out in this question

(function() {
    var john = {
        age: 28,
        year_of_birth: 1985
    };
    var anne = {
        age: 31,
        year_of_birth: 1985
    };
}());

// Whenever a "year_of_birth" object property is read/set it should change to whichever value it has been established in the setters/getters at the top

【问题讨论】:

  • 你的对象有句柄吗?你控制谁在你的代码中引用它?
  • @MadaraUchiha 正如我所解释的,我打算对我无法直接访问的任意数量的对象执行此操作。我提供的示例显示了这些对象是如何在一个自封闭匿名函数中生成的,我无法操作它的内容或将它们暴露给外部范围。
  • 你想要的都是不可能的。
  • 这是不可能的。如果某个库创建了私有对象,则应该非常不希望该对象因为您所做的某事而获得不同的行为或数据。
  • “在我的范围/闭包之外创建的对象”您如何完全意识到正在创建对象或访问这些对象?

标签: javascript object


【解决方案1】:

在多次被告知我的要求是不可能的后,我发现了一种通过定位 Object.prototype 来实现这一目标的方法。

解决方案如下,“my_property”是我希望定位的任何对象属性名称。

Object.defineProperty(Object.prototype, "my_property", {
    set: function (value) {
        this._value = value;
    },
    get: function () {
        return "changed";
    }
});

var some_object = {};

some_object.my_property = "unchanged";


document.body.innerHTML += some_object.my_property;
My property value is: 

【讨论】:

    【解决方案2】:

    您可以使用RegExp 解析原始<script> .textContent 以获取变量标识符和分配给变量标识符的对象。操作对象以满足要求,将标识符分配给全局或其他对象。从document中删除原来的<script>

    let scripts = document.scripts;
    
    let iife = scripts.namedItem("iife");
    
    let iifeText = iife.textContent;
    
    let objs = iifeText.replace(/\(function\(\) \{|\}\(\)\)/g, "")
      .replace(/(var|let|const)|[a-z_]+?\s=(?=\s\{|\{)|\s+/ig, "")
      .replace(/(\w+)(?=:)/g, "\"$1\"")
      .match(/[^;]+/g);
    
    let props = iifeText
      .match(/(var|let|const)\s[a-z_]+?\s=?\s(?=\{)/ig)
      .map(function(id) {
        return id.replace(/var|let|const|\s+|=/g, "");
      });
    
    let setProp = (obj, value) => {
      // perform logic here
      if (obj.age && 2017 - obj.age > value) {
        obj.year_of_birth = 2017 - obj.age;
      }
      return obj
    }
    
    let getProp = (obj, value) => {
      if (obj.age && 2017 - obj.age > value) {
        return 2017 - obj.age;
      }
      return obj
    }
    
    for (let [key, prop] of props.entries()) {
      this[prop] = setProp(JSON.parse(objs[key]), 27);
    }
    
    // remove original `script`
    iife.remove();
    
    console.log(props, objs);
    
    for (let prop of props) {
      // changed properties of objects
      console.log(this[prop]);
    }
    <script name="iife">
      (function() {
        var john = {
          age: 28,
          year_of_birth: 1985
        };
        var anne = {
          age: 31,
          year_of_birth: 1985
        };
      }());
    </script>

    【讨论】:

    • @Shadow 解析完对象后,您可以在链接答案中使用Proxy 方法进行观察,拦截对象上的get、set。
    【解决方案3】:

    归根结底,问题归结为您是否有对象的句柄。如果你这样做了,太好了,你可以改变它的.prototype 和__proto__,你可以使用Object.defineProperty 用你自己的逻辑定义getter 和setter。

    如果您可以控制第 3 方对象在整个代码中的分布方式,您甚至可以使用 Proxy 并替换引用。

    如果您没有对您的对象的引用,并且它只是在封闭范围内漂浮在后面,您将无能为力。


    值得注意的是,在这些情况下,可以考虑使用Facade design pattern,然后您可以进行所有您想要的自定义,并使用您自己的 API 来启动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2021-05-31
      • 2021-02-06
      • 2018-06-07
      • 1970-01-01
      • 2021-05-15
      相关资源
      最近更新 更多