var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function(){
return function() {
return this.name;
};
}
};
console.log( object.getNameFunc()() );
when i tested the code. the result is The Window. but i think this.name; should be My Object. what's wrong with my thinking.
when i add var before the name : "My Object", it show's an error.? why?
this inside a function is the "receiver" it was invoked upon.
That is,
for the construct x.f(), this inside the function (f) will evaluate to the value of x.
for all other cases, this will evaluate to window inside the invoked function. (The functions call, apply, and bind can also alter this... but that's another story.)
In the posted example the second function (the one with this.name) is not invoked using the x.f() form and so this is the window object.
The "simple fix" is to use a closure: (The first function is invoked in the x.f() form and thus this is the same as object, which is as expected. We capture the value of this in the current scope via a closure created with self and the returned function.)
getNameFunc : function () {
var self = this
return function () {
return self.name
}
}
However, I may consider another design, depending :)
Happy coding.
Additional clarification, for comment:
...that is because you are using circle.getArea() which is of the form x.f(). Thus this inside the getArea function evaluates to circle.
In the code posted you are invoking two different functions in a row. Imagine writing the code like this:
var nameFunc = object.getNameFunc()
nameFunc()
The first function call is in the form of x.f() and thus this inside getNameFunc is the evaluation of object. However, in the second line, the function (nameFunc) is not invoked in the form x.f(). Therefore, the this inside nameFunc (the function returned from getNameFunc) will evaluate to window, as discussed above.
var myObject = {
name:'My Object'
};
console.log(myObject.name);
console.log(myObject['name']);
There are various other ways to make objects in javascript.
this is a hidden argument that is automatically passed from the calling function to the callee. The traditional way is to do:
function MyObject() {
this.name = 'My Object';
}
myObject = new MyObject();
console.log(myObject.name);
Nowadays you might just use closures:
[**edit**: redacted because not a good method]
Nowadays you might just use closures, correctly:
function makeObject() {
var THIS = {};
THIS.name = 'My Object';
THIS.sayMyName = function () {
return THIS.name+" is my name";
}
return THIS;
}
There are many libraries that support "smarter" ways to make objects as well.
You need to use .bind() to set the right context for the method, so the this keyword will be what you want it to actually be.
The default is in such a scenario for the this keyword is to point to the window object, because...this is how the JS engine works.
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
}.bind(this); // <-- sets the context of "this" to "object"
}
};
console.log( object.getNameFunc()() );
As the others have written, you need to target this. I believe this piece of code will help you to understand how this in javascript works
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
that = this; // targeting this
return function() {
return that.name;
};
}
};
alert(object.getNameFunc()()); // it is My Object now
var object = {
name : "My Object",
getNameFunc : function(){
return (function(){
return this.name;
}).bind(this);
}
};
.bind, use the ES5-shim for browser support
The problem lies in the way you have declared your function.
The important point we need to remember while placing function inside a method is to use arrow function (if our function block is going to have a this keyword).
Instead of declaring a new variable and assigning this keyword to the variable, we can easily solve this problem using Arrow Functions.
Just convert the normal function into arrow function and boom it will work.
var name = 'The Window';
var object = {
name: 'My Object',
getNameFunc: function(){
return () => {
return this.name;
};
}
};
console.log( object.getNameFunc()() );
This works because arrow functions are always lexically binded and not dynamically binded like any other functions.
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.
Here's a sample of a simple Javascript class with a public and private method (fiddle: http://jsfiddle.net/gY4mh/).
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
Calling the private function from the public one results in "this" being the window object. How should I ensure my private methods are called with the class context and not window? Would this be undesirable?
Using closure. Basically any variable declared in function, remains available to functions inside that function :
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Another approach is to use "apply" to explicitly set what the methods "this" should be bound to.
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
Yet another approach is to use "call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
both "apply" and "call" take the object that you want to bind "this" to as the first argument and an array of arguments to pass in to the method you are calling as the second arg.
It is worth understanding how the value of this in javascript is determined in addition to just having someone tell you a code fix. In javascript, this is determined the following ways:
If you call a function via an object property as in object.method(), then this will be set to the object inside the method.
If you call a function directly without any object reference such as function(), then this will be set to either the global object (window in a browser) or in strict mode, it will be set to undefined.
If you create a new object with the new operator, then the constructor function for that object will be called with the value of this set to the newly created object instance. You can think of this as the same as item 1 above, the object is created and then the constructor method on it is called.
If you call a function with .call() or .apply() as in function.call(xxx), then you can determine exactly what this is set to by what argument you pass to .call() or .apply(). You can read more about .call() here and .apply() here on MDN.
If you use function.bind(xxx) this creates a small stub function that makes sure your function is called with the desired value of this. Internally, this likely just uses .apply(), but it's a shortcut for when you want a single callback function that will have the right value of this when it's called (when you aren't the direct caller of the function).
In a callback function, the caller of the callback function is responsible for determining the desired value of this. For example, in an event handler callback function, the browser generally sets this to be the DOM object that is handling the event.
There's a nice summary of these various methods here on MDN.
So, in your case, you are making a normal function call when you call privateFunction(). So, as expected the value of this is set as in option 2 above.
If you want to explictly set it to the current value of this in your method, then you can do so like this:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Other methods such as using a closure and defined var that = this are best used for the case of callback functions when you are not the caller of the function and thus can't use 1-4. There is no reason to do it that way in your particular case. I would say that using .call() is a better practice. Then, your function can actually use this and can behave like a private method which appears to be the behavior you seek.
I guess most used way to get this done is by simply caching (storing) the value of this in a local context variable
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
a more convenient way is to invoke Function.prototype.bind to bind a context to a function (forever). However, the only restriction here is that this requires a ES5-ready browser and bound functions are slightly slower.
var privateFunction = function() {
console.log(this);
}.bind(this);
I would say the proper way is to use prototyping since it was after all how Javascript was designed. So:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
Here's a fiddle http://jsfiddle.net/BFm2V/
If you're not using EcmaScript5, I'd recommend using Underscore's (or LoDash's) bind function.
In addition to the other answers given here, if you don't have an ES5-ready browser, you can create your own "permanently-bound function" quite simply with code like so:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
Then use it like this:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
Voilà -- this is magically the outer context's this instead of the inner one!
You can even get ES5-like functionality if it's missing in your browser like so (this does nothing if you already have it):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
Then use var yourFunction = function() {}.bind(thisobj); exactly the same way.
ES5-like code that is fully compliant (as possible), checking parameter types and so on, can be found at mozilla Function.prototype.bind. There are some differences that could trip you up if you're doing a few different advanced things with functions, so read up on it at the link if you want to go that route.
I would say assigning self to this is a common technique:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
Using apply (as others have suggested) also works, though it's a bit more complex in my opinion.
It might be beyond the scope of this question, but I would also recommend considering a different approach to JavaScript where you actually don't use the this keyword at all. A former colleague of mine at ThoughtWorks, Pete Hodgson, wrote a really helpful article, Class-less JavaScript, explaining one way to do this.
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.
followed the docs, tried my own and bump into some problem.
initializeViewModel = function(){
var listing_model = {
sale_rent: ko.observable( jQuery('#id_sale_rent')),
property_type: ko.observable( jQuery('#id_property_type').val()),
address: ko.observable( jQuery('#id_address')),
is_condo: ko.computed(function(){
return this.property_type() == 'condominium';
}, this)
};
listing_model.district = ko.computed(function(){
return this.district() || this.property_type();
}, listing_model);
return listing_model;
}
The statement return this.property_type() == 'condominium'; causes an exception object <object> has no method property_type(). I think this might be a scoping issue, but this seems to be referring to the right instance here. Can someone please point out my problem?
The cleanest solution is to use an anonymous function (to create a closure) rather than a plain object:
initializeViewModel = function(){
var listing_model = new function() {
// Close-in a reference to this object
var self = this;
self.sale_rent = ko.observable( jQuery('#id_sale_rent') );
self.property_type = ko.observable( jQuery('#id_property_type').val() );
self.address = ko.observable( jQuery('#id_address') );
self.is_condo = ko.computed(function() {
return (self.property_type() == 'condominium');
});
}();
// ...
Otherwise, "this" inside the function (that defines the computed) refers to whatever you're passing as the second parameter to ko.computed() - the value of the "this" there is the current context that "initializeViewModel" is executed in, so if you're calling that function as usual (i.e. initializeViewModel()), "this" will just be a reference to the global object and not to "listing_model" (as expected/intended).
The example in the manual differs from you're code: you're creating a plain object right away while in the manual everything is wrapped in a function. Calling that function with the "new" keyword creates a new object and sets the context ("this") to this object. That's why their code works.
Well the this is referring to the anonymous function scope, and secondly this.property_type() is a function call you can't assign a variable to that.
I'm having difficulty referencing "this" from within a javascript inline function, within an object method.
var testObject = {
oThis : this,
testVariable : "somestring",
init : function(){
console.log(this.testVariable); // outputs testVariable as expected
this.testObject.submit(function(){
var anotherThis = this;
console.log(this.testVariable) // undefined
console.log(oThis.testVariable) // undefined
console.log(testObject.testVariable) // outputs testVariable
console.log(anotherThis.testVariable) // undefined
}
}
How do I access this.testVariable from within the submit function?
I'm also using jQuery as well, if that makes a difference.
I wonder if this is the best approach - and maybe I should have submit as a separate function, and then reference that inline, like:
init : function(){
this.testObject.submit = this.submitForm;
},
submitForm : function(){
// do validation here
console.log(this.testVariable) // outputs testvariable
.
.
.
return valid;
}
But this didn't seem to work either - and I think I'd just like to keep the submit function inline within my init method for now.
A common way is to assign the this you want to a local variable.
init: function() {
var _this = this;
this.testObject.submit(function() {
console.log(_this.testVariable); // outputs testVariable
});
}
You could also do this using ES6 arrow functions:
init: function(){
this.testObject.submit( () => {
console.log(this.testVariable);
}
}
Arrow functions capture the this value of the enclosing context, avoiding the need to assign this to a new variable, or to use bound functions.
The "this" variable is bound dynamically when a function — any function, regardless of where it was defined — is called.
Without seeing what that "submit" function is supposed to do, or where it's supposed to be used, it's hard to say how to change it. One thing you could do is to define "submit" in your "init" function:
init: function() {
// whatever
var instance = this;
instance.submitForm = function() {
console.log(instance.testVariable);
// ...
};
}
As long as "init" is called initially with "this" set to an instance of one of your objects, you should be good.
You can only access the oThis variable from the context of the object, which is lost because you are inside of another function. or through instantiating a new object. like this
var testInstance = new testObject();
Then you could access oThis by using:
testInstance.oThis;
but that would be redundant
I would try something like this Matt:
init: function(){
var self = this; // this allows you to access the parent object from different contexts
this.testObject.submit(function(){
console.log(self.testVariable);
}
A possible answer is to use arrow functions and pass in the object that "this" should refer to...
function create() {
var thing = { name: "thingy" };
thing.doStuff = function() {
alert(this.name);
}
thing.doStuff(thing);
}
The reason this works is arrow functions automatically have a final thisArg optional parameter which is bound to this.