I have issues calling function "Izpis" from an array. Class below:
function Kandidat(ime, priimek, stranka, stDelegatov) {
if (ime == "" || priimek == "") {
alert("Podatki niso popolni!");
return;
} else {
this.ime = ime;
this.priimek = priimek;
this.stranka = stranka;
this.id = polje.length + 1;
this.stDelegatov = stDelegatov;
}
Izpis = function() {
return "(" + this.id + ")" + this.ime + " " + this.priimek + " pripada stranki " + this.stranka + ".";
}
PosodobiIzpis = function(ime, priimek, stranka, stDelegatov) {
this.ime = ime;
this.priimek = priimek;
this.stranka = stranka;
this.stDelegatov = stDelegatov;
}
}
I tried it like this:
var a = [];
a = a.concat(Isci($("#iskalniNiz")));
for (var i = 0; i < a.length; i++) {
var temp = (Kandidat)(a[i]).Izpis();
$("br:eq(0)").after(temp + "\n");
}
and without (Kandidat) with no success. I am getting either "is undefined" or "is not a function" error.
It looks to me as if Kandidat is meant to be a constructor function. The way you've defined Izpis is a bit sketchy...
If you want to make Izpis a property of an instance you're creating (using the new keyword), you need to write this.Izpis.
If you don't prefix it with this., nor with var, it will do one of two things:
If there's a globally defined Izpis, it will overwrite this variable.
If there's no Izpis variable defined in the current context, it will create a new one inside the constructor function, which will not be accessible outside of this code block.
Another issue I see in your code, that might not initially show, is that you are using this inside the Izpis and PosodobiIzpis functions.
This will break once you call your functions other than kandidatInstance.Izpis(). E.g.: setTimeout(kandidatInstance.Izpis) will not work.
To fix this, do either:
function YourConstructor(id) {
// Method 1: store 'this' context in closure
var self = this;
this.yourMethod = function() {
return self.id;
};
// Method 2: explicitly bind 'this' context
this.yourMethod2 = function() {
return this.id;
}.bind(this);
};
// Method 3: use prototype
YourConstructor.prototype.yourMethod3 = function() {
return this.id;
};
Related
I have the following JS code, how could I insert new function without adding inside the self object?
Function select(selector){
Var self = {
Print: ()=>{},
Delete: ()=>{}
};
Return self;
}
//I want to add new function here so I can call it by using select("something").newFunc()
Is there any ways to do that? I tried something as below, but I'm wondering if there's another way to do it.
After several hours of testing, I tried to assign all the methods inside a variable prototype's method (A), and then set A's prototype back to the variable's prototype. Then I can call it using the variable.
var myScript = function(selector){
return new myScript.prototype.init(selector);
}
var init = myScript.prototype.init = function(selector){
var self = {
//codes
};
return self;
}
init.prototype = myScript.prototype;
(function(mS){
mS.prototype.newFunc = function(){
return "Coding is Fun";
}
})(myScript);
After that, I can use myScript("something").newFunc()
That's what I've tried, please share if you know another way, thanks.
Constructor functions do not require the 'self' object you designed. In your case
You return the self object from the constructor
You use arrow functions that do not change the value of this. Arrow functions are cool, but they are not interchangeable with regular functions (at least not in every case - and inside a constructor function is such a case)
Look at the two constructor functions below (Select1 is based on your code, Select2 is based on a "how to do it"):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
// adding a self object - arrow functions
function Select1(selector) {
this.selector = selector
var self = {
print: () => {
return 'Select1 print: ' + this.selector
},
delete: () => {
return 'Select1 delete: ' + this.selector
}
}
return self
}
// no self object - regular functions
function Select2(selector) {
this.selector = selector
this.print = function() {
return 'Select2 print: ' + this.selector
}
this.delete = function() {
return 'Select2 delete: ' + this.selector
}
return this
}
// instantiating the two different Objects
let select1 = new Select1('selector1')
let select2 = new Select2('selector2')
// calling the print method on both Objects
console.log(select1.print())
console.log(select2.print())
// logging both objects
console.log(select1)
console.log(select2)
// modifying the prototype of the constructor functions
// modifying Select1.self's prototype would throw an error
/*Select1.prototype.self.newFunc = () => {
return 'Select1 newFunc: ' + this.selector
}*/
Select1.prototype.newFunc = function() {
return 'Select1 newFunc: ' + this.selector
}
Select2.prototype.newFunc = function() {
return 'Select2 newFunc: ' + this.selector
}
// logging the new function
// logging select1.newFunc() would throw an error, as you return 'self', that's not modified
// console.log(select1.newFunc())
console.log(select2.newFunc())
// logging the modified object
console.log(select1)
console.log(select2)
BUT
You should use correct indentation - code is much more readable that way
You should follow naming and casing conventions, so others can quickly see what is what in your code (constructor functions begin with a capital letter, but other reserved words do not (so casing is important too)
USAGE
And if you want to use it like myScript('selector').myFunc(), then you need to wrap it in another function (like you did in your second code sample):
function Select2(selector) {
this.selector = selector
this.print = function() {
return 'Select2 print: ' + this.selector
}
this.delete = function() {
return 'Select2 delete: ' + this.selector
}
return this
}
function myFunc(selector) {
return new Select2(selector)
}
console.log(myFunc('s1').print())
console.log(myFunc('s2').print())
If you want to be able to set the selector, then you need a set() function:
function Select2(selector) {
this.selector = selector
this.print = function() {
return 'Select2 print: ' + this.selector
}
this.delete = function() {
return 'Select2 delete: ' + this.selector
}
// this.setSelector is the set() function
this.setSelector = function(s) {
this.selector = s
}
return this
}
function myFunc(selector) {
return new Select2(selector)
}
// instantiating Select2
const selector2 = myFunc('s1')
console.log(selector2.print()) // expected: s1
// setting the 'selector' of the instantiated
// Select2 Object to a new value
selector2.setSelector('s2')
console.log(selector2.print()) // expected: s2
I am having trouble writing an object constructor in Javascript. When I call a function on one of my instantiated objects, it always returns the value of the instantiated object. The flow is like this:
blue = tool('blue');
blue.jDom(); // returns '[<div id="blue" class="tool">...</div>]'
red = tool('red');
red.jDom(); // returns '[<div id="red" class="tool">...</div>]'
blue.jDom(); // returns '[<div id="red" class="tool">...</div>]'
I believe this is due to the private variables I included in the prototype declaration. If I move the prototype declaration into the constructor, everything works fine, but this is simply masking the fact that it seems like my objects are affecting the properties of the prototype, rather than themselves, by creating a new prototype for each object. Here is my related code:
function beget(oPrototype) {
function oFunc() {};
oFunc.prototype = oPrototype;
return new oFunc()
};
var tool = (function (){
var protoTool = function(){
var oTool = {},
that = this,
_bVisible = true,
_oParentPane = 'body',
_aoComponents,
_sName = 'tool',
_sSelector = '#' + _sName,
_jDomElement;
// this is the private tab object, needs to be refactored
// descend from a single prototype
function _tab() {
var oTab = {},
_sHtml = '<li>' + _sName + '</li>',
_jDomElement = $(_sHtml);
function jDom() {
return _jDomElement;
}
oTab.jDom = jDom;
return beget(oTab);
};
// this builds the jDom element
function _jBuild() {
var sHtml = '<div id="' + _sName + '" class="tool"></div>';
_jDomElement = $(sHtml)
return _jDomElement;
};
// this returns the jQuery dom object
function jDom() {
if (typeof _jDomElement === 'undefined') {
_jBuild();
}
return _jDomElement;
};
function configure (oO){
if (typeof oO !== 'undefined') {
if (typeof oO === 'string') {
var name = oO;
oO = Object();
oO.sName = name;
}
_bVisible = oO.bVisible || _bVisible,
_oParentPane = oO.oParentPane || _oParentPane,
_aoComponents = oO.aoComponents || _aoComponents,
_sName = oO.sName || _sName,
_sSelector = '#' + _sName,
_jDomElement = undefined;
_oTab = _tab();
_oTab.jDom()
.appendTo(jDom())
.draggable({
revert: 'invalid',
containment: '#main',
distance: 10,
});
}
};
oTool.tMove = tMove;
oTool.bVisible = bVisible;
oTool.uOption = uOption;
oTool.jDom = jDom;
oTool.configure = configure;
return oTool;
}();
var tool = function (oO) {
that = beget(protoTool);
that.configure(oO);
that.configure = undefined;
return that;
};
return tool;
})();
First : inside the inner tool var definition, by 'that = beget(protoTool);' you must mean 'var that = beget(protoTool);'
What's going on in your code ? :
The tool definition gets evaluated in order to give tool a value. During this evaluation, a closure is made around protool.
But this closure is made only once, during this evaluation : all later calls to protool (made by a call to 'that', which has protools as prototype), will change the values of this first and only closure.
That is why you see this behaviour : the latest seen object will gets all attention since it updated the closure's values.
The solution is to have the right closure mades within the 'tool' inner var function definition.
But if i may, i would suggest to altogether go to a classic javascript class definition(s), using afterwise the new operator, which is, i believe, much easier to code/understand/debug.
Another rq : beget === Object.create in the latest javascript specifications (1.8.6)
My question is... in CallMeLaterTestObj function in the TestObj the "this" is the window object and not TestObj. How can I restructure this so that within the CallMeLater function I don't have to wrap the call function() { v.CallMeLaterTestObj(); } in a closure or using the bind function since it has limited support to newer browsers. Two objectives:
Keeping "this" in function calls within the object
Maintaining a separate value for "value" for each separate object so they don't share the same value.
// Emulating public api, private methods, private variables, public fields.
// New portion of question
Re-written to include binding function and prototypical notation. How do you move the Binding function into a base object that all new objects would get?
This is as close as I can come to getting this to use the best of both worlds. I have no idea what the pitfalls of this approach are though
var BaseObject = function ()
{
_getBinding = function (method)
{
var _self = this;
return function ()
{
_self[method].apply(_self, arguments);
};
};
return {
CallInline: _getBinding
}
}();
var TestObj = function (value)
{
$.extend(this, BaseObject);
// public var
this._value = value;
};
TestObj.prototype = function()
{
var privateVar = false;
// these are private
_giveMe = function () {
return this._value;
},
_callMeLaterTestObj = function () {
console.log('I am ' + this.constructor.name + ' my value is ' + this._value);
};
// public API
return {
GiveMe : _giveMe,
CallMeLaterTestObj : _callMeLaterTestObj
}
}();
function CallMeLater(v, i)
{
setTimeout(v.CallInline('CallMeLaterTestObj'), 10);
}
var V1 = new TestObj(1);
var V2 = new TestObj(2);
var V3 = new TestObj(3);
console.log('V1= ' + V1.GiveMe());
console.log('V2= ' + V2.GiveMe());
console.log('V3= ' + V3.GiveMe());
console.log('---');
V1.CallMeLaterTestObj();
console.log('---');
I think what you're looking for is this:
function TestObj(value) {
var _value = value;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
return this;
};
function callMeLater(v, i) {
setTimeout(function() {
v.callMeLaterTestObj();
}, 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);
To access constructor.name, you need to declare the function with function name() syntax, rather than var name = function() syntax.
To keep private variables and expose a public api, expose the public variables as properties of this in the function.
Be sure to return this from the constructor function to make it work.
It's also good practice to follow the naming convention of CamelCase for class names (of which TestObj is one) and lowerCamelCase for variables / methods / objects / etc. Helps keep things clear as to which variables are instances, and which are Classes.
Test and see the console output expected here.
note
Regarding wrapping v.callMeLaterTestObj() in a closure for the setTimeout, this technique is completely cross-browser compatible. You won't have any issues.
The bind method is newer, although there are many libraries that will shim that for you in older browsers. My personal favourite is underscore.
note 2
You can't call a method on an object in setTimeout without wrapping it in a closure somewhere, however if you want to you can abstract the closure in the Class without using a generic bind function (as provided by Underscore or jQuery and others) you can 'roll your own' in the Class like this:
function TestObj(value) {
var _value = value;
var _self = this;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
this.getBinding = function(method) {
var _self = this;
return function() {
_self[method].apply(_self, arguments);
};
};
return this;
};
function callMeLater(v, i) {
setTimeout(v.getBinding('callMeLaterTestObj'), 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);
explanation:
You need to use some sort of binding because, when you pass the method to setTimeout, you pass it by reference. So all setTimeout sees is a function - not the object it was on, which is why you lose the context of this.
Since setTimeout will therefore execute the function in the default scope - i.e. the browser window - you need a way to get this back, by reference, either through an inline anonymous function, or by returning a closure that uses the apply method to 'reset' this.
note 3
If you wanted to have your own bind method, and not include a library that provides it for you or include it in every class then you can use this one from Underscore, which defers to the native method in newer browsers:
function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
Then use it like this:
function callMeLater(v, i) {
setTimeout(bind(v.callMeLaterTestObj, v), 10);
}
This will work well in all browsers.
No, you can't. That's just the way to do it. Btw, you can easily shim the bind method so that it is available in older browsers, too.
An alternative would be to move the closure into the prototype method, if you know that you always will need to bind the actual function:
TestObj.prototype.getCallMeLaterTestObj = function () {
var that = this;
return function() {
console.log('I am ' + that.constructor.name + ' my value is ' + that._value);
};
};
setTimeout(v.getCallMeLaterTestObj(), 10);
Btw, your prototype has no constructor property so the log will not work as expected.
Your only chance is to avoid the this keyword entirely:
TestObj = function() {
var privateVar = false; // these are private static
function TestObj(value) {
function giveMe() {
return value;
}
function callMeLaterTestObj() {
console.log('I am TestObj my value is ' + giveMe());
}
this._value = value;
this.giveMe = giveMe;
this.callMeLaterTestObj = callMeLaterTestObj;
/* you could do this as well:
return {
_value: value,
giveMe: giveMe,
callMeLaterTestObj: callMeLaterTestObj
}; */
}
return TestObj;
})();
var v = new TestObj;
setTimeout(v.callMeLater, 10);
But this is not very memory-efficient, as it does not use prototypical inheritance at all.
I'm using objects to namespace my JavaScript code. These objects usually contain functions that are called mapping the this-pointer to the object itself using apply. However, I find it inconvenient to use the this-pointer everytime I want to access other functions or properties of the object, especially because in lots of cases I use the new-operator to use function-objects the way you would use classes. I would prefer writing new Line() instead if new this.Line().
It would be great if you could add local variables to a function the way php does it with extract (pseudocode following, it's a little more complicated)
var sample_object = {
"some_function": function() {}
}
test() {
extract(sample_object);
some_function(); // imported from sample_object
}
Is that even possible?
I'm pretty sure eval is your only answer; but you need to be aware that if there's any input outside of your control involved, it isn't safe
function dynamicArgs (varName, varValue) {
eval("var " + varName + "=" + JSON.encode(varValue) );
alert(a);
}
dynamicArgs("a", "value");
You can see the problem with this. How is your function supposed to call the dynamic variable if it doesn't know its name? I hardcoded it to the a variable since I pass it in when calling it, but that's not a good solution. The only solution would be another eval. You really should think about what you need to do and whether this is useful. But it's doable.
Here it is in action: http://jsfiddle.net/mendesjuan/GG3Wu/
function dynamicArgs (varName, varValue) {
eval('var ' + varName + "='" + varValue + "';");
alert(eval(varName));
}
dynamicArgs("f", "Here I am");
Now here's an example like what you're doing, creating a variable from this.MyConstructor
http://jsfiddle.net/mendesjuan/AK3WD/
var ns = {
MyConstructor: function(val) {
this.prop = val;
},
runConstructor: function(val) {
var Ctor = "MyConstructor";
eval('var ' + Ctor + ' = this.' + Ctor);
return new MyConstructor(val);
}
}
alert( ns.runConstructor("Hello").prop );
And here's an example if you wanted to import all the values from an object into the scope;
http://jsfiddle.net/mendesjuan/AK3WD/1/
var ns = {
MyConstructor: function(val) {
this.val= val;
},
anotherProperty: 5,
runConstructor: function(val) {
// Bring all the variables from this into this scope
for (var prop in this) {
eval('var ' + prop + ' = this.' + prop);
}
alert('Testing var anotherProperty: ' + anotherProperty);
var obj = new MyConstructor(val);
alert('Created MyConstructor: its prop is ' + obj.val)
}
}
ns.runConstructor("Hello");
There is controversial with, which has some great applications, but is marginally slow and prone to errors. It throws an error in the strict mode (which you should always opt into) and is going to be deprecated.
var sampleObject = {
someFunction: function() {},
b: 10
}
with (sampleObject) {
typeof someFunction // "function"
var a = 42
var b = 20
}
sampleObject.a // undefined
sampleObject.b // 20
Note, that new variables defined in a with-block won't be added to the object. Nevertheless, if the object already had an eponymous property in it, this property would be modified (thanks, #Rocket).
Just for fun, here's an implementation of extract using eval (which is even more evil than with). You can do unspeakable things with it, for example if your object has properties like sampleObject['x; while (true) { alert("Hi!") }'].
This is how I did it:
function smObject ( object) {
return function () {
function getter(prop) {
return function() {
return this[prop];
}
}
function setter(prop) {
return function(data) {
this[prop]=data;
}
}
for (var o = 0; o < object.length; o++) {
this[object[o]] = {};
this['get' + object[o]] = getter(object[o]);
this['set' + object[o]] = setter(object[o]);
}
}
}
now you can instantiate a function like this:
var fields = ['Name', 'Id', 'Other', '....' ]
var MyFunction = smObject( fields );
var myObject = new MyFunction();
// getter/setters
myObject.setId(5);
myObject.getId(); // will return 5
Regards,
Emanouil
I have my object defined as follows:
function KoolTabs() {
this.targetName = "";
this.activeNode = 1;
this.init = function()
{
this.targetName = arguments[0];
this.activeNode = (arguments[1] || 1);
this.setEle( this.activeNode );
this.findNodes();
}
this.findNodes = function()
{
for (i=0;i<document.links.length;i++) {
myEle = document.links[i];
x = document.links[i].href;
if (x.indexOf("#" + this.targetName) >= 0) {
myEle.addEventListener('click', this.onClick, false);
}
}
}
this.onClick = function()
{
alert('Hello ' + this.activeNode);
}
};
I am calling it like:
<script>
var StockTabs = new KoolTabs;
StockTabs.init('tabsStock', 1);
</script>
Now when i click on the object which has the method bing it says "Hello undefined"
how can i get the value of parent object activeNode?
Because in that handler this refers to the clicked element, you can maintain a reference to the origin KoolTabs object though, like this:
function KoolTabs() {
var self = this;
Then in your handler, use that reference, like this:
this.onClick = function()
{
alert('Hello ' + self.activeNode);
}
You can test it out here. (I commented out the setEle() call, since that code wasn't included.)
your onClick method is called in a different context when used as an event handler in this method- this no longer refers to your KoolTabs instance.
the easy work around is to create a closure with a self-referencing variable with a different name.
function KoolTabs() {
var self = this;
this.targetName = "";
this.activeNode = 1;
this.init = function()
{
this.targetName = arguments[0];
this.activeNode = (arguments[1] || 1);
this.setEle( this.activeNode );
this.findNodes();
}
this.findNodes = function()
{
for (i=0;i<document.links.length;i++) {
myEle = document.links[i];
x = document.links[i].href;
if (x.indexOf("#" + this.targetName) >= 0) {
myEle.addEventListener('click', this.onClick, false);
}
}
}
this.onClick = function()
{
// "this" refers to a different object now. use the "self"
// variable to reference the KoolTabs instance.
alert('Hello ' + self.activeNode);
}
};
if you want to get fancy, you can look at jQuery's bind method to see how it generates a function call with the proper scope applied. it would be something like
$(myEle).click( this.onClick.bind(this) );
and when onClick fires, this would point to what you expect it to. you would not need to define the self reference.