Just made the switch over to ES6, running io.js.
I'm writing some class code, but I'm having an unexpected error.
'use strict';
var _ = require('lodash');
class Country {
constructor(blocked) {
this.blocked = ['USA'];
}
ok(input) {
console.log('Receiving...',input['country']);
console.log('Blocked:', this.blocked);
if(_.includes('USA', input['country'])) {
return -1;
}
return 0;
}
}
module.exports = Country;
For whatever reason, everything works well except for the this.blocked class variable.
When I console log it, it shows up as Blocked: undefined.
Any thoughts as to what's going on here?
Addition
I'm calling the function in another class as follows...
var Country = require('./filters/country.js');
var country = new Country();
class FilterClassifier {
constructor() {
var self = this;
self.filters = [country.ok];
}
userFilter(params) {
var self = this;
var input = {
country : params.country,
};
console.log(self.filters[0](input));
}
}
module.exports = FilterClassifier;
As mentioned in the comments, the way you are calling the function removed the context of the function.
self.filters = [country.ok];
and then
console.log(self.filters[0](input));
means that this inside ok will not be country. You'll need to do
self.filters = [country.ok.bind(country)];
or
self.filters = [() => country.ok()];
I'd recommend reading up on this in javascript. The short answer in this particular case is that this is defined based on how a function is called.
var a = {};
a.fn = function(){};
var b = {};
b.fn = a.fn;
b.fn();
When calling b.fn(), this inside the function is b. This is because when calling a function using the form foo.bar(), this inside a function is defined as the object that the function is called on (foo). In your case, you have
self.filters[0]();
that means that this inside your ok functions is actually self.filters for the same reason.
If you have a specific this that matters, it is your responsibility to make sure that as you pass around a function, that the function you are passing will set the proper this. Using fn.bind(foo) will return a new function which, when called, call fn with a given this.
It looks like this.blocked is scoped to the constructor function, this in ok doesn't have a identifier called blocked.
Edit: I was wrong, thanks Pointy. In the interest of helping others who stumble on this post I'm not going to delete my wrong answer but instead share what I learned. David, in the comments you asked for a way to fix it. this could be replaced with let variables to avoid confusion or use this with bind() when a function is called.
class Country {
// variable scoped to class with let
// set blocked = value in constructor
// should not need 'this.' nor 'bind()'
let blocked = [];
...
}
"Determining this" says you had default this binding: undefined. You hoped for implicit binding and got explicit binding to work with country.ok.bind(country).
Further reading illustrating how the fat arrow => and var self = this; make this confusing.
Related
Background
I want a function keeping track of its own state:
var myObject = {
myFunction: function () {
var myself = this.myFunction;
var firstTime = Boolean(!myself.lastRetry);
if (firstTime) {
myself.lastRetry = Date.now();
return true;
}
// some more code
}
}
The problem with the above code is that the value of this will depend on the site of the function call. I want the function to be able to refer to itself without using:
myObject.myFunction
.bind()
.apply()
.call()
Question
Is it possible to give a function this kind of self awareness independent of its call site and without any help from external references to it?
If you want to store that state on the function instance, give the function a name, and use that name within it:
var myObject = {
myFunction: function theFunctionName() {
// ^^^^^^^^^^^^^^^--------------------- name
var firstTime = Boolean(!theFunctionName.lastRetry);
// ^--------------------------- using it
if (firstTime) {
theFunctionName.lastRetry = Date.now();
// ^------------------------------------------------ using it
return true;
}
// some more code
}
};
You'd do that whenever you want to use a function recursively as well. When you give a name to a function that way (putting the name after function and before (), that name is in-scope within the function's own code. (It's not in-scope for the code containing the function if it's a function expression, but it is if it's a function declaration. Yours is an expression.)
That's a named function expression (where previously you had an anonymous function expression). You may hear warnings about NFEs, but the issues various JavaScript implementations had with them are essentially in the past. (IE8 still handles them incorrectly, though: More in this post on my blog.)
You might consider keeping that state somewhere private, though, via an IIFE:
var myObject = (function(){
var lastRetry = null;
return {
myFunction: function() {
var firstTime = Boolean(!lastRetry);
if (firstTime) {
lastRetry = Date.now();
return true;
}
// some more code
}
};
})();
Now, nothing outside that outer anonymous function can see lastRetry at all. (And you don't have to worry about IE8, if you're supporting stubborn XP users. :-) )
Side note: The unary ! operator always returns a boolean, so your
var firstTime = Boolean(!theFunctionName.lastRetry);
...is exactly equivalent to:
var firstTime = !theFunctionName.lastRetry;
...but with an extra unnecessary function call. (Not that it hurts anything.)
Of course you can, simply give your function an internal named representation and it can refer to itself from there. For example...
var obj = {
doThings:function doThingsInternal(arg1, arg2) {
console.log(arg1, arg2);
for (var arg in doThingsInternal.arguments) {
console.log(arg);
}
}
};
obj.doThings('John', 'Doe');
You could use a simple Closure, if you are not too bent on keeping state existence knowledge within the function. But I guess you don't want that. Another way to do this could be changing the function itself on the first call. Benefits, no/less state variables needed and no costly checks on subsequent calls! -
var myObject = {
myFunction: function () {
// Whatever you wanna do on the first call...
// ...
// And then...
this.myFunction = function(){
// Change the definition to whatever it should do
// in the subsequent calls.
}
// return the first call value.
}
};
You can extend this model to any states by changing the function definition per your state.
I'm trying to create a class in node.js for a small project of mine but I can't really figure out how scoping works.
I have a basic constructor function:
function testClass(username){
this.config = {
uName : username,
url : 'url_prefix'+username,
};
this.lastGame = {
firstTime : 1,
time : null,
outcome: null,
playingAs: null,
playingAgainst : null,
};
this.loadProfile(this.config['url']);
};
And the loadProfile function:
testClass.prototype.loadProfile = function(url){
request(url,function(error,response,body){
$ = cheerio.load(body);
matchTable = $('div[class=test]').children();
tempLast = matchTable.first().html();
if(this.config['firstTime'] == 1 || this.lastGame['time'] != tempLast){
this.lastGame['time'] = tempLast;
}
});
};
(I'm using the Request and Cheerio libraries.)
The problem I have is that I can't use the class variables using "this" inside the "request" function.
It returns "Cannot read property 'firstTime' of Undefined".
This only happens inside the "request" function. I can use "this" and all its functions/variables just fine outside it.
I've thought about passing it to the function but a) I couldn't find how and b) That would mean that any modification I made to the variables wouldn't change the actual class variables.
Could anyone please explain what is going on?
Thanks a lot!
The typical solution is to copy this into another variable called self.
However, if you aren't going to be creating very many instances of your "class", or it only has a few methods, then it's generally simpler to avoid using constructor functions, this and new altogether.
function makeAnObject(username){
// declare private information:
var url = 'url_prefix' + username;
// return public information (usually functions):
return {
loadProfile: function(blah) {
// ...
}
};
};
This lets you have genuinely private data, and you don't have to copy the parameters of makeOnObject by hand, and you don't have to worry about this being broken, or remember to prefix calls with new, etc.
Every function creates a new scope, since scopes are function-centric in JavaScript. The ES6 let keyword will help you circumvent this kind of scenario. Before that, you'll have to stick to retaining a reference to the this you mean to use.
testClass.prototype.loadProfile = function(url){
var self = this;
request(url,function(error,response,body){
$ = cheerio.load(body);
matchTable = $('div[class=test]').children();
tempLast = matchTable.first().html();
if(self.config['firstTime'] == 1 || self.lastGame['time'] != tempLast){
self.lastGame['time'] = tempLast;
}
});
};
Update
if I set self.config['time'] = "whatever", this.config['time'] remains unchanged.
Yes. That's because this refers to the request function local scope, rather than the loadProfile scope you want to refer to. That is why you should be using the self reference, rather than this. self kept a reference to this in the context of loadProfile. Then, this changed when you entered the request callback's context.
Inside request you have different scope. This inside request function is probably instance of request object. You could try something like:
testClass.prototype.loadProfile = function(url){
var self = this;
request(url,function(error,response,body){
$ = cheerio.load(body);
matchTable = $('div[class=test]').children();
tempLast = matchTable.first().html();
if(self.config['firstTime'] == 1 || self.lastGame['time'] != tempLast){
self.lastGame['time'] = tempLast;
}
});
};
Why does the marked line fail to find protectedACMember?
var Module = (function (ns) {
function AbstractClass() {
this.protectedACMember = "abstract";
this.abstractPublicACMethod = function (input) {
this.methodToImplement();
}
}
ConcreteClass.prototype = new AbstractClass();
function ConcreteClass(){
var privateCCMember = "private CC";
var privateCCMethod = function(){
alert(this.protectedACMember); // cant find protectedACMember
}
this.methodToImplement = function(){
privateCCMethod();
console.log('Implemented method ');
}
}
ns.ConcreteClass = ConcreteClass;
return ns;
})(Module || {});
//somewhere later
var cc = new Module.ConcreteClass();
cc.abstractPublicACMethod();
are there any good patterns for simulating private, protected and public members? Static/non-static as well?
You should change that part of code like this:
var self = this;
var privateCCMethod = function(){
alert(self.protectedACMember); // this -> self
}
This way you get the reference in the closure.
The reason is, that "this" is a reserved word, and its value is set by the interpreter. Your privateCCMethod is an anonymous function, not the object property, so if you call it simply by privateCCMethod() syntax, this will be null.
If you'd like "this" to be bound to something specific you can always use .call syntax, like this:
privateCCMethod.call(this)
Another way to ensure that this means what you want is to use bind. Bind allows you to ensure a function is called with a specific value of this.
Most newer browsers support it (even IE9!) and there's a workaround for those that don't.
Bind - MDN Documentation
It fails to find protectedACMember because what the this keyword means changes when you enter the function privateCCMethod. A common practice is to store the outer this for use inside the functions:
function ConcreteClass(){
var privateCCMember = "private CC";
// store the outer this
var that = this;
var privateCCMethod = function(){
alert(that.protectedACMember);
}
...
The rest of your questions are fairly loaded and should probably be posted as a separate question.
This question is simplified version of my old question Adding scope variable to a constructor. Question is simple can I add priv variable to the fu()'s scope without changing the function? (not adding inside of the function block)
Here is fiddle
Here is the code:
fff = function() {
alert('constructed');
//alert(priv);
};
pro = {
pub: 'public'
}
var make = function(fu, pro) {
var priv = 'private';
fu.prototype = pro
return function() {
return new fu();
};
};
var cls = make(fff, pro);
var obj = cls();
alert(obj.pub);
As you can see if you de-comment the
//alert(priv);
line Uncaught ReferenceError: priv is not defined error.
I need a way to redifine the scope of the fu() function object.
I don't see the fu object listed, but I think the answer is "yes", you can add a private variable without changing the "function". Now, I may be missing something, but if I follow you, here is what you want:
var fu = {
DoStuff: function(someVar){
alert(someVar);
}
};
Then later in your code:
fu["NewPrivateVar"] = "something!";
Or in dot notation:
fu.NewPrivateVar = "someting!";
Finally:
fu.DoStuff(fu.NewPrivateVar);
Results in:
"something!"
Is that what you are looking to do?
You can't change the scope of the function by calling it from inside an object or a closure.
You can however add the variable to the scope of the function, i.e. in the global scope:
window.priv = 'private';
That will make the function work without changes, but the variable isn't very private...
I had a "class" defined and was making only one instance of it. The instance possessed a member function that would end up being passed around (it's a mouse handler, but that's not important). Since I would only ever make one instance of my "class", I decided to rewrite it as a singleton by using an object literal.
So I have
var mySingleton = {
theObjects : [];
}
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}());
mySingleton.addObject = function(newObj) {
this.theObjects.push(newObj);
}
However, when I try to use this code (after adding a few objects), I keep getting an that.theObjects is undefined error. It's referring to the line in the for loop.
Update for 2015 – Use Function.bind() to specify the value of this within the function. Then, instead of using that, you can use this.
mySingleton.mouseHandler = function (e) {
for (var indx = 0; indx < this.theObjects.length; indx++) {
// do something to this.theObjects[indx];
}
}.bind(mySingleton);
This doesn't work if you want mouseHandler to have the context of the 'moused' element. For that, use my original answer below.
If you need to support IE8 or (heaven forbid) earlier, you'll need to use a polyfill.
Since you are calling the function that creates mouseHandler immediately, it is run in the context of window, not mySingleton. So that refers to window. Instead of calling it immediately, just change it to a method so that it runs in the context of mySingleton:
mySingleton.getMouseHandler = function() {
var that = this;
return function() { ... };
};
myElement.onclick = mySingleton.getMouseHandler();
Of course, since you are already using a singleton, you can just reference it directly. In your click handler, instead of checking that.theObjects, check mySingleton.theObjects. Or, in mouseHandler change var that = this to var that = mySingleton.
Edit: Or, pass the context to your anonymous function when you call it:
mySingleton.mouseHandler = (function() {
var that = this;
return function (e) {
for (var indx = 0; indx < that.theObjects.length; indx++) {
// do something to that.theObjects[indx];
}
}
}).call(mySingleton);
There are a few popular ways to do this. First, super-simple solution is just reference mySingleton directly and bypass the confusion associated with this. Instead of that.theObjects just do mySingleton.theObjects and move on with your life and things will work fine.
However, there is a common pattern to do this binding. Here's how underscore.js does it
Check out the annoted source to underscore, where you will find this
_.bind = function(func, obj) {
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
};
The other answers here so far are also correct. Providing my viewpoint here in case it helps.
The key to understanding why the code doesn't behave as you expect requires understanding how this works in JavaScript. The problem is that this depends on how the function is called.
First, if you call the function in the method style, this is what you'd expect:
mySingleton.mouseHandler(); // this === mySingleton
If you attach the function to something esle, that works too.
var anotherSingleton = {};
anotherSingleton.foo = mySingleton.mouseHandler;
anotherSingleton.foo(); // this === anotherSingleton
If you detach the function, this becomes the global scope object (window)
var foo = mySingleton.mouseHandler;
foo(); // this === window
And finally, you can force this to be something else using call or apply:
var randomThingy = {};
mySingleton.mouseHandler.call(randomThingy); // this === randomThingy
The takeaway is that this is determined at runtime based on the context of how the function was called. Often, frameworks that allow you to make "classes" abstract these details from you by implicitly applying the bind pattern on your behalf. This is why it used to work, and no longer does.
As others have mentioned, you can change your handler to reference the variable by its scoped name (mySingleton) or otherwise bind it as discussed.
Here's an article I wrote on the subject a few years ago that goes into more detail: http://trephine.org/t/index.php?title=Understanding_JavaScript%27s_this_keyword
Hope this helps!