Here is a trivial use of a closure:
function Thing() {
var _x;
return {
setX: function(val) { _x = val; },
getX: function() { return _x }
};
}
var a = Thing();
var b = Thing();
a.setX(12);
b.setX(23);
a.getX(); //returns 12
What I want to do is be able to define the implementation of setX and getX outside the definition of Thing.
I tried something like this:
function setXimpl(val) {
_x = val;
}
function getXimpl() {
return _x;
}
function Thing() {
var _x;
return {
setX: setXimpl,
getX: getXimpl
};
}
var a = Thing();
var b = Thing();
a.setX(12);
b.setX(23);
a.getX(); //returns 23 not 12!
It's pretty obvious that setXimpl and getXimpl are setting/reading some globally scoped _x, rather than inside the closure.
I tried a bunch of other stuff (mostly syntactical changes), but I just can't get an outside function to be a part of the Thing closure. Is there any way to achieve what I want?
The very short answer to your question is no.
Closures work on the principle of accessing variables within function scope which are not accessible in global scope. This only occurs when the function doing the getting/setting are nested functions within a function that has returned (creating the closure). This implies new functions for setX and getX have to be created each time Thing is called, as in your Thing code.
This doesn't mean that functions returned from Thing can't call functions closer to global scope that are static by using (say) a IIFE
to define Thing:
var Thing = function(){
function a(...) {...}; // create once
function b(...) {...}; // create once
return function () { // the Thing function (create once)
var _x;
return {
setX: function(val) { _x = val; },
getX: function() { return _x }
};
};
}();
effectively giving the anonymous getter and setter functions access to statically defined encapsulated function helpers.
Try a factory:
function setXimplLoader(x) {
return function setXimpl(val) {
x.value = val;
};
}
function Thing() {
var _x = { value: '' };
return {
setX: setXimplLoader(_x),
getX: function() { return _x.value; }
};
}
var a = Thing();
var b = Thing();
a.setX(12);
b.setX(23);
console.log(a.getX())
Or use some utility library:
https://lodash.com/docs#partial
Related
Consider this:
var Foo = function Foo () {
var numberVar = 0;
fooPrototype = {
getNumberVar: function () {
return numberVar;
},
setNumberVar: function (val) {
this.numberVar = val;
}
}
return fooPrototype;
};
var foo = new Foo();
Alternatively, look at this:
var Bar = function Bar() {
var numberVar = 0;
};
Bar.prototype = {
getNumber: function () {
return this.numberVar;
},
setNumber: function (val) {
this.numberVar = val;
}
};
var bar = new Bar();
They both do the same thing, in that they allow for public / private members. Is there any benefit to doing this one way or the other?
Your logic here is based on a faulty assumption. In your second implementation, the constructor variable numberVar is never used. You have no code that can reach it and thus you are not using a private variable in the second code block.
Your methods in that second implementation are accessing an object property named numberVar which is publicly accessible as a property on the object which is different than the local variable of the same name in your constructor. You cannot have private variables in your second implementation because your prototype-declared methods are not declared in a private scope.
Here's what happens in your second code block:
var Bar = function Bar() {
// this variable is never used as there is no code in this scope
// that can reach this variable. In fact, it is garbage collected
// immediately
var numberVar = 0;
};
Bar.prototype = {
getNumber: function () {
return this.numberVar;
},
setNumber: function (val) {
// sets a public property on the object
this.numberVar = val;
}
};
var bar = new Bar();
bar.setNumber(10);
console.log(bar.numberVar); // 10, this property is public
For a general discussion of methods declared in the constructor vs. prototype-defined methods, see this discussion:
Advantages of using prototype, vs defining methods straight in the constructor?
TypeScript compiles a class something like:
var UrlProvider = (function(){
//tons of logic in here that only needs to be performed once for each UrlProvider instance
function UrlProvider(baseUrl){
var baseRequest = {
get: function(){return baseUrl;},
update: function(){return baseUrl;},
delete: function(){return baseUrl;}
};
var documents = function(){
var context = '/documents/';
return{
get: function(){return baseRequest.get() + context;},
post: function(){return baseRequest.post() + context;},
delete: function(){return baseRequest.delete() + context;}
}
};
var editors = function(){
var context = '/editors/';
return{
get: function(){ return baseRequest.get() + context; },
post: function(){ return baseRequest.post() + context; },
delete: function(){ return baseRequest.delete() + context; }
}
}
}
return UrlProvider;
})();
Is there any benefit to putting logic outside of the UrlProvider constructor, but inside the closure of the outer IIFE? My thinking was that perhaps if we needed a remote service or some other expensive process to create UrlProviders that could possibly be better placed in the outer closure vs. the constructor of the UrlProvider? Is this correct? IS there any benefit to putting logic in outside the constructor, but inside the IIFE?
IS there any benefit to putting logic in outside the constructor, but inside the IIFE
Yes. The IIFE is needed for inheritance to capture the base class. This is shown below
class Foo {
log() { }
}
class Bar extends Foo {
log() {
super.log(); // IIFE needed for `super` to work
}
}
Look at the generated javascript (I've removed the extends function).
var Foo = (function () {
function Foo() {
}
Foo.prototype.log = function () {
};
return Foo;
})();
var Bar = (function (_super) {
__extends(Bar, _super);
function Bar() {
_super.apply(this, arguments);
}
Bar.prototype.log = function () {
_super.prototype.log.call(this); // IIFE needed for `super` to work
};
return Bar;
})(Foo);
_super is captured by the IIFE. Reason is that functions are the only thing that create a variable scope in JavaScript and that is why we create an IIFE in the codegen to capture the base class in a nice local name (_super). This is conventional JavaScript, not specific to TypeScript.
I want to build a function outside a jQuery scope:
(function($) {
function MyObject() {
console.log('foo');
};
}(jQuery));
var $my_object = new MyObject();
But function MyObject is not accessible :
ReferenceError: MyObject is not defined
However, if i build my function in the scope, it's working:
(function($) {
function MyObject() {
console.log('foo');
};
var $my_object = new MyObject();
}(jQuery));
foo
How access to MyObject outside the scope ?
I would probably not recommend it but you can basically do what you want by returning the functions as part of an object and assigning the IIFE to a variable like this
var library = (function ($) {
var exports = {};
var private = 'see you cant get this';
var MyObject = exports.MyObject = function (_in) {
console.log(_in);
};
var another_func = exports.sum = function (a, b) {
console.log(a + b);
};
return exports;
}(jQuery));
library.MyObject('foobar'); // "foobar"
library.sum(3, 5); // 8
console.log(private); // Uncaught ReferenceError: private is not defined
Although I don't know why you want to do it.. Maybe this helps
// Define Class globally
// window.MyObject also works
var MyObject = (function($) {
// Passes jQuery in
return function () {
console.log('foo');
};
}(jQuery));
var $my_object = new MyObject();
I always have difficulty grasping new concepts without seeing a real, basic, working example of what I am reading about. While I like the other explanation on stackoverflow, I'd really like to see a very basic example showing the difference between methods and functions in JavaScript that I can quickly run to learn more.
A method is just a function that is a property of an object. It's not a different type of object in javascript, but rather method is just the descriptive name given to a function that is defined as a property of an object.
var myObj = {};
myObj.go = function() {alert("hi");}
myObj.go();
In this example, go is a method on the myObj object.
When a method is called as in the above example myObj.go(), then the value of the this pointer is set to the object that was involved in the invocation of the method (in this case myObj).
Since global functions are also implicitly properties on the window object, one could say that global functions are also methods on the window object, but you do not need the window designation in order to call them.
Local functions like inner() in this function are just functions and not methods as they are not attached to a particular object:
function main() {
function inner() {
alert("hi");
}
inner();
}
This is a function and a function call:
function myFunction(){
alert("This is a function!");
}
myFunction();
This, on the other end, is a method call, because it is a member function of an object.
message.toUpperCase();
Here's the full code to create a class/methods and a call:
function Circle(x,y,r) {
this.xcoord = x;
this.ycoord = y;
this.radius = r;
}
Circle.prototype.retArea = function () {
return ( Math.PI * this.radius * this.radius );
};
var aCircle = new Circle(1,2,3);
var a = aCircle.retArea();
example:
function:
var f1 = function fBase() { ... }
function f2() { ... }
var f3 = function() { ... }
f1()
f2()
f3()
method:
var c = function oBase() {
this.method1 = function() { ... };
}
c.prototype.method2 = function() { ... }
var o = new c()
o.method1()
o.method2()
method json:
var o = { method1: function() { ... } }
o.method2 = function() { ... }
o.method1()
o.method2()
A function is a type which can be used to define a piece of code that can be executed by using call ("()") operator and may return data to the caller.
e.g.
define
function sayHello(){
return "Hello";
}
use
var result = sayHello();
Now, result will contian "Hello".
A method is a function that is defined inside an object and accessible through a property. For example, slice is function defined over all string instances
e.g.
define
var obj = {
sayHello : function(){
return "Hello";
}
};
you can also define methods outside the object definition
var obj = {};
obj.sayHello = function(){
return "Hello";
};
use
var result = obj.sayHello();
We use methods in object oriented programming.
Refer:
Functions at MDN
Objects at MDN
Okay, I'm hating Javascript right now, and I hope someone can help me.
I have code which is set up like the following:
function Obj1() {
var me = this;
this.something = "yay";
this.getThis = function(){
return me;
}
}
Obj1.prototype.method = function() {
return this.something;
};
function Obj2() {
this.something = "nay";
}
Obj2.prototype.method = function() {
return this.something;
};
var o1 = new Obj1();
var o2 = new Obj2();
document.write(o1.method()); // Returns yay
document.write(o1.method.call(o2)); // Returns nay, but I need "yay" here
(JSFiddle # http://jsfiddle.net/A9u9K/)
My Problem is, that I need to call Obj1.method in the second case, but I am absolutely unable to get a reference to the object :(
How can I work around this?
Edit: Sorry, I got my example code pretty wrong :( Updated it. I took most of the code from a previous answer, because it is much nicer and still illustrates my problem.
Updated Answer:
document.write(o1.method.call(o2)); // Returns nay, but I need "yay" here
You've said you've got it sorted now, but as the answer to that isn't actually shown here on SO, I figured I may as well update to show it.
If it's method you want to have access me, even if it's been called with a different this value, you have to define it like getThis, as a closure over me:
function Obj1() {
var me = this;
this.something = "yay";
this.method = function() {
return me.something;
};
this.getThis = function(){
return me;
};
}
function Obj2() {
this.something = "nay";
}
Obj2.prototype.method = function() {
return this.something;
};
...or of course, if you don't need the "something" to be a property on the object, just make it a var within the constructor (a private variable, like me):
function Obj1() {
var me = this;
var something = "yay";
this.method = function() {
return something;
};
this.getThis = function(){
return me;
};
}
function Obj2() {
this.something = "nay";
}
Obj2.prototype.method = function() {
return this.something;
};
Original Answer: (To Revision 1 of the question, which didn't have me.)
but I thought that, when creating a closure (as I do in 4) Javascript should preserve "this".
this is set entirely by how a function is called, not where it's defined; more about that here and here. But the way you've defined your getThis function, you can use the fact it closes over the constructor call to solve this (no pun) without using this:
function Obj1() {
var me = this; // <== Use a variable to remember `this`
this.something = "yay";
this.method = function() {
return this.something;
};
this.getThis = function(){
return me; // <== Return it
};
}
Live example
More about closures and the plumbing that makes the me thing work here.
There is a cost involved in this, and just generally in your pattern of defining functions within the constructor function: Each individual object created by Obj1 and Obj2 gets its own copy of each function. This can have memory implications if there are lots of these objects running around (but unless you have lots, you needn't worry and you get benefits like the me thing and other private variables). In constrast, if you use a function assigned to the prototype, all instances will share a single, common copy of the function.
In your sample code, only the getThis function really needs to be duplicated for every instance (because you're relying on the closure), so you can do this to avoid unnecessary function proliferation:
function Obj1() {
var me = this;
this.something = "yay";
this.getThis = function(){
return me;
};
}
Obj1.prototype.method = function() {
return this.something;
};
function Obj2() {
this.something = "nay";
}
Obj2.prototype.method = function() {
return this.something;
};
see it here http://jsfiddle.net/2Jhwv/5/
The issue is with the reference changing for the this object with scope.
Instead if using a this directly in closure use a local variable equated to this, i.e, change your Obj1 toL
function Obj1() {
this.something = "yay";
var that = this;
this.method = function() {
return that.something;
}
this.getThis = function(){
return that;
}
}
The only way to solve this is to another place holder to hold the value of this in Obj1 and use it in the function method() and getThis().
function Obj1() {
var instance = this;
this.something = "yay";
this.method = function() {
return instance.something;
}
this.getThis = function(){
return instance;
}
}
But what I cannot under stand is why you are doing it(obj1.getThis.call(obj2).method())?
This explicitly says that you want to change the scope of the method getThis() to something else, then you are trying to solve the problem which was created by this usage.
Can you tell why you want something like this?