JavaScript function encapsulation outside the object - javascript

Please see the following script:
var x = function(param){
this.data=param;
this.y = function(){
alert(this.data)
}
return this;
}
/*
x.prototype.z = function(){
alert(this.data);
}
*/
x(123).y();
x(123).z(); // This should behave same as y()
When I call x(123).y() then message displays 123. The function y() declared inside x()
Now I want to declare another function z() which will reside outside x() but will behave same as y() [associate with x()]
Is it possible? If possible how?

You're missing a new when calling x(). Otherwise, this within the function body will refer to the global object (window in browser contexts) and not an instance of x.
That's the reason why calling z() (after un-commenting the code) doesn't work. Calling y() only works by coincidence as you create a global variable data, whose value will be overwritten by the next call to x().
I have no idea what you're trying to accomplish, and from what I can see, it most likely isn't a good idea. Anyway, here's an example of how to get rid of explicit new when creating objects:
var x = function(param){
// add missing `new`:
if(!(this instanceof x))
return new x(param);
this.data=param;
this.y = function(){
alert(this.data)
}
}
x.prototype.z = function(){
alert(this.data);
}
x(123).y();
x(456).z();

It is possible, and your commented-out z function should work as is if you fix how you're creating xs.
Note that your function y doesn't have to be declared inside the constructor if it's only dealing with instance properties (which in your code it is), and doing so has a significant memory cost (every instance gets its own copy of that function). You only want to do that if you absolutely have to for major data hiding reasons, given the costs involved.
Edit: Sorry, I missed something: You're missing the new keyword, your examples should be:
new x(123).y();
new x(123).z();
...and your constructor shouldn't return this.
Complete example:
var x = function(param) {
this.data=param;
// Doesn't have to be in the constructor, and you should
// avoid it unless you're doing something with major
// data hiding a'la Crockford
this.y = function() {
alert(this.data)
}
}
x.prototype.z = function() {
alert(this.data);
}
new x(123).y();
new x(123).z();
This is the Crockford article I mention above, but again, it has big memory implications.

function generator( param ) {
this.data = param;
this.y = function() {
alert( this.data )
}
}
generator.prototype.z = function() {
alert( this.data );
}
x = new generator( 3 );
x.y()
x.z()
Not sure if this is what you want, but this is a constructor named generator which returns an object, and a prototypal method is defined outside of it with the new keyword.
As others stated:
you don't need to return this in the constructor
you call it with the new keyword
all methods declared with this are public unless you use var in which case they become private

Related

Newly created objects call to constructor undefined if constructor is inside another function

I just learned OOP and there is one little thing that I am not able to solve. The problem is a scope issue of some sort.
If I create a new object then how will I be able to give it access to my constructor function if the constructor function is inside another function? Right now I get undefined. Storing the function in a global variable wont do the job.
var example = new something x(parameter);
example.i();
var getFunction;
var onResize = function() {
getFunction = function something(parameter) {
this.i= (function parameter() {
// Does something
});
};
};
window.addEventListener('resize', onResize);
onResize();
For OOP javascript, the pattern should be like this.
//defining your 'class', class in quotes since everything is just functions, objects, primitives, and the special null values in JS
var Foo = function (options) {
// code in here will be ran when you call 'new', think of this as the constructor.
//private function
var doSomething = function () {
}
//public function
this.doSomethingElse = function () {
}
};
//actual instantiation of your object, the 'new' keyword runs the function and essentially returns 'this' within the function at the end
var foo = new Foo(
{
//options here
}
)
If I understand you, you want to know how to access variables inside another function. Your attempt is reasonable, but note that getFunction is not bound until after onResize is called. Here's a bit of a cleaner demo:
var x;
function y() {
// The value is not bound until y is called.
x = function(z) {
console.log(z);
}
}
y();
x('hello');
A common JavaScript pattern is to return an object that represents the API of a function. For example:
function Y() {
var x = function(z) {
console.log(z);
}
return {
x: x
};
}
var y = Y();
y.x('hello');
You should definitely read up on the basic concepts of JavaScript. Your code and terminology are both sloppy. I'd recommend Secrets of the JavaScript Ninja. It does a good job explaining scope and functions, two tricky topics in JavaScript.

Javascript OOP and Classes Problems

