JS bound function accesses window anyways [duplicate] - javascript

I am trying to access this inside my arrow function:
import myObject from '../myObjectPath';
export const myClass = Fluxxor.createStore({
initialize() {
this.list = [];
this.id = null;
},
myOutsideFunction(variable1) {
// here this in NOT undefined
myObject.getMyList(this.id, (myList) => {
// here this in undefined
this.list = myList;
}
});
)};
But inside arrow function which in ma callback function this is undefined!!
I am using babel to transpile the code:
myOutsideFunction: function myOutsideFunction() {
var _this = this;
myObject.getMyList(function (myList) {
_this.list = myList;
});
},

If this is undefined within an arrow function, it's undefined outside of the arrow as well. Arrow function simply capture the this of the surrounding scope.
In this case, you're declaring myOutsideFunction as a method on an object literal and never binding it or doing anything else that would call it with the object as this.
When debugging, bear in mind that transpilers can rename variables (and have to rename this for it to capture correctly). Using the original name in the console without sourcemaps that include renaming will show you undefined even if the original value isn't. Make sure you use the transpiled name in watches or console commands.

Related

Can not bind 'this' to imported function - javascript

I am a beginner and I want to bind 'this' to helper-functions which I have imported from an other file (that I can use the variables, I created in the current lexical environment ).
But I have recognized, that I can bind these imported functions to any object - which I have created in the file, into I have imported them - but not to the current this.
node.js example:
https://github.com/sdeli/issues-with-this
// random-js-file.js
// this is the function I import in app.js
function logOutThis() {
console.log(this);
}
module.exports = logOutThis;
// --------------------------------
// app.js
const importedFn = require('./random-js-file.js');
// this is now the global of random-js-file.js
importedFn();
console.log('--------------------------------');
var monkey = {
chimp : 'chimp'
}
// this is now the object 'monkey'
var myfunction = importedFn.bind(monkey);
myfunction();
console.log('---------------------------------');
//this should be now the current this
var myfunction2 = importedFn.bind(this);
myfunction2();
// console.log displays '{}' and i can not refer to the variable in this lexical environment
So I dont understand why I can not bind 'this' into a function which I have imported but I can bind it to any object.
Thank you for your suggestions
There isn't a way to access the inner context of an imported module unless it explicitly exports the bits you want (or provides functions that expose them). Javascript this doesn't behave like Java this, and modules aren't classes.
There's some other cases, but basically, if the function you're currently is called someFunc and it was called with syntax a.someFunc(), then this will be the same as a. Here's a worked example:
const someObject = {
someFunc() {
//Here, "this" will be the same as someObject, because of the way we called it
someOtherFunction();
}
};
someObject.someFunc();
function someOtherFunc() {
//"this" is still someObject because it's inherited from the calling function which was not called using a method syntax
x.y(); //inside the y() function, "this" will now be x
}
Basically, IMHO, this is a broken mess in Javascript and is one of the key reasons I avoided using it whereever possible. That means I don't use classes, and I get everything I need from closures.

Entire JS inside one global variable?

