This question already has answers here:
Is it possible to implement dynamic getters/setters in JavaScript?
(5 answers)
Closed 6 years ago.
I have an object that contains both properties and methods:
var foo = {
bar: function(a) {},
baz: 42
}
I'm trying to restructure, moving all methods into a new methods object:
var foo = {
methods: {
bar: function(a) {},
}
baz: 42
}
Is it possible to remove foo.bar() while also preserving backwards compatibility? E.g. when a user tries foo.bar(a), it's aliased to foo.methods.bar(a)?
Object literals are typically used for storage of state (properties), rather than objects that also have behavior (methods), unless we are talking about objects with static methods.
In general, when making objects with methods, you should make constructor functions rather than object literals and then you should set up the methods on the prototype of that object.
// Use constructor functions for instantiatable objects
function foo () {
// Local variables and instance properties are defined in the constructor
// Set up a simple proxy reference:
this.bar = this.methods.bar;
this.baz = 42;
}
// Set up methods on the prototype, not the constructor because the
// algorithms stored in these properties won't change from instance
// to instance, so we should just store them once - on the prototype
// that all instances of foo will inherit.
foo.prototype.methods = {
bar : function (a) {
console.log("Hello from foo.methods.bar!");
}
};
// Instantiate a "foo"
var f = new foo();
// Call the proxy
f.bar();
Updated
var foo = {
methods: {
bar: function(a) { return true; }
},
baz: 42,
bar: function() { return this.methods.bar() }
}
You will need to keep a reference, something like:
bar: this.methods.bar
Related
This question already has answers here:
New JavaScript prototype changes constructor
(2 answers)
Closed 8 years ago.
Why does obj.constuctor.name give 2 different results if prototype is missing? How do i get the constructor name instead of "Object" if it has prototype then?
// Class with prototype
function Foo(a) {
this.a = a;
}
Foo.prototype = {
bar: function () {
console.log(this.a);
}
};
f=new Foo(1)
f.constructor.name
"Object"
// Class with no prototype
function Fooee(a) {
this.a = a;
}
f1=new Fooee(1)
f1.constructor.name
"Fooee"
You're changing the constructor of Foo() by redefining its prototype to object {}.
You should've instead done this:
Foo.prototype.bar = function () {
console.log(this.a);
}
Functions’ prototype properties have initial values that include constructor. You can try it:
function Foo() {
}
assert(Foo.prototype.constructor === Foo);
When you overwrite the entire prototype with an object, you’re clobbering that property. ({}.constructor === Object.) Just assign new properties to it instead:
Foo.prototype.bar = function () {
console.log(this.a);
};
This question already has answers here:
Setting methods through prototype object or in constructor, difference? [duplicate]
(3 answers)
Closed 8 years ago.
What's the difference between defining methods on a prototype individually vs via an object?
Example:
function Example() {
this.Test();
}
Example.prototype.Test = function() {
alert("Example");
};
instead of:
function Example() {
this.Test();
}
Example.prototype = {
Test: function() {
alert("Example");
}
};
It's the difference between adding to the prototype and replacing it.
The only place it's really likely to make a difference is in this sort of scenario, which is relatively rare (and yet, I avoid replacing prototypes because of it):
var f = new Foo();
function Foo() {
}
Foo.prototype = {
test: function() { }
};
f.test(); // Fails!
Live Copy | Live Source
That fails because the f object is created with Foo's original prototype object, but then later you replace that prototype object with a new one. f still uses the old one, which doesn't have the test property on it.
This works:
var f = new Foo();
function Foo() {
}
Foo.prototype.test = test: function() { };
f.test(); // Works
...because you're just adding to the object that f already uses as its prototype. Live Copy | Live Source
Provided f isn't created until after you've replaced Foo.prototype with a new object, it really doesn't make any significant difference.
This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 9 years ago.
Sometime ago I heard that it was good practice to wrap your code in a big object to serve as a namespace in order to reduce global namespace cluttering and to facilitate library export, so I tried this.
var wrapper = {
foo: function(){
return 42;
},
bar: this.foo()
};
It fails, claiming that "foo is not defined".
Calling methods before finishing the object declaration is probably bad, so I moved bar, and it worked.
var wrapper = {
foo: function(){
return 42;
},
};
wrapper.bar = wrapper.foo();
I feel that this can become kind of ugly, especially with nested namespaces and such, so are there any workarounds that don't make it hard to see all of the wrapper's members at once?
The problem is that this is going to equal the global context. You need to access the function like so:
var wrapper = {
foo: function(){
return 42;
},
bar: null,
init : function() {
// all initialization code goes here
wrapper.bar = wrapper.foo();
}
};
wrapper.init();
This method is great for organizing your code into logical chunks so you and future developers can easily find what you are looking for in your javascript.
var wrapper = {
foo: (function(){
return 42;
})()
};
alert(wrapper.foo);
http://jsfiddle.net/ee8Ww/
Using this like that will not work unless wrapper is 1) a function, and 2) you instantiate it to use it:
var wrapper = function() {
this.foo = function() { return 42; }
this.bar = this.foo();
};
var wrapperInstance = new wrapper();
alert(wrapperInstance.bar()); // 42
wrapperInstance.foo(); // also works
What is the difference between these 2 types of structures
var bar = {
something : value,
execute : function() { /* Whatever */ }
}
function foo() {
this.something = value;
this.execute = function() { /* Whatever */ };
}
My reasoning is that bar is a static object, and foo is a regular object that has to be created calling the new constructor
Is that correct ? Or not really
I assume you mean what's the difference between bar (as you declared it) and
var bar2 = new foo();
There's not a lot of difference between bar and bar2, other than that the prototype for bar will always be the prototype property of Object (as if you had written var bar = new Object(); bar.something = value; bar.execute = function() {...}), while the prototype for bar2 will be whatever is assigned to the prototype property of foo (or the prototype property of Object by default).
Other than the issue of prototypes, writing a constructor function is mostly a matter of convenience.
Note that with the constructor approach, you can use the prototype to advantage:
function foo() {
this.something = value;
}
foo.prototype.execute = function() { /* Whatever */ };
Then all instances of foo share the same execute function. This is much more space efficient than having a new function object for each foo object. (Of course, if you're only creating one of these, there's not much advantage.)
I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"