最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to intercept and modify a specific property for any Object - Stack Overflow

programmeradmin0浏览0评论

For any unknown number of objects, there are certain properties I want to intercept and change if needed. I have tried getters and setters, but I was only able to achieve close to what I wanted and only for known objects.

The following are examples of what I am trying to achieve:

Objects being created outside of my scope/closure

As you can see these are objects that cannot be accessed from outside and what I want to do is check every year_of_birth property and modify it whenever it is created or altered for any unknown object. The closest I got was through getters/setters, but I had to pass the object and it would loop itself every time it change its value.

An example that tries to correct the year_of_birth by checking the age with the current year

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;
        }
    }
});

but still did not work well and only worked with singular objects that I had direct access.

Is there any way to do this? Please no solutions with libraries/frameworks like jQuery.

EDIT: Snippet example because the above was not clear enough:

// 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

For any unknown number of objects, there are certain properties I want to intercept and change if needed. I have tried getters and setters, but I was only able to achieve close to what I wanted and only for known objects.

The following are examples of what I am trying to achieve:

Objects being created outside of my scope/closure

As you can see these are objects that cannot be accessed from outside and what I want to do is check every year_of_birth property and modify it whenever it is created or altered for any unknown object. The closest I got was through getters/setters, but I had to pass the object and it would loop itself every time it change its value.

An example that tries to correct the year_of_birth by checking the age with the current year

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;
        }
    }
});

but still did not work well and only worked with singular objects that I had direct access.

Is there any way to do this? Please no solutions with libraries/frameworks like jQuery.

EDIT: Snippet example because the above was not clear enough:

// 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

Share Improve this question edited Mar 5, 2017 at 18:35 Shadow asked Mar 5, 2017 at 17:38 ShadowShadow 4,7926 gold badges59 silver badges79 bronze badges 20
  • Do you have a handle for your object? Do you control who gets a reference to it in your code? – Madara's Ghost Commented Mar 5, 2017 at 17:44
  • @MadaraUchiha as I explained, I intend to do this for any number of objects that I have no direct access to. The example I provided shows how these objects might be generated, inside a self-closed anonymous function of which I have no way to manipulate its contents or expose them to the outside scope. – Shadow Commented Mar 5, 2017 at 17:46
  • What you want is not possible. – Felix Kling Commented Mar 5, 2017 at 17:58
  • This is not possible. If some library creates a private object, it should be very undesirable that the object gets a different behaviour or data because of something you have done. – trincot Commented Mar 5, 2017 at 18:00
  • "Objects being created outside of my scope/closure" How do you bee aware the objects are being created at all or access the objects? – guest271314 Commented Mar 5, 2017 at 18:01
 |  Show 15 more ments

3 Answers 3

Reset to default 9

After being told multiple times that what I was asking was not possible, I discovered a way to achieve this by targeting the Object.prototype.

The solution is as follows, with "my_property" being any object property name I wish to target.

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: 

You can use RegExp to parse original <script> .textContent to get variable identifiers and objects assigned to variable identifiers. Manipulate objects to meet requirement, assign identifier to global or other object. Remove original <script> from document

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>

At the end of the day, it boils down to the question of whether you have a handle for your object or not. If you do, great, you can alter its .prototype and __proto__, you can use Object.defineProperty to define getters and setters with your own logic.

If you have control over how the 3rd party object gets distributed throughout your code, you can even use a Proxy and replace the reference.

If you don't have a reference to your object, and it just kind of floats around in the back in closed scopes, you can do nothing.


It's worth noting that in these cases, using the Facade design pattern can be considered preferable, then you can have all the customization you want, with your own API to boot.

发布评论

评论列表(0)

  1. 暂无评论