How can I access baz() from inside the bar() function in the following code?
var obj = {
baz : function(){ alert("Hi!"); },
foo: {
bar: function(){
baz();
}
}
}
JavaScript doesn't have kind of a built-in parent reference because an object can be referenced by multiple 'parents' in what we call a many-to-one relationship.
As others have said, in this simplified case, simply calling obj.baz() will work.
In a more complicated case, you would have to manually build the object and track parenthood:
// Create the root object
var rootObject = {baz: function() {console.log('rootBaz');}}
// And the basic child
var childObject = {foo: function() {console.log('childFoo');}}
// Configure the parent
childObject.parent = rootObject;
// Add our call.
childObject.baz = function() {this.parent.baz()};
// Invoke and test
childObject.baz();
Which can be slightly simplified:
var rootObject = {
baz: function() {console.log('rootBaz');}
};
var childObject = {
foo: function() {console.log('childFoo');},
baz: function() {this.parent.baz()}
};
childObject.parent = rootObject;
childObject.baz();
Updated per Sujet's comment
In addition, if you need to make sure that baz has the correct value for this you can use either call or apply.
baz: function() {this.parent.baz.call(this.parent)}
If your code doesn't require this then I would recommend a straight function call per my original answer.
Just use the object reference:
var obj = {
baz : function(){ alert("Hi!"); },
foo: {
bar: function(){
obj.baz();
}
}
}
You need to reference via object.property notation.
In your example you would get baz via:
obj.baz()
Some great resources for this:
http://www.w3schools.com/js/js_objects.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
Related
I'm usingconsole.log(value) however when I use console.log() If I wanted to play around with stuff and make it do other things is there a way I can create a function like...
var console.log = (function() { // something }
You could create a wrapper for the console.log function and then only use your wrapper to write to the console:
function myCustomConsoleLog() {
// do stuff with your arguments
console.log(arguments)
}
Now instead of calling console.log(vars) you would make a call to myCustomConsoleLog(vars).
You don't need to declare console.log again because it's already declared.
In Javascript, console is a global variable. There is nothing preventing you from adding, editing or removing properties from it.
So yes, you can just assign a different function to console.log or whatever else you want:
console.log = function(foo, bar) { ... }
console.anotherProperty = { ... }
If however, you were trying to create a foo.bar variable that does not exist yet, you could do it in many different ways:
// first approach
var foo;
foo.bar = function() { ... };
// second approach
var foo = {
bar: function() { ... };
};
// third approach
var fnBar = function() { ... };
var foo = { bar: fnBar };
See more at Console API docs and Working with objects.
This is not possible the way you are trying.
What you can do is create an object and add to it some objects:
var obj = {}; // we create an object where we will add the functions
obj.i = 4; // a value
obj.log = function() { }; // a function
you can do the same, like:
var console = {log:function(){ }};
I guess you could do something like this:
var console = {}
console.log = "alert me!"
alert(console.log);
Is that what you meant?
Let's say I have this code
(function() {
function Foo(arg) {
this.name = arg;
}
Foo.prototype = {
bar: {
baz: function() {
alert(this.name); // Undefined...
}
}
}
var foo = function(arg) {
return new Foo(arg);
};
window.foo = foo;
return foo;
}());
foo("Anything").bar.baz();
How can I make "this" in my function "baz" refers to the object Foo without using bind or apply when I call it from outside ?
FWIW, I would strongly recommend not building nested structures like that, or at least not on the prototype, because the bar object is shared amongst all of the instances, which opens the door to a lot of cross-talk-style bugs. Instead, I'd create bar within the constructor.
How can I make "this" in my function "baz" refers to the object Foo without using bind or apply when I call it from outside ?
You may have bind and apply/call slightly confused. You wouldn't use bind when calling the function, but when creating it. Unless you use bind (or something equivalent to it), you can't do what you've said you want, because absent bind (or similar), this is set by how the function is called, and so this.bar.baz() will make this be this.bar within the call.
Here's how you'd build bar within the constructor, and use bind to make baz use the correct this:
function Foo(arg) {
this.name = arg;
this.bar = {
baz: function() {
alert(this.name);
}.bind(this) // <== Note
};
}
Example:
function Foo(arg) {
this.name = arg;
this.bar = {
baz: function() {
snippet.log(this.name);
}.bind(this) // <== Note
};
}
var f1 = new Foo("f1");
var f2 = new Foo("f2");
f1.bar.baz(); // "f1"
f2.bar.baz(); // "f2"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
More about cross-talk: The naive thing to do is to just add one line to your Foo constructor, and keep bar on the prototype:
this.bar.baz = this.bar.baz.bind(this);
That would be a very bad idea, because you'd get cross-talk between instances:
function Foo(arg) {
this.name = arg;
this.bar.baz = this.bar.baz.bind(this); // DON'T DO THIS
}
Foo.prototype = {
bar: {
baz: function() {
snippet.log(this.name);
}
}
};
var f1 = new Foo("f1");
var f2 = new Foo("f2");
f2.bar.baz(); // "f1" -- cross talk! Should be f2
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Use bind at declaration time to properly scope this, e.g.
function foo() {}.bind(this);
I have an object literal as follows. In the Init method I set a handler for a click event. Later, when the handler is called, I want to access the Bar property using this keyword. At that point, this has the jQuery meaning.
Also, to make things clear, I don't want to implement functions inline with the selectors.
var StackOver = {
Bar: "MyBarValue",
Init: function(){
$("#postId").click(this.Foo);
},
Foo: function(eventObject){
// here **this** is jQuery keyword
// how do I access StackOver.Bar?
}
}
How do I access properties of this object literal inside Foo?
This could have been easy if I was using a constructor literal, which is not a go for me:
var StackOver = function (){
var self = this;
function bar()
{
// I can use self here
}
}
edit I forgot to mention that I use the Revealing Module Pattern in this object literal, that hides private properties from the object.
Everyone else is suggesting .bind, which makes sense, but you also may just be able to reference the object itself in the closure:
Foo: function(eventObject) {
console.log(StackOver.Bar);
}
one option:
Init: function(){
$("#postId").click(this.Foo.bind(this));
}
another option: (from http://api.jquery.com/jquery.proxy/)
Init: function(){
$("#postId").click($.proxy(this.Foo, this));
}
both of there take the this variable so you can't use this for other purposes
if, however, you can't use this:
Init: function(){
$("#postId").click(function (self) {
return function (event) {
return self.Foo(self, event);
}
}(this));
}
and in Foo just add the self parameter.
Foo: function (self, event...) {
...
}
All that said, why can't you use (function () {var self = this; ... }()) ?
It is the revealing module pattern, after all
var StackOver = {
/*...*/
Init: function(){
$("#postId").click(this.Foo.bind(this));
},
/*...*/
Foo: function(eventObject){
// here **this** was actually the html element
// now it's the old this.
alert(this.Bar);
}
}
I'm not sure why this has to be an object literal. If you can use other structures, you could gain access through a revealing module like this:
var StackOver = (function() {
var bar = "MyBarValue",
init = function(){
$("#postId").click(foo);
},
foo = function(eventObject) {
// here `this` might be a jQuery wrapper object
// but you can access `bar` directly.
};
return {
Bar: bar, // Or not. Do you really want this public?
Init: init,
Foo: foo
}
}())
This problem has been bothering me for a long time since I meet it in a project.
In JavaScript, it's easy to access a nested object through . notation. Is there any way to access parent object in a nested object?
Take a look at code below:
function Parent() {
this.foo = new Foo;
this.bar = new Bar;
}
function Foo () {
this.sayHi = function () {
console.log('Hello World');
}
}
function Bar() {
this.callFoosMethod = function () {
// should call object foo's sayHi method and log 'Hello World'
}
}
var parent = new Parent;
parent.bar.callFoosMethod(); // => should log 'Hello World'
parent has two child objects foo and bar, and in bar object's callFoosMethod, I need to access parent's foo object's sayHi method, but the foo nesting in parent knows nothing about its parent object.
Is there any way to access parent object in a nested object Or there is actually no solution to this problem in JavaScript?
No, there is not.
There is a composition relation. If you want to access the 'parent' you have to pass a reference explicitly. That's practice.
Now a word about "why":
A 'sub object' can be a sub-object of multiple objects:
var parent = new Parent;
var o = parent.bar;
o.bar.callFoosMethod(); // but o doesn't have a foo
This also creates issues with architecture. Circular structures are generally bad and the way objects communicate has to be as straightforward as possible.
If they need to talk it has to be through the parent, the Bar is not even aware of the fact there is a Foo there.
Workarounds
Although this is bad practice (high coupling, wrong place for responsibility, etc) if you must you can do:
function Parent() {
this.foo = new Foo(this);
this.bar = new Bar(this);
}
function Foo (parent) {
this.sayHi = function () {
console.log('Hello World');
}
}
function Bar(parent) {
this.callFoosMethod = function () {
parent.foo.sayHi(); // BAD DESIGN WARNING!
}
}
Again, this is really bad design. It completely violates the single responsibility principle, separation of concerns and clear communication. It generally indicates a design problem. Avoid it unless you're absolutely sure it's what you need.
you can modify your function callFoosMethod to accept Foo object as an argument. then invoke the
sayHi in it.
function Parent() {
this.foo = new Foo;
this.bar = new Bar;
}
function Foo () {
this.sayHi = function () {
console.log('Hello World');
}
}
function Bar() {
this.callFoosMethod = function (obj) {
// should call object foo's sayHi method and log 'Hello World'
obj.sayHi();
}
}
var parent = new Parent;
parent.bar.callFoosMethod(parent.foo); // => should log 'Hello World'
demo: http://jsfiddle.net/RgTLP/
I agree with Benjamin; if you need to do Foo things from Bar, why isn't Foo a member of Bar? If the parent class needed to execute a Foo method, it could do so via Bar, rather than making Bar too aware of where it stands in the hierarchy.
In the <head> of my page, I do this:
<script type="text/javascript" src="js/foo.js"></script>
<script type="text/javascript">
console.log(foo.bar);
</script>
Code of foo.js:
var foo = function()
{
this.bar = function()
{
console.log('here');
}
}
Later on in the html document:
Test
However if I click that link above, it says function not defined even though foo.js has been included. Also if I do console.log(foo) it only shows 'function()' and console.log(foo.bar) shows undefined. Why is this, why can't I access the function?
Because you haven't created an object. This is a correct way of running your code:
var foo = function()
{
this.bar = function()
{
console.log('here');
}
}
var instance = new foo();
instance.bar();
http://jsfiddle.net/zerkms/wDaEn/
Or, you can define it in another way:
var foo = {
bar: function() {
console.log('here');
}
};
foo.bar();
http://jsfiddle.net/zerkms/wDaEn/1/
I'm not sure if you want it this way, but to get your console.log(foo.bar); to work you can do this:
var foo = {
bar: function() {
console.log('here');
}
};
Since you are using this and creating instance class member, you need to instantiate the class first:
var fooClass = new foo;
console.log(fooClass.bar());
For minimal code changes use the following:
<script type="text/javascript">
var foo = function()
{
this.bar = function()
{
console.log('here');
};
return this; // magic yes ?
};
foo().bar();
</script>
The content of foo.js just initializes foo to a function... What's in the implentation has no importance until foo() is called.
So foo.bar is undefined.
The above answers are not all correct, remember javascript has no concept of classes or instances of said classes. I would do some reading on Javascript scope and closures.
When you assign your object to the variable name bar, you are assigning it to the local scope. You are then attempting to access your local function from a global context. This is wrong.
I am willing to bet you are attempting something along the following:-
var foo = {
bar: function() {
}
}
Etc...