Changing javascript 'this' value but can't understand why

I am full javascript newb and I am trying to wrap my head around OLN. I am faced with the fact that when calling a method of an object from another method on the same object, the value of the local value 'this' in the called method changes. Here is my code:

var generator = {
    generateForLevelSkillAndCount : function(level, skill, count) {
        var functionCall = this['generate_' + level + '_' + skill];
        return functionCall(count);
    },
    generate_0_4 : function(count) {
        return this.generate_generic_dots(count, 3);
    },
    generate_generic_dots : function(count, maxDots) {
        /* do cool stuff and return it */
    }
};

So, I call generator.generateForLevelSkillAndCount(0, 4, 20), and it works correctly, calling generate_0_4(count). However, this is where it fails, with the Chrome Javascript console telling me "Uncaught TypeError: Object [object DOMWindow] does not have a generate_generic_dots method."

, , , this generate_0_4 DOMWindow, ( , this generateForSkillLevelAndCount, , .

: CMS, eval, , eval.

+3
6

JavaScript (this) " " (window, ), . :

var foo = { bar: function() { alert(this.baz); }, baz: 5 };
var bar = foo.bar;
var baz = 3;

foo.bar();    // alerts 5, from foo
foo["bar"](); // alerts 5, from foo
bar();        // alerts 3, from the global object

, !

, functionCall , window . : .call() .apply():

function generateForLevelSkillAndCount1(level, skill, count) {
    return this['generate_' + level + '_' + skill](count);
}

function generateForLevelSkillAndCount2(level, skill, count) {
    var functionCall = this['generate_' + level + '_' + skill];
    return functionCall.call(this, count);
}
+8

, eval, , , :

//...
generateForLevelSkillAndCount : function(level, skill, count) {
    var functionCall = this['generate_' + level + '_' + skill];
    return functionCall(count);
},
//...

eval . .

, , Chrome, eval , , eval FunctionExpression (, generateForLevelSkillAndCount), .

. .

: - , functionCall, :

, :

//...
generateForLevelSkillAndCount : function(level, skill, count) {
    this['generate_' + level + '_' + skill](count);
},
//...

- , this:

//...
generateForLevelSkillAndCount : function(level, skill, count) {
    var functionCall = this['generate_' + level + '_' + skill];
    return functionCall.call(this, count);
},
//...

this...

+3

call():

var generator = {
  generateForLevelSkillAndCount : function(level, skill, count) {
    return this['generate_' + level + '_' + skill].call(this, count);
  },
  generate_0_4 : function(count) {
    return this.generate_generic_dots.call(this, count, 3);
  },
  generate_generic_dots : function(count, maxDots) {
    /* do cool stuff and return it */
  }
};
+1

, , , , generate_0_4, eval()?

0

generate_0_4 ( to_string()), generateForLevelSkillAndCount . Window, Object, this, , this .

, , :

generate_0_4 : function(count) {
    throw(this);
    return this.generate_generic_dots(count, 3);
},

generator.generateForLevelSkillAndCount(0, 4, 1); [object Window] [object DOMWindow].

generator.generate_0_4(1); , ( ): [object Object] #<an Object>.

0

This is a feature of Javascript: the value thiswill depend on the object from which the function was called, and not where it was defined. (Which makes sense when functions are first-class objects themselves.) thisIn most other contexts, refers to the window object.

There are two general workarounds:

function bind(func, obj) {
    return function() {
        func.apply(obj, arguments);
    }
}

or using closure:

var self = this;
function generate_blah() {
    // use self instead of this here
}

In your case, however, simply replacing

var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);

with

this['generate_' + level + '_' + skill](count);

would do the trick.

0
source

Source: https://habr.com/ru/post/1761457/


All Articles