JS: nested function v prototype - javascript

I have an object in Javascript and want to process the data passed into the constructor using a function that could later be called externally with more data. Naturally I don't want to duplicate the code (once in the constructor, once in a function), so how should I best set this up?
I could use a nested function, but I'm told this is inefficient:
function MyOb(data) {
this.myData = {};
function addData(newData) {
//Add newData to myData
}
addData(data);
}
But if I use a prototype I get a "can't find variable addData" error on line 3:
function MyOb(data) {
this.myData = {};
addData(data);
}
MyOb.prototype.addData = function(newData) {
//Add newData to myData
}
So am I forced to either use a nested function or repeat myself, or is there a way of making this work using prototype?

Change
function MyOb(data) {
var myData;
addData(data);
}
to
function MyOb(data) {
this.myData = {}; // or another initialization
this.addData(data);
}
You need the explicit this in JavaScript objects.
Note also that using var myData makes it private : you won't be able to use this variable from functions defined outside the constructor, including the addData function. That's why you probably need this.myData instead.

Using the prototype you need to create a new object:
var abc = new MyOb(data);
then you can access the function using the this:
function MyOb(data) {
var _myData; // local variable in this scope (addData won't have access)
this.myData = {}; // public variable
this.addData(data);
}
If you don't use the newto build your object, then the thiswill be the window, and your code won't work

You should just make the nested function publically available as a property on your object:
function MyOb(data) {
var myData;
function addData(newData) {
//Add newData to myData
}
addData(data);
this.addData = addData;
}
Your current code with the prototype suffers from the problem that you're trying to get the function like a variable, while it's a (inherited) property of your instance (referenced by this). However, changing it to
this.addData(data);
would lead to the error can't find variable myData in the prototype function - it's a variable that is local to the constructor. You would have to make that a instance property as well to use the prototype. See also Javascript: Do I need to put this.var for every variable in an object?.

Related

How to access javascript object Arrays inside prototype function