I've got a school assignment of creating an app and one of the restrictions were that only one global variable was allowed, named "App". So I need to put the whole JS inside this variable.
I thought of doing something like:
App = function() { this.test = () => alert("test"); }
And then calling it with App.test().
But this doesn't work, the error I'm getting is:
Uncaught TypeError: App.test is not a function at HTMLLIElement.onclick (index.html:25)
Am I doing something wrong?
You need to define your app in a variable as an object and then you can use those members of the object such as:
// Object creation
window.App = {};
Then you add more properties like functions or variables and use it later inside of that variable.
window.App.test = function() {
alert('test');
}
window.App.variable = 'my variable';
console.log( App.test() );
console.log( App.variable );
Another thing is you can omit the word window from App.
Keeping most of your approach as it is, you could return an object that has functions as properties.
App = function() {
return {
test: () => alert("test"),
test2: () => alert("test2")
};
}
App().test();
App().test2();
To be able to use your function that contains this.test..., you'll need to use it as a "constructor function" because this in a function declaration means "instance property", meaning you will need to explicitly create an instance of App with the new keyword:
// Declare the global
var App = function() { this.test = () => alert("test"); }
// Make an instance of an object via the constructor function
var myApp = new App();
// Invoke the functionality via the instance
myApp.test()
Or, set up App as an object, connect that object to the Global window object and set test as a property of App all without any instance properties (this references), which avoids having to make the explicit instance:
// Declare the global property as an Object
// and set up a "test" property that stores
// a function in that object:
window.App = { test: function(){alert("test");}}
// Invoke the functionality directly
App.test()
The test function is not defined before executing the App function:
App = () => test = () => alert("test")
<button onclick='App(); test()'>:</button>
App can be defined as object instead:
App = { test: () => alert("test") }
<button onclick='App.test()'>:</button>
Just to piggyback on to what the other answers have suggested, this technique is most commonly used (in browser developement) when you "namespace" some JS code. Namespacing is useful because it helps the developer reduce global variable pollution by adding all their code under one namespace under window.
This also helps the developer modularise the code.
Here's a pattern you might see from time to time that adds code to a single namespace under window.
// This first function is what's known as an Immediately-invoked
// function expression (IIFE). `window` is passed in as an argument
// to the function - all other declared variables are local to the scope
// of the function so you don't get anything leaking to global.
// PS, the semi-colon is there before the opening parenthesis to prevent
// any errors appearing if you minimise your code
;(function (window) {
// Here we declare something new to add to the namespace
// It could be another object, a string, an array, or a constructor
// like Model
function Model() {...}
// If namespace `window.app` doesn't exist instantiate it with
// an empty object. If it _does_ exist it probably means that another
// module like this one has already been added to the namespace.
window.app = window.app || {};
// Then assign your new module as a property under that namespace
window.app.Model = Model;
})(window);
You can then use it later something like this:
var model = new app.Model();
var game = new Game(model);
For further reading: Addy Osmani on namespacing.

Javascript function assigned to object cannot access inherited method

I'm no doubt doing something dumb here, but the following code results in an
error "this.getString is not a function."
This occurs because when unrelatedInstance calls stringGetter, "this" in showCombinedStrings() has the value of Unrelated....which actually seems fair enough, but how could this be set up so that it would work?
function BaseStringGetter() {
this.getString = function () {
return 'this is from BaseStringGetter';
}
}
function DerivedStringGetter() {
this.showCombinedStrings = function () {
console.log( 'this is from DerivedStringGetter and... ' + this.getString() );
}
}
DerivedStringGetter.prototype = new BaseStringGetter();
var stringGetterInstance = new DerivedStringGetter();
function Unrelated() {};
var unrelatedInstance = new Unrelated();
unrelatedInstance.stringGetter = stringGetterInstance.showCombinedStrings;
unrelatedInstance.stringGetter();
One option is this:
unrelatedInstance.stringGetter =
stringGetterInstance.showCombinedStrings.bind(stringGetterInstance);
unrelatedInstance.stringGetter();
Here, you're using Function.prototype.bind() to make this inside of unrelatedInstance.stringGetter() always refer back to stringGetterInstance.
The problem is how you are calling unrelatedInstance.stringGetter();
Even though stringGetter refers to the showCombinedStrings function, this inside showCombinedStrings now refers to the unrelatedInstance instance which does not have the toString() property that is why the error.
Demo: Fiddle
Here the value of this is printed as Unrelated {stringGetter: function} which is not an DerivedStringGetter instance
One easy solution is to use .bind() to give a custom execution context to unrelatedInstance.stringGetter like
unrelatedInstance.stringGetter = stringGetterInstance.showCombinedStrings.bind(stringGetterInstance);
Demo: Fiddle
Now even if you call unrelatedInstance.stringGetter(), this inside showCombinedStrings will refer to the stringGetterInstance instance.
When you call a function on an object, this will refer to the object the function is invoked on even if the function was originally defined elsewhere.
When you call unrelatedInstance.stringGetter();, this inside the function will now refer to unrelatedInstance which doesn't have getString(). The MDN this reference page has more info.
You could do something like this to preserve the original context:
unrelatedInstance.stringGetter = function() {
return stringGetterInstance.showCombinedStrings();
}
Edit: I left out bind that the other answers have now mentioned since it doesn't exist in IE8 but you'd be fine using that if you have a shim or don't care about old browsers.