I wanted to rearrange my Code to OOP, but I am not able to figure out my errors here, especially since they appear correct according to different Tutorials and examples.
I suppose I misunderstand something of JS´s, object-instantiation and Call stack.
I will provide some examples, which I don´t understand.
What I want here is to do some operations on an Array and then get it to an other class.
https://jsfiddle.net/8g22nj8y/1/
<script>
$(document).ready(function() {
var p = new Parser();
p.init();
p.getArray();
p.getArray2();
p.get3();
}</script>
function Parser() {
var myArray = [];
this.myArray2 = [];
thisReference = this;
this.myArray3=[];
return {
init: function () {
alert("huhu");
this.parse2();
parse();
},
getArray: function () {
alert(thisReference.myArray2.length);
},
getArray2: function () {
alert(myArray);
}
}
function parse() {
var arr = [1, 2, 3];
myArray.push(arr);
myArray2.push(arr);
for(var i =0;i<10;i++){
a=[];
a.push(i);
thisReference.myArray3.push(a);
}
}}Parser.prototype.parse2 = function () {
var arr = [1, 2, 3];
myArray.push(arr);
this.myArray2.push(arr);};
Independent how I run it, it always says that this.parse2() is not a function.
When I am only using parse(), it says that myArray2 is undefined, althought it´s clearly there - just as "class variable". If I change myArray2 in parse() to thisReference.myArray2 it´s working.
Why? I thought an inner Function - which parse() clearly is, is able to grab all the variable in the outer function - in this case Parser(). When I am now using myArray3 either if it´s used with thisReference or with this. "it is not defined".
If I call parse2 with thisReference it´s working, but then "myArray is not defined", yes it´s an local variable but it´s in the same class and if I call parse() I am able to use it without problems.
Furthermore:
simplified: https://jsfiddle.net/Lzaudhxw/1/
function Syntax(){
var mine = new Lex();
myRef=this;
}
Class1.prototype.foo=function(){
myRef.mine.setFunc(5);
myRef.mine.publicFunc();}
function Lex(){
this.x, this.h=1;
return{
publicFunc: function(param){
this.h;
this.x;
},
setFunc: function(x){
this.x=x;
}
}
Initially I set h to be 1. If I now instantiiate Syntax and call from that the publicFunc from Lex both are undefined. But if I run foo() from Syntax and call the publicFunc again, x is set to the value and h is undefined. Why is it not possible to predefine an varriable (in this case h) like that and then use it?
EDIT to Jan´s Answer:
I read in many Tutorials and some production code that you should store "this" into an variable. Why should myRef point to anything else than the Syntax Object? :O
Why is myRef not an variable of Syntax? Does it have to be this.myRef?
Ahh right, var means local, so mine is only accessiable in the constructor?!
I didn´t wanted to init "x", only define it.
Ahh with return{} I am creating a new class/object, then it´s clear that this. does not point to the above vars. But to introduce an myRef=this should do the job, right?
...So, it´s wiser to use prototype to add functions instead of an inner function?
Yeah you've got a bunchload of JS concepts wrong. I suggest you read the documentation. Tried adding a few explanations.
function Syntax(){
// Since you're returning a new object from "Lex" straight away, there's
// little point of using "new" here
var mine = new Lex();
// Why store "this" here? "this" will be accessible from your prototype
// methods pointing to your object instance... Provided you use "new Syntax()",
// Otherwise "myRef" will (probably) point to the global object.
myRef=this;
}
// Where's "Class1"? You don't have a Class1 function anywhere. You probably mean "Syntax"
Class1.prototype.foo=function() {
// "myRef" is not a property of "Syntax", so it wouldn't be accessible here.
// Furthermore, "mine" is declared as a variable above, so it wouldn't be
// accessible in this manner even if "myRef" pointed to "this" (which it doesn't).
myRef.mine.setFunc(5);
myRef.mine.publicFunc();
}
function Lex(){
// This is a correct property declaration of h. You're not setting the
// value of x here though, just calling it. Javascript allows "trying"
// to call ANY property of ANY object without giving neither a compilation
// nor runtime error, so calling the undefined "this.x" here is valid.
// It just won't do anything.
this.x, this.h=1;
// Here you return a new object straight off, so the below "this" will point
// to the object below, not the "Lex" object defined above. So your above
// defined "this.h" will not be used, it's a property of a different object.
return {
publicFunc: function(param){
this.h;
this.x;
},
setFunc: function(x){
this.x=x;
}
}
// You're missing a closing bracket here.
What you're probably trying to do would look something like this with correct Javascript syntax
function Syntax(){
this.mine = Lex();
}
Syntax.prototype.foo=function() {
this.mine.setFunc(5);
this.mine.publicFunc();
}
function Lex() {
return {
h:1,
publicFunc: function(){
console.log(this.h);
console.log(this.x);
},
setFunc: function(x){
this.x=x;
}
}
}
var s = new Syntax();
s.foo();
But returning an object from Lex would be pretty impractical in most cases. So what you really REALLY want to do is probably
function Syntax(){
this.mine = new Lex();
}
Syntax.prototype.foo = function() {
this.mine.setFunc(5);
this.mine.publicFunc();
}
function Lex() {
this.h = 1;
}
Lex.prototype = {
publicFunc: function(){
console.log(this.h);
console.log(this.x);
},
setFunc: function(x){
this.x=x;
}
};
var s = new Syntax();
s.foo();

How to properly pass functions to other functions in javascript

I am trying to understand the way that javascript passes functions around and am having a bit of a problem groking why a prototype function can NOT access a var defined in a function constructor while a function defined in the constructor can access the var. Here is code that works:
var model = function model() {
this.state = 1;
this.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
}
var othermodel = function othermodel(mdl) {
this.GetStateFn = mdl.GetState;
}
othermodel.prototype.WriteState = function() {
console.log(this.GetStateFn.call());
};
var m = new model();
var o = new othermodel(m)
o.WriteState();
This works and makes sense - the GetState() function can access this.state.
However, if I create GetState as follows:
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
The result will be an error that scope is not defined.
I would prefer to have this work with the prototype method as I do not want a copy of the function in ever model, but it would seem that prototype can't work because it can't access the specific instance of the model.
So, can someone provide me with a good explanation of a) what I need to do to get this to work with prototype (assuming I can) and b) if I can't get it to work with prototype, what is the reason so I can understand better the underpinnings of the issue.
Why not simply write the function this way
model.prototype.GetState = function() { return this.state; }
var othermodel = function othermodel(mdl) {
this.GetStateFn = mdl.GetState.bind(mdl);
}
othermodel.prototype.WriteState = function() {
console.log(this.GetStateFn.call());
};
The above code will work, as in most cases you will execute code like m.GetState(). That is an example of invoking a function as an object method. In that case, this is guaranteed to point to the object m. You seem to know how the prototype chains work, so I won't go there.
When assigning the function reference to the other model, we use the .bind to ensure that within GetState, this points to mdl. Reference for bind: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Your original IIFE's were in effect your implementation of bind. The issue was the value of this was wrong. Currently, every time you need to assign models function to some other function, you will need to use bind at all those times. You have tagged your question as node.js, bind is available on the Function prototype in node.js and any ES5 compatible browser. If you need to run the above code on older browsers or environments that do not support bind, replace bind with your IIFE.
As for why your code isn't working,
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
Here, this doesn't refer to the eventual model object (m). this can refer to any one of 5 options in javascript. Refer: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
Lets assume the above code is in an html file inside some script tag. Then this will refer to the window object. window doesn't have any property called state, hence the undefined. If you were to console.log(this.m, this.o) at the end of you script, you would see the respective m and o objects.
When defined like this:
var model = function model() {
this.state = 1;
this.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
}
the anonymous function is declared and immediately executed. this is passed as a parameter to that self-executing function. As a result - a new function is returned, but this function has scope parameter in its closure - so that it is accessible after the scope has exited. As a result - the function, when invoked, can still access state property of that "enclosed" this (the one that became scope and was closed upon).
If you define it like this:
model.prototype.GetState = (function(scope){
return function(){ return scope.state;};
})(this);
the mechanism is the same, it's just this is not. It is now the context of the scope you execute the above code in. Assuming it's done in global scope - it would be window object.
If you don't want to use bind because of its support with older browsers, you could try this:
http://jsfiddle.net/j7h97/1/
var model = function (state) {
this.state = state || new Date().getTime();
};
model.prototype.GetState = function () {
return this.state;
};
model.prototype.WriteState = function () {
console.log("model WriteState: " + this.GetState());
};
var othermodel = function othermodel (mdl) {
this.GetStateFn = function () {
return mdl.GetState.call(mdl);
};
};
othermodel.prototype.WriteState = function () {
console.log("othermodel WriteState: " + this.GetStateFn());
};
var model1 = new model();
model1.WriteState();
var othermodel1 = new othermodel(model1);
othermodel1.WriteState();
var model2 = new model();
model2.WriteState();
var othermodel2 = new othermodel(model2);
othermodel2.WriteState();
Seems to do what you want without bind. I created the model.prototype.WriteState for testing purposes.
It depends on where it is called. If it's in global scope, this will not refer the the model. If it's running in a browser it will refer to the global window object instead.

Confusing JavaScript statement: "var x = new this();"

I thought I understood the concept of the JavaScript prototype object, as well as [[proto]] until I saw a few posts regarding class inheritance.
Firstly, "JavaScript OOP - the smart way" at http://amix.dk/blog/viewEntry/19038
See the implementation section:
var parent = new this('no_init');
And also "Simple JavaScript Inheritance" on John Resig's great blog.
var prototype = new this();
What does new this(); actually mean?
This statement makes no sense to me because my understand has been that this points to an object and not a constructor function. I've also tried testing statements in Firebug to figure this one out and all I receive is syntax errors.
My head has gone off into a complete spin.
Could someone please explain this in detail?
In a javascript static function, you can call new this() like so,
var Class = function(){}; // constructor
Class.foo = function(){return this;} // will return the Class function which is also an object
Therefore,
Class.foo = function(){ return new this();} // Will invoke the global Class func as a constructor
This way you get a static factory method. The moral of the story is, not to forget functions are just like any other objects when you are not calling them.
What is confusing you, I think, is just where "this" is really coming from. So bear with me-- here is a very brief explanation that I hope will make it quite clear.
In JavaScript, what "this" refers to within a function is always determined at the time the function is called. When you do:
jimmy.nap();
The nap function (method) runs and receives jimmy as "this".
What objects have references to nap is irrelevant. For example:
var jimmy = {}, billy = {};
jimmy.nap = function(){ alert("zzz"); };
var jimmy_nap = jimmy.nap;
jimmy_nap(); // during this function's execution, this is *NOT* jimmy!
// it is the global object ("window" in browsers), which is given as the
// context ("this") to all functions which are not given another context.
billy.sleep = jimmy.nap;
billy.sleep(); // during this function's excution, this is billy, *NOT* jimmy
jimmy.nap(); //okay, this time, this is jimmy!
In other words, whenever you have:
var some_func = function(arg1, arg2){ /*....*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(2, 3);
other_obj.some_meth(2, 3);
What it's getting "translated" into (not literally-- this is pedagogical, not about how javascript interpreters actually work at all) is something like:
var some_func = function(this, arg1, arg2){ /* ...*/ };
// let's say obj and other_obj are some objects that came from somewhere or another
obj.some_meth = some_func;
other_obj.some_meth = some_func;
obj.some_meth(obj, 2, 3);
other_obj.some_meth(other_obj, 2, 3);
So, notice how extend is used in the example on that page:
UniversityPerson = Person.extend({ /* ... */ });
Pop quiz: When extend runs, what does it think "this" refers to?
Answer: That's right. "Person".
So the puzzling code above really is the same as (in that particular case):
var prototype = new Person('no_init');
Not so mysterious anymore, eh? This is possible because unlike in some languages,
a JavaScript variable-- including "this"-- can hold any value, including a function such as Person.
(There is nothing that makes Person specifically a constructor. Any function can be invoked with the new keyword. If I recall the exact semantics, I think they are that when a function is called with the new keyword, it is automatically given an empty object ({}) as its context ("this") and when the function returns, the return value is that same object unless (maybe?) the function returns something else)
This is a cool question because it speaks to a pretty essential part of JavaScript's neatness or oddness (depending on how you see it).
Does that answer your question? I can clarify if necessary.
AJS.Class effectively* translates this:
var Person = new AJS.Class({
init: function(name) {
this.name = name;
Person.count++;
},
getName: function() {
return this.name;
}
});
Person.count = 0;
into this:
var Person = function (name) {
this.name = name;
Person.count++;
};
Person.prototype = {
getName: function() {
return this.name;
}
};
Person.extend = AJS.Class.prototype.extend;
Person.implement = AJS.Class.prototype.implement;
Person.count = 0;
Therefore, in this case, this in AJS.Class.prototype.extend refers to Person, because:
Person.extend(...);
// is the same as
Person.extend.call(Person, ...);
// is the same as
AJS.Class.prototype.extend.call(Person, ...);
* There are a lot of cases I don't go over; this rewrite is for simplicity in understanding the problem.
Imagine the following situation :
var inner = function () {
var obj = new this;
console.log(obj.myProperty);
};
var f1 = function () {
this.myProperty = "my Property"
}
f1.f2 = inner;
f1.f2();
Here the calling object is itself a function, so this will return a function, and we can instantiate it.
In order to use this()(not this) the outer function(the context) must itself return smth that can be instantiated(another function):
var inner = function () {
var obj = new this();
console.log(obj.myProperty);
};
var f1 = function () {
var func = function () {};
func.myProperty = 'my property';
return func;
};
f1.f2 = inner;
f1.f2();
A simpler code explaination:
class User {
constructor() {
this.name = '';
this.age = '';
}
static getInfo() {
let user = new this();
console.log(user);
}
}
User.getInfo()
Output:
Object {
age: "",
name: ""
}
see this link http://www.quirksmode.org/js/this.html It will tell you about the this keyword, but I am not sure what this() is, may be its some kind of user defined function...... that you are not aware of...
"this" means the context of the function currently running.
The code you are posting surely appears in a function that act as a method for an object.
So the object is the context of the function.
"new this()" will return a clone of the current object after running its constructor function with the passed arguments.
this() refers to the the function that the code is in, but this() would have to be within that function. Calling new this(); within a function would create a never ending loop. Calling it outside of a function would be redundant because there is no function/class set as this().

Attaching methods to prototype from within constructor function

Here is the textbook standard way of describing a 'class' or constructor function in JavaScript, straight from the Definitive Guide to JavaScript:
function Rectangle(w,h) {
this.width = w;
this.height = h;
}
Rectangle.prototype.area = function() {
return this.width * this.height;
};
I don't like the dangling prototype manipulation here, so I was trying to think of a way to encapsulate the function definition for area inside the constructor. I came up with this, which I did not expect to work:
function Rectangle(w,h) {
this.width = w;
this.height = h;
this.constructor.prototype.area = function() {
return this.width * this.height;
};
}
I didn't expect this to work because the this reference inside the area function should be pointing to the area function itself, so I wouldn't have access to width and height from this. But it turns out I do!
var rect = new Rectangle(2,3);
var area = rect.area(); // great scott! it is 6
Some further testing confirmed that the this reference inside the area function actually was a reference to the object under construction, not the area function itself.
function Rectangle(w,h) {
this.width = w;
this.height = h;
var me = this;
this.constructor.prototype.whatever = function() {
if (this === me) { alert ('this is not what you think');}
};
}
Turns out the alert pops up, and this is exactly the object under construction. So what is going on here? Why is this not the this I expect it to be?
I think the right answer is that you should not do this because as kennebec said in the comment:
If you have a hundred rectangles, you
are going to redeclare that prototype
method a hundred times.
I thought that 'this' always referred to the object against which the function was called.
The meaning of this depends how the function was called:
this usually refers to the object the function is called from at runtime, e.g. when called as ob.foo(), this in foo will refer to ob.
If a function is called in a no-object-provided way, e.g. just foo(), this refers to the global variable (the top object that contains all other global variables in your js program).
And in .call() and .apply(), the object that this refers to is supplied.
Now, if you wanted a way to point to the object for the function that your function was created in (i.e., the 2nd level this at the time of creation), then you would have to rename the deeper this to make it shine through the currently-visible one. If that's clear as mud, this should help clarify a bit:
function outside() {
// Here, 'this' refers to the object outside() is called with.
// Let's "rename" this, to make it visible to inside functions.
var that = this,
private = 42;
return {
inside: function {
// here, 'this' refers to the object inside() is called with,
// it is hiding outside's this.
// Also, 'that' refers to the object outside() was called with,
// *at the time* outside was called and inside was created.
// Notice that you can see 'private'
// (but nobody outside of 'outside()) can!
return private;
}
}
}
This pattern above is useful to create object with public methods that can access private members. See Crockford for probably better explanations.
What 'this' points to, is determined when the code is run.
Here's an easy way to figure out what 'this' should be.
If you use '.' to reference a function, 'this' will be a reference to whatever is on the left side of the '.'
(This doesn't account for .call and .apply)
var myFn = function () {
return this.name + ' called me';
};
var me = {
name : 'oatkiller',
shoutOut : myFn
};
var you = {
name : 'Matthew',
shoutOut : myFn
};
// im on the left of the dot, so this points to me
me.shoutOut(); // 'oatkiller called me'
// youre on the left of the dot, so this points to you
you.shoutOut(); // 'Matthew called me'
I think you're really close with the final example. How about using a privileged method:
function Rectangle(w,h) {
this.width = w;
this.height = h;
var that = this;
this.area = function() {
return that.width * that.height;
}
}
var rect = new Rectangle(2,3);
console.log(rect.area());
See Crockford's "Private Members in JavaScript" for more info.

Categories