Hello I'm having a problem that haven't searched before
I'm trying to recode my javascript used for accessing google api's so that I can create objects to access them in further projects .
Let me Explain the Code because I'm not posting the original code here below code is the just like an example of my code
I'm a having constructor function and it has arrays declared with 'this' keyword. and Then I have an prototype of the constructor function and inside that prototype I had a nameless function created to access jquery requested output from a server.But I'm unable to access those array objects
function cons(){
this.objectarray = [];
}
cons.prototype.profun = function(){
this.objectarray[0] = 'working';
alert(this.objectarray[0]);//Access is possible
$.get('requesting url',{'parameters'},function(data){
alert(this.objectarray[0]);//Access is not possible
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
when I try to access the object inside that jquery function I'm getting this error from browser console
TypeError: this.YouTubeTitle is undefined
You have to cache the this object so that when you use the this keyword in your callback, it refers to the correct object:
function cons(){
this.objectarray = [];
}
cons.prototype.profun = function(){
// this is volatile in JavaScript. It's meaning changes depending
// on the invocation context of the code that contains it. Here,
// this will refer to your "cons" object instance.
var self = this;
this.objectarray[0] = 'working';
alert(this.objectarray[0]);
$.get('requesting url','parameters',function(data){
// But here, "this" will be bound to the AJAX object
alert(self.objectarray[0]); // <-- Use cached this object
});
};
//*************************
var c = new cons();
c.profun();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Inside the GET-Callback there is a local this which overrides your Prototype-Function's this. Store the outer this in a named variable and call that inside the callback and you will be fine.
let outerThis = this;
somethingWithCallback(function(){
alert(outerThis);
})
I've found solution for this from one of the comments
the below code is the solution
function cons(){
this.objectarray = [];
}
cons.prototype.profun = function(){
this.objectarray[0] = 'working';
alert(this.objectarray[0]);
$.get('requesting url',{'parameters'},function(data){
alert(this.objectarray[0]);
}.bind(this));//by binding 'this' we can access the 'objectarray'
}
Thanks for the solution #Redu from comments
You can wrap your anonymous function with $.proxy to persist the outer this context.
function cons() {
this.objectarray = [];
}
cons.prototype.profun = function() {
this.objectarray[0] = 'working';
alert(this.objectarray[0]);
$.get('requesting url', {
'parameters'
}, $.proxy(function(data) {
alert(this.objectarray[0]);
}, this));
}

Closures Cannot access a function

I am trying to understand closures. In the code below, I create an instance of the constructor function Ninja and I call the instance kawazaki. I expected to be able to access the methods of Ninja. However, I am getting a TypeError: Object #<Ninja> has no method 'feints' instead.
The output I expected was 1.
Here is my code:
function Ninja() {
var feints = 0;
function getFeints() {
return feints;
}
function feints() {
feints++;
}
}
var kawazaki = new Ninja();
kawazaki.feints();
console.log(kawazaki.getFeints());
Try this instead:
var kawazaki = new Ninja;
kawazaki.feints();
alert(kawazaki.getFeints());
function Ninja() {
var feints = 0;
this.getFeints = function () {
return feints;
};
this.feints = function () {
feints++;
};
}
You need to assing public properties to this within the constructor function.
The scope of the functions getFeints and feints is limited to the function Nija. As you can not access to variables declared in a function, you can not access to those functions.
To be able to execute kawazaki.feints(), you have to "attach" the function to the Ninja function, as an object (which a function also is)
You will find in these resources several ways to achieve that, and also some deeper explanations:
How do JavaScript closures work?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
Closure is a very simple yet largely misunderstood topic.
function Ninja() {
var feints = 0;
function getFeints() {
return feints;
}
function feintsInc() {
feints++;
}
}
You have defined the closure alright but please note that a closure is not actually a method of the object. In order to get your desired output you need to call the closures just before closing the object.
feintsInc();
getFeints();
If,however, you wish to do it as
kawazaki.feintsInc();
you need to use this keywords in your function to get the functions assigned to the object.
Note,make sure your functions and variable names don't overlap.

JS variable scope: pushing into an array in one function and accessing it another function

http://jsfiddle.net/ujapned5/
I'm trying to make an "initializer" function that will be used to define CSS id and class names.
function init() {
//our empty array for pushing
var DivNamingPushArray = [];
//object where we define our properties that will be used later
var namingScheme = {
"parentId": {
"firstChild": "blah",
"secondChild": "blahblah",
"thirdChild": "blahblahblah"
}
}
//loop through the namingScheme object and push into array
for (propOne in namingScheme) {
DivNamingPushArray.push(propOne);
for (propTwo in namingScheme[propOne]) {
DivNamingPushArray.push(namingScheme[propOne][propTwo])
}
}
}
function execute() {
//call the "init" function
init();
//this cannot be called
console.log(DivNamingPushArray);
//however, why can this be successfully called?
console.log(propOne);
}
execute();
I would really prefer to keep these functions separate, instead of including execute inside init. There are other functions that will need to call the DivNamingPushArray variable later on.
I am looking through the MDN documentation on variable scope but not finding a simple solution...
I'd suggest you use a third function to separate your logic
As for the propOne, you can see my comment in your question, just put var in front of it.
Working example here
execute();
function init(app) {
app.DivNamingPushArray = getNamingArray();
}
function execute() {
var app = {};
//call the "init" function
init(app);
console.log(app.DivNamingPushArray);
}
function getNamingArray() {
//our empty array for pushing
var DivNamingPushArray = [];
//object where we define our properties that will be used later
var namingScheme = {
"parentId": {
"firstChild": "blah",
"secondChild": "blahblah",
"thirdChild": "blahblahblah"
}
}
//loop through the namingScheme object and push into array
for (var propOne in namingScheme) {
DivNamingPushArray.push(propOne);
for (var propTwo in namingScheme[propOne]) {
DivNamingPushArray.push(namingScheme[propOne][propTwo])
}
}
return DivNamingPushArray;
}
I suggest to use some js pattern like module to separate it:
http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
and the using something like observer to let function comunicate.
This is not a simple implementing solution, but you can have fun with it!
If you want DivNamingPushArray accessible within the scope of execute(), take its declaration one level upper, before init() declaration :
//Declare your array outside of your init function
var DivNamingPushArray = [];
function init() {
//...
For propOne, see Amit Joki's answer.
When you declare a variable without the keyword var, it becomes global. Add var before you declare the variables in for...in loop.
for (var propOne in namingScheme) {
DivNamingPushArray.push(propOne);
for (var propTwo in namingScheme[propOne]) {
DivNamingPushArray.push(namingScheme[propOne][propTwo])
}
}
When a variable becomes global, or part of window, it can be accessed anywhere. So, always use var to keep the variables in scope and thereby avoiding the pollution of global scope.
After you've called init, propOne and propTwo have become global variables and therefore can be accessed anywhere. As to DivNamingPushArray, declare it one-level higher, so it will be visible to other functions or try to use module pattern.
Javascript variable scoping works like this:
//this will not be changed in "init" function.
DivNamingPushArray = [];
//this will be changed because you don't localize your variable in init function
propone = 'value';
function init() {
//this "var" declaration localizes the variable.
//You can do anything you want with it and
//the global DivNamingPushArray wont change.
//The only way to use the global variable now is through
//the global object. (window.DivNamingPushArray for browsers)
var DivNamingPushArray = [];
// if you would have used "for (var propOne in namingScheme)",
// the variable would have been local
for (propOne in namingScheme) {
// ...
}
}

How come an array inside an instanciated object returns undefined?

function test() {
var test_array = [];
}
var arrayList = new Array();
arrayList[0] = new test();
arrayList[0].test_array[0] = "test";
(try it out)
I'm trying to create an array, initialize an object as a member of that array, and then assign a text value to an array inside that object. However the array inside the object gives
TypeError: arrayList[0].test_array is undefined
when I try to assign a string to the inner array. I'm still pretty new to javascript so any tips to best practice in this case would be greatly appreciated.
Statement var test_array = []; creates a local variable which will not be visible outside the scope it is defined within. What you need here is the variable defined as the property of object instance. Use this reference inside your test function:
function test() {
this.test_array = [];
}
For more information on scopes in JavaScript read the documentation.
var declarations within a constructor don't actually modify the instance. They're just locally-scoped within the constructor function itself.
To define a property of the instance, you have to modify this:
function test() {
this.test_array = [];
}
Updated Fiddle: http://jsfiddle.net/5t62z/3/
Your function was not returning anything. If you notice my update, I now will return an object with the test_array property.
function test() {
return {
test_array: []
};
}

Does JavaScript have a variable for items declared in the function's scope? [duplicate]

This question already has answers here:
How can I access local scope dynamically in javascript?
(4 answers)
Closed 9 years ago.
Does JavaScript have a variable for items declared in the function's scope? I would like to access items declared inside a function using an associative array.
For example I can do the following with items at the global scope
var globalVar = "hi";
var myFunction = function () {
alert(window["globalVar"]);
};
But I would like to do a similar thing with variables declared inside a function
var myFunction = function () {
var funcVar = "hi";
alert(func["funcVar"]);
};
I realise doing such a thing isn't necessarily a good thing and I am doing the below instead, but I am still interested if JavaScript has such a variable.
var myFunction = function () {
var func = {funcVar : "hi" };
alert(func["funcVar"]);
};
This question has been asked and answered many times. No, in JavaScript there is no local object containing local variables as properties (in the way that for instance, in browser environments the window object contains global variables as properties).
Depending on what you are trying to accomplish, there are probably many alternative ways to attack it, including the one you are using now.
Duplicate of Javascript: Get access to local variable or variable in closure by its name, How can I access local scope dynamically in javascript?, Javascript local variable declare.
Perhaps you could assign properties to the function object itself, and reference those?
var myFunction = function() {
myFunction.funcVar = 'hi';
alert(myFunction['funcVar']);
};
It is not exactly the answer to your question, but it's the best way I can think of to access local variables as properties of an object. Note that in this method these variables will be visible outside the function in the same manner (that is, looking up the properties of the function).
If you really needed those properties to be hidden, you could hide them within a closure, like so:
var myFunction = function() {
(function hidden() {
hidden.funcVar = 'hi';
alert(hidden['funcVar']);
})();
};
Functions are just special objects that can be invoked. You can set properties of a function, and get them later.
var a = function () {
alert(a.testingVar);
};
a.testingVar = "asdf";
a();
DEMO: http://jsfiddle.net/gEM7W/
Although I don't see a reason/need to do this. You could always use a closure to keep local variables specific to a function. For example:
var a = (function () {
var obj = {
testingVar: "asdf"
};
return function () {
alert(obj.testingVar);
};
})();
a();
DEMO: http://jsfiddle.net/gEM7W/1/
You don't really have associative arrays. You have indexed arrays and you have objects.
In the future, there will be an iterator which will happily traverse both, without any side-effects. At that point, perhaps people will forget the difference.
However, the properties still wouldn't be order-based:
$arr = array(0, 1, "name"=>"Bob", 3);
In another language might get you an array where the keys are: 0, 1, "name", 3
In JS, you'd get 0, 1, 2, "name" (or "name", 0, 1, 2).
So stick with indexed arrays and objects with properties.
That said, you've got multiple options.
var myFunc = function () {
var private_data = {
name : "Bob",
age : 32
};
return {
getName : function () { return private_data.name; /* or private_data["name"] if that's really what your heart longs for */ },
get : function (key) { return private_data[key] || null; },
set : function (key, val) { private_data[key] = val; }
};
};
Now everything is private, and you can access them by property-name, using dot or bracket notation.
If they can be public, and the function is always going to be called the same thing (ie: not a constructor making an instance) then you can attach yourself to the actual function:
var myFunc = function () {
myFunc.name = "Bob";
myFunc["age"] = 32;
return {
get : function (key) { return (myFunc.hasOwnProperty(key)) ? myFunc[key] : null; }
};
};
Downside (or upside) is that myFunc is the public name. As such, these properties are publicly accessible.
Going the first route, you don't even need to declare a variable. You can just use the object you pass into a function.
var myFunc = function (dataObj) {
return {
getName : function () { return dataObj.name; },
setAge : function (val) { dataObj["age"] = val; }
};
};
var bob = myFunc({ name : "Bob" });
bob.setAge(32);
Now everything's private and I didn't even have to declare anything.
Closure keeps the object in play as long as there's a publicly accessible function that's returned, which still has access to that particular instance of the function call.
Once you figure out closures, this becomes a non-issue.

Categories