Javascript Prototype not Working

Hi I don't know whether this is my mistake in understanding Javascript prototype object ..
Well to be clear I'm new to the Javascript singleton concept and lack clear cut knowledge in that but going through some referral sites I made a sample code for my system but it's giving out some errors which I couldn't find why so I'm asking for your help. My code is:
referrelSystem = function(){
//Some code here
}();
Prototype function:
referrelSystem.prototype.postToFb = function(){
//Some Code here
};
I get an error saying prototype is undefined!
Excuse me i thought of this right now
EDIT
I have used like this:
referrelSystem = function(){
return{
login:getSignedIn,
initTwitter:initTw
}
};
Is this causing an issue?
A typical way to define a JavaScript class with prototypes would be:
function ReferrelSystem() {
// this is your constructor
// use this.foo = bar to assign properties
}
ReferrelSystem.prototype.postToFb = function () {
// this is a class method
};
You might have been confused with the self-executing function syntax (closures). That is used when you would like to have "private" members in your class. Anything you declare in this closure will only be visible within the closure itself:
var ReferrelSystem = (function () {
function doSomething() {
// this is a "private" function
// make sure you call it with doSomething.call(this)
// to be able to access class members
}
var cnt; // this is a "private" property
function RS() {
// this is your constructor
}
RS.prototype.postToFb = function () {
// this is a class method
};
return RS;
})();
I would recommend that you study common module patterns if you're looking into creating a library.
Update: Seeing your updated code, the return from referrelSystem won't work as expected, since return values are discarded when calling new referrelSystem().
Rather than returning an object, set those properties to this (the instance of referrelSystem that gets constructed):
var referrelSystem = function () {
// I assume you have other code here
this.login = getSignedIn;
this.initTwitter = initTw;
};
I don't think you intend to immediately execute the functions, change them to this:
var referrelSystem = function(){
//Some code here
};
(+var, -())
Same with the prototype function:
referrelSystem.prototype.postToFb = function(){
//Some Code here
};
(Here you don't need the var, because you're assigning to something that already exists.)
A function should return to work as
prototype
property.
Take a look at this example here

How to return name of the property an unnamed function is assigned to

I got following code:
function test () {
this.testFunction = function () {
//code to alert or return the string "testFunction"
}
}
var testVar = new test();
testVar.testFunction();
Is there a way to find out the name of the property, which the unnamed function is assigned to? Whatever I tried yet in conjunction with "caller" and "callee" methods didn't yield any success.
Edit:
The reason why I'd like to retrieve the property name is to use it for debugging messages, where I don't have to manually pass the property name to the logger. Performance would be not an issue since this is just for the developing process.
Actually the suggestion to name the function is a good idea ... I think. Does this have any obvious/well-known side effects, beside having to type in the function name twice? :-P
Additionally this brought me to the idea to add a comment at the start of a function which looks something like
/* $$NAME$$="testFunction" */
and which could also be parsed - but JavaScript comments seem to be trimmed in FireFox (unlike IE), and I rather prefer FF for developing. Would there be a way to also display/use JS comments in FF when using the "caller"/"callee" property?
You can cycle through everything that's available in the instance of the object, e.g.
function test() {
this.testFunction = function () {
for (var i in this) {
if (this[i] === arguments.callee) {
alert(i); // alerts 'testFunction'
}
}
}
}
var x = new test();
x.testFunction();
If your intent is to call the function recursively, you can simply name it
this.testFunction = function inner() {
inner();
}

Categories