I am having trouble calling the object method,it always throw a error this.b
is not a function
var a={
b:()=>"3333",
c:()=>this.b();
}
console.log(a.c());
Your code does not work because the arrow function binds the function to the scope in which it is defined. In this case, you are in the global scope when you create the function "c" using the arrow function. Often this can be fixed with a bind call. However, in this case, I would just convert to a classical function. This is a good lesson in why you should not be lazy and use the arrow function to save a few characters. The arrow function IS NOT the same as a normal function and can lead to hard to debug bugs.
var a={
b:()=>"3333",
c:function () { return this.b() }
}
console.log(a.c())
Simplest way to make your code working is to use a instead of this
var a = {
b: () => "3333",
c: () => a.b()
};
console.log(a.c());
Basically, the reference of c, will call the value based on lexical scope, the same of 'window.c()'.
To fix your implementation, do:
var a={
b:()=>{ return "333"; },
c:function(){ return this.b(); }
}
console.log(a.c()); // Here we have a "333"
Why this happens?
The function expressions work about dynamic scope, different of Arrow Functions. To access Object Properties and reference to same this, use { yourProperty: function() { return "Hello, World"; } }
Related
According to (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions):
An arrow function does not have its own this. The this value of the
enclosing lexical scope is used; arrow functions follow the normal
variable lookup rules.
Here's some examples of where what I thought was the arrow function's this is wrong. (I have not embedded runable code into the question because it gives me different results than my code-editor - Visual Studio Code that's running with node). Could someone explain my examples?
1.
f = param1 => console.log(this);
f(); //expected: global object prints: {}
2.
var bike = {
owner: 'Adam',
getOwner: () => {
console.log(this.owner);
}
};
bike.getOwner(); //expected: 'Adam' prints: undefined
An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules.
So what you need to think of is, what would this refer to if it wasn't in it's own function?
So if we have an IIFE, like:
(() => console.log(this.foo))();
this is equivalent to
console.log(this.foo)
So, using your example:
var bike = {
owner: 'Adam',
getOwner: (() => {
console.log(this.owner);
})()
};
is equivalent to:
var bike = {
owner: 'Adam',
getOwner: console.log(this.owner)
};
and obviously, this.owner doesn't exist.
You could also think of an arrow function as a regular function where you .bind(this) to it:
this.tmp = 'a';
x = () => {
console.log(this.tmp);
}
y = function() {
console.log(this.tmp);
}.bind(this)
x();
y();
The problem is that you are not running the code in a browser (or Node). In both of your examples, this refers to the global object.
Probably wherever you're running the code doesn't provide the usual global object (faster? more secure?) and instead provides {}.
In your case, using traditional function keyword instead of lambda function solves the problem.
var bike = {
owner: 'Adam',
getOwner: function() {
console.log(this.owner);
}};
bike.getOwner();
well they are two cases for this keyword the global Object which is window in the browser or Global in Node JS and the second case is object if it called within any method of that object. so if you called function or run it in the global scope it will refer to the global object as I mentioned before either if it is an arrow function or ordinary function for example:
function foo () {
console.log(this);
}
let bar = () => console.log(this);
foo() // window
bar() // window
the second case it will refer to the object for example:
let obj = {
name: "john doe",
sayName(){
console.log(this.name);
}
}
obj.sayName() // john doe
I hope this will explain you what is the heck of this keyword
For arrow functions, do not require to bind. takes the reference of where the arrow function has defintion.
1 point - This will print the props where the arrow was defined
2 point - is compilation successful, because colon are not suppose to be with arrow function is this fashion.
How are you trying the execution of this code!
Using this keyword inside functions of an object works, but refering to other functions without this doesn't. When I put out those functions before the object, both ways work. Why is that so?
var Obj = {
func1: function () {
console.log(this.func2()); // works
console.log(func2()); // doesn't work
},
func2: function () {
return 5;
}
};
Obj.func1();
But doing the same in IIFE:
var Obj = (function () {
function func1() {
console.log(this.func2()); // works
console.log(func2()); // works
}
function func2() {
return 5;
}
return {
func1: func1,
func2: func2
};
})();
Obj.func1();
This has nothing to do with the IIFE, in the first example you have an object literal, in the second regular functions.
Of course, object literals would need the name of the object (or this if the this-value is the object, like inside an object literal) followed by the property to access it, while named functions can be accessed anywhere in that scope by just using the name.
var obj = {
prop : function() {...}
}
prop(); // fail ... undefined
obj.prop(); // works
// then _______________________________________________________________
function prop() {...}
prop(); // works fine
This is really what you're doing, you've just wrapped it up in different objects and immediately invoked function expressions, so it looks somewhat the same, but it's not.
There is no difference.
In both cases, you're working with an object. So, you need to use this or the object name to call the function defined under an object.
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.
I'm trying to understand when to use anonymous JavaScript functions.
State differences between the functions? Explain when you would use each.
var test1 = function(){
$("<div />").html("test1").appendTo(body)
};
function test2() {
$("<div />").html("test2").appendTo(body)
}
I think the answer is that one uses anonymous function and the other doesn't to replace an empty div element. Does that seem right?
In your example it really doesn't make a huge difference. The only difference is that functions declared using function foo() { } are accessible anywhere within the same scope at any time, while functions declared using var foo = function () { } are only accessible after the code that does the assignment has run.
foo(); // ok
function foo() { ... };
bar(); // error, bar is not a function
var bar = function () { ... };
bar(); // ok
You usually use anonymous functions in cases where you don't need a named function, or where you're constructing objects:
arr.sort(function (a, b) { return a - b; }); // anonymous callback function
function MyObject() {
this.foo = function () { ... } // object constructor
}
You would use a function like the following (which is another type of anonymous function) when you do not want to pollute the global namespace:
(function() {
var pollution = 'blablabla';
function stinky() {
// Some code
}
})();
You may check John Resig's Secrets of JavaScript Libraries, especially page 47 for JavaScript function. Quite lengthy, but you'll learn more about JavaScript
What does the following javascript code mean? I guess it's defining a function within a function to make it look like OOP? Why the function can return multiple functions? what is the bracket at the end?
var grid_ui = function () {
function setup_data_source() {}
return {
init: function () {},
set_ds: function(rpt_headers, rpt_rows) {}
} // return
}();
The { } notation is called an object literal. It is same as:
a = new Object();
a.init = function() { };
a.set_ds = function(...) { };
return a;
and return { } returns an object.
The function () { ... }(); is a self-invoking function: it creates an anonymous function them immidiately invokes it.
In your code, the self-invoking function returns an object of functions, which is a namespace pattern. The value of grid_ui now contains { init: ..., set_ds: ... }, which is mentioned in return.
These concepts are very difficult to explain in one SO answer, so I will provide you some links:
http://www.hunlock.com/blogs/Functional_Javascript/
http://www.dustindiaz.com/namespace-your-javascript/
it is defining an function then calling it and taking the return value and assigning it to grid_ui.
the value of grid_ui is now the object (also called a dictionary) containing the keys init and set_ds.
In javascript, you can define functions within functions and assign functions to variables.
Now you can make calls like grid_ui.init() and grid_ui.set_ds("test", 1).
It is OOP. Functions are objects in JavaScript.
This code means that there is a variable, grid_ui, which evaluates to an object that has two "public" functions, init and set_ds. init and set_ds also have a context which includes a "private" function, setup_data_source.
There are no brackets.