1

I want to invoke a function using apply(), but when I pass a var with bracket notation, it does not work any more. Why this does not work? thanks

window.video['play'] = OK window.video.play = OK obj[p[i]] = not OK <= something like this I'd like to use

var obj = window;
var prop = 'video.play';

var p = prop.split('.');
for (var i = 0; i < p.length; i++) {
    obj = obj[p[i]];
}

var orig = obj; // problem here with obj: window.video['play'] = OK, but obj[p[i]] = not OK
obj = function() {
    var ar = Array.prototype.slice.call(arguments);
    console.log(ar); // not work!
    orig.apply(this, ar);
};

almost the same, but this works:

var orig = window.video.play;
window.video.play = function() {
    var ar = Array.prototype.slice.call(arguments);
    console.log(ar); // work!
    orig.apply(this, ar);
};
mkj
  • 2,761
  • 5
  • 24
  • 28
dmj16
  • 21
  • 3

1 Answers1

2

tld;dr: If you want to change the value of video.play, then you have to explicitly assign to it. Only because obj has the same value as video.play doesn't mean that assigning to obj will change the value of video.play.


obj is a variable. Assigning a new value to a variable does not magically assign the new value to another variable or property. Lets get some ASCII art.

Lets start with

var foo = {
  fn: function() {
    console.log(foo);
  },
};

This creates the following object structure in memory:

                         +--------------+                     
+----+-----------+       |  Object#123  |                     
|foo |  ref:123 *+------>+------+-------+     +--------------+
+----+-----------+       | fn   |   *---+---->| Function#456 |
                         +------+-------+     +--------------+

If we assign the function to another variable, e.g.

var bar = foo.fn;

then bar directly points to the function object.

                        +--------------+                      
                        |  Object#123  |                      
                    +--->------+-------+      +--------------+
                    |   | fn   |    *--+----->| Function#456 |
+----+-----------+  |   +------+-------+      +--------------+
|foo |  ref:123 *+--+                                 ^       
+----+-----------+                                    |       
|bar |  ref:456 *+------------------------------------+       
+----+-----------+                                            

Now, assigning a new value bar will do just that: It will make bar point to another value, but it won't have any impact on foo or foo.fn:

bar = function() {
  console.log('bar');
};

As you can see, foo.fn still points to the original function:

                         +--------------+                     
                         |  Object#123  |                     
                    +--->+------+-------+     +--------------+
                    |    | fn   |   *---+---->| Function#456 |
+----+-----------+  |    +------+-------+     +--------------+
|foo |  ref:123 *+--+                                         
+----+-----------+       +--------------+                     
|bar |  ref:789 *+------>| Function#789 |                     
+----+-----------+       +--------------+                 
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Very good explanation of the problem. If I may add a simple solution to this for this particular question, you can correctly overwrite the `video.play` function by continuously storing the last parent object in the hierarchy using `parent = obj;` in the loop that gets the function reference, then overwrite it using `parent[p[p.length - 1]] = ...`. Though it really feels like there are some odd design choices that took us to this place. – Vala Sep 07 '16 at 00:28
  • I had the feeling the probem could be sth. to do with the pointer or overwriting, but was not sure untill this explaination. Thor84no, thx for your suggestion, i will try it... – dmj16 Sep 07 '16 at 00:36
  • @dmj16: It doesn't actually have anything to do with "pointers" (references is a better word). You can simplify the issue to `var foo = 42; var bar = foo;`. Assigning a new value to `bar` (`bar = 21;`) won't change the value of `foo`. The keywords to look for are *pass-by-value* (which is what JavaScript does) vs *pass-by-reference* (not to confuse with object references). See https://en.wikipedia.org/wiki/Evaluation_strategy . – Felix Kling Sep 07 '16 at 00:37