m_spz Posted January 12, 2019 Share Posted January 12, 2019 Hello, im trying to call an function when i press a button in html and it throw me this error: Uncaught TypeError: Cannot read property 'sprite' of undefined at showMessage (init.js:105) at xd(init.js:121) at HTMLDivElement.onclick ((index):1) The function is this: function xd(){ console.log("clicked0"); showMessage(); console.log("clicked1"); } function showMessage(){ this.add.sprite(725, 275, 'message'); } Link to comment Share on other sites More sharing options...
mattstyles Posted January 14, 2019 Share Posted January 14, 2019 Hey there @m_spz, welcome to the forums! You're having an issue with scoping in JS, and the use of context. It can be a little tricky, and is sometimes unexpected if you come from other languages (particularly classical languages). `this` is a context in which functions execute. In your case `this` is applied by `addEventListener` by default to the HTML element to which it is attached, i.e. var el = document.querySelector('#myElement') el.addEventListener('click', function () { console.log(this) }) // <div id='myElement'>...</div> HTML elements do have quite a few methods (functions) and members (data) attached to them. You are trying to access a function (`sprite`) on an object (`add`). As `this` is not what you're expecting (unless you've done something not shown it'll be the HTML element) the object `add` does not exist (it is undefined), and the error is telling you that the JS engine is trying to access a function (`sprite`) on the undefined object, which throws an error. There is some info here and here from MDN on JS scoping, there are a couple of reasons these don't mention the `this` keyword. You can explicitly set a context for a function, see the docs for `.bind`. There are sister functions `.call` and `.apply`, but `.bind` is probably going to make your program operate how your mental model expects. There are pros and cons to this. Something common is to do something like the following (note that I'm not suggesting this is a good or bad pattern, only that it is common): var el = document.querySelector('#myButton') var entity = { name: 'Dave', say: function () { console.log(this.name) } } el.addEventListener('click', entity.say.bind(entity)) This binds the function `say` with the object `entity`. If you come from a classical language this might exhibit the behaviour you are expecting. By binding the `entity` object `this` becomes the `entity` object and we can access `this.name` and get the value we expect. If you omit the `.bind` you won't get 'Dave' back for name. Note that `.bind`ing creates a new function, this isn't specifically attached to the `entity` object, it is contextually bound. Depending on what you are doing this may not matter too much but when you start having vast arrays of objects it can become important because you are creating lots of new functions rather than passing around a pointer to a single function. Link to comment Share on other sites More sharing options...
Recommended Posts