Define function for property of javascript class - javascript

I have this Javascript class and want to add some kind of function (like prototype)
to properties of this class.
function theUploader(virtualField)
{
var self = this;
//self.v = virtualField;
self.v = (function(){return self.v; this.clear = function(){self.v = '';}})()
self.v.prototype = function clear() {
self.v = '';
}
}
i tried those lines.
i couldn`t find out the right way to define such a thing.i want to call it like this
var temp = new theUploader('smart');
temp.v.clear();
someone guid me with jsaon.but still working on it

The problem(s) with this line:
self.v = (function(){return self.v; this.clear = function(){self.v = '';}})()
...would be more obvious if you split it out over several lines:
self.v = (function(){
return self.v;
this.clear = function(){
self.v = '';
}
})()
It's an immediately invoked function expression which returns on its first line, so it never gets to the this.clear = ... line. The value returned, self.v, will be undefined at that point, which means the self.v property you assign that value to will also be undefined, which means then on this line:
self.v.prototype = function clear() {
...you'll get an error TypeError: Cannot set property 'prototype' of undefined.
It's a bit hard to tell exactly what you're trying to do given the confusion in your theUploader() function, but given that you said you want to be able to do this:
var temp = new theUploader('smart');
temp.v.clear();
Then you need to create a .v property that is itself an object that has a .clear() method, so:
function theUploader(virtualField)
{
var self = this;
self.v = {}; // create a v property that is an object
self.v.clear = function(){self.v = '';}; // add a method to v
}
...would do it. Or you could define the clear function directly in the object literal:
self.v = {
clear : function(){self.v = '';}
};
(Either way it doesn't really make sense to me that calling self.v.clear() would actually overwrite the .v property with an empty string, but if that's what you want this is how you could do it.)

self.v.prototype = function clear() {
self.v = '';
}
Should be
self.v.clear = function() {
self.v = '';
}

Related

I initaialized the object method below, and it mysteriously cleared my object

I have this code snippet I made:
var SCP_Object = {
scp_function:function(){
var proxy_this={};
proxy_this.a = 5;
proxy_this.b = 7;
return proxy_this;
},
get scp_function(){
this.scp_function.random_string = "Hello, World!";
}
}
var new_SCP = new SCP_Object.scp_function();
When I ran it, I got RangeError: Maximum Call Stack Size Exceeded., and more curiously, new_SCP was undefined, and more curious still, SCP_Object was now an empty object {}.
What exactly happened here? I guess it enetered into a forever loop of sorts, but why did it clear the object?
Okay, so there are a few different things going on here! I'll work through each. First off, the new keyword/operator is reserved for JavaScript classes and functions. For this same reason, the below code will throw an error:
let A = {b:2};
new A();
// -> !!! Uncaught TypeError: A is not a constructor
I presume here that you would like to set up SCP_Object as a class and not just an ordinary object, but I'll deal with this as an object first and then move onto how to work with it as a class.
Getters and setters are perfectly legal to use on regular JavaScript objects, but there are three issues with yours:
new_SCP will not equal anything because your getter function does casually return anything.
Your getter function shares the same name as one of your scp_function property, which is illegal. Properties cannot share the same name as getter/setter functions.
You are calling the getter with parentheses as if it is a function (()), but it is not. You only need to call the property name of the getter and it will return whichever value you set it to return.
Let's resolve these issues:
var SCP_Object = {
_scp_function: function() {
var proxy_this = {};
proxy_this.a = 5;
proxy_this.b = 7;
return proxy_this;
},
get scp_function() {
var proxy_this = this._scp_function()
proxy_this.random_string = "Hello, World!";
return proxy_this;
}
}
var new_SCP = SCP_Object.scp_function;
console.log(new_SCP);
If you would like to achieve this with a class so you can use the new operator, we can do so like this:
class SCP_Object {
_scp_function() {
var proxy_this = {};
proxy_this.a = 5;
proxy_this.b = 7;
return proxy_this;
}
get scp_function() {
var proxy = this._scp_function()
for (var [key, value] of Object.entries(proxy)) {
this[key] = value;
}
this.random_string = "Hello, World!";
}
}
var new_SCP = new SCP_Object();
new_SCP.scp_function;
console.log(new_SCP);
If you'd like to set all those object properties without having to use your proxy functions at all, you can do so within the class itself with ease, whether using a function-style class or a newer ES6-style class:
function SCP_Object_1() {
this.a = 5;
this.b = 7;
this.random_string = "Hello, World!";
}
class SCP_Object_2 {
constructor() {
this.a = 5;
this.b = 7;
this.random_string = "Hello, World!";
}
}
var new_SCP_1 = new SCP_Object_1();
var new_SCP_2 = new SCP_Object_1();
console.log(new_SCP_1, new_SCP_2);

Copy object functions and properties in new object by value not by reference - javascript

I want to copy the functions and properties of an object into new object. The old object should not effect by changing made in new Object.
Here is the object definition:
var Call = function() {
this.number="123";
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
I can access function1 using callobj.function1().
What I have tried to copy it:
Javascript:
var newcallobj = Object.assign({}, callobj);
In this case, i am not able to access function1 but i can access number property directly.
JQUERY:
var newObj = jQuery.extend(true, {}, callobj); OR
var newObj = jQuery.extend({}, callobj);
In this case, i am able to access function1 and property but when i change number like that newObj.number="222". It also change the value of original object.
I know that there is couple of other posts. But all is not working for me. Please let me know if i am doing any thing wrong?
AFTER #gurvinder372 answer(I am updating question):
After #gurvinder372 answer. It is working for first level of property but if it has another object like i show below and i change the value of property of another object. Then it is effecting on original object also.
var ABC = function(){
this.number = "333";
}
var Call = function() {
this.number="123";
this.anotherobj = new ABC();
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
var newcallobj = Object.create(callobj);
newcallobj.anotherobj.number= "123";
console.log(newcallobj.anotherobj.number);
console.log(callobj.anotherobj.number);
Output of both is 123. #gurvinder372. can you check th above code ?
Object.assign only copies the enumerable properties of an object.
Use Object.create instead of Object.assign
var newcallobj = Object.create(callobj);
var Call = function() {
this.number="123";
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
var newcallobj = Object.create(callobj);
console.log(newcallobj.function1());
Ok. By the help of #gurvinder372. The following solution is working for me.
var ABC = function(){
this.number = "333";
}
var Call = function() {
this.number="123";
this.anotherobj = new ABC();
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
var newcallobj = Object.create(callobj);
newcallobj.anotherobj = Object.create(callobj.anotherobj);
newcallobj.anotherobj.number= "123";
console.log(newcallobj.anotherobj.number);
console.log(callobj.anotherobj.number);
Please let me know if there is any better solution other than this?

Override JavaScript (window) Function

I'd like to override a function which is being made by a javascript plugin. I know how to override regular window functions, but this is different. I'm not sure how to name it, but the structure of that function is like:
window.something.function
I have no idea how to override that. I have tried the following:
var originalFunction = window.something.function;
window.something.function = function(parameter) {
alert('called');
return originalFunction(parameter);
}
But it's not working.
Does someone know a solution?
Edit:
As I have been told my question is unclear, I have edited it again using the actual names of the plug-in.
The plugin is meant to be used as:
var myColor = new jscolor(target, options)
When this is being used, there is a function "inside" the object "jscolor" which is being called when setting the value of target element. I want to override that function to add an extra functionality without changing the original js file.
Code:
if (!window.jscolor) { window.jscolor = (function () {
var jsc = {
.....
jscolor : function (targetElement, options) {
....
//Function I want to change:
this.exportColor = function (flags) {
if (!(flags & jsc.leaveValue) && this.valueElement) {
var value = this.toString();
if (this.uppercase) { value = value.toUpperCase(); }
if (this.hash) { value = '#' + value; }
if (jsc.isElementType(this.valueElement, 'input')) {
this.valueElement.value = value;
} else {
this.valueElement.innerHTML = value;
}
}
}
}
};
My attempts so far:
var origJsColor = jscolor.exportColor;
jscolor.exportColor = function(flags) {
console.log('called');
return origJsColor(flags);
}
and the window attempt above.
The jscolor code you've shown creates an object with its own copy of exportColor (one is created for each object). So to replace it, you have to replace it on each instance as the instance is created.
You can do that as a one-off in much the way you showed, just working with the instance rather than the plugin function, and using Function#call to call it with the right this:
// Get the instance
var c = new jscolor(target, options)
// Update it
var origExportColor = c.exportColor;
c.exportColor = function(flags) {
console.log('called');
return origExportColor.call(c, flags); // Note the changes on this line
};
Or instead of
return origExportColor.call(c, flags);
you might use
return origExportColor.apply(c, arguments);
...if there's any chance of the function being called with anything other than exactly one argument. (arguments is a magic pseudo-array containing the arguments used to call the function.)
If you want to do that for all instance you might create, you can put a facade in front of jscolor to do that to each instance:
var realJscolor = jscolor;
jscolor = function() {
// Call the real function, passing along all the arguments we
// get automatically (`arguments` is a magic pseudo-array)
var retVal = realJscolor.apply(this, arguments);
// If it returned a non-`null` object, we want to use that instead
// of `this`; if not, we keep using `this`
if (!retVal || typeof retVal !== "object") {
retVal = this;
}
// Slip in our version of exportColor
var origExportColor = retVal.exportColor;
retVal.exportColor = function(flags) {
console.log('called');
// (Maybe use `apply` here instead)
return origExportColor.call(retVal, flags);
};
// Return the result, in case the real function overrode `this`
return retVal;
};
jscolor.prototype = realJscolor.prototype;
Then just use jscolor normally:
var c = new jscolor(target, options);
The reason for the retVal thing is that although normally a new expression's result is a refernece to the new object created by new, a constructor function can return a non-null object reference and, if it does, the new expression's result is that object reference instead. That's why we check the return value of realJscolor.
Of course, that means that all uses of jscolor on the page that use the global will now use your updated function instead. If you don't want that, just use your own name and don't override jscolor:
var myColor = function() {
var retVal = jscolor.apply(this, arguments);
// ...and so on...
return retVal;
};
myColor.prototype = jscolor.prototype;
Usage:
var c = new myColor(target, options);
Function
function a() {alert(this)} // will print `window` obejct
is defined in the window scope. That is, it is a method of the window. Your more difficult situation comes from the fact that this is different from window if you define function as a method in another object.
var a = {method: function() {alert(this)}}
you call a.method() but see that the same window again. You need to bind your function to the parent object to make it compete method.

Getting undefined from javascript module property

I have a feeling I'm missing something obvious. I'm returning a variable from my javascript module, but it keeps coming back undefined.
Here's the module:
var MyNs = MyNs || {};
MyNs.Global = function () {
var privateTestVar;
var init = function () {
if (privateTestVar == null ) {
privateTestVar = "this is a test" ;
console.log( 'Init: ' + privateTestVar);
}
};
var Public = {
init: init,
TestVar: privateTestVar
}
return Public;
} ();
Here's the call:
MyNs.Global.init();console.log( 'Called: ' +MyNs.Global.TestVar);
The console.log in the init function works fine and returns the value, but the other console log returns undefined. I'm totally missing it. Any help would be appreciated.
Update: I've change the code a bit, to this:
var privateTestVar = function () { return 'Test!'; }
var Public = {
TestVar: privateTestVar
}
And variations of that, but it returns this exact text to the console: "function () { return 'Test!'; }"
At the time that Public is assigned here:
var Public = {
init: init,
TestVar: privateTestVar
}
privateTestVar is still undefined (because init() hasn't been run yet) so the TestVar property is initialized to the value of privateTestVar which is undefined.
The TestVar property gets assigned the value of privateTestVar. If it's initially undefined (which it is in this case), it will stay that way until you assign something different to the TestVar property. I won't automatically inherit future values of privateTestVar which is perhaps what you were expecting. Javascript does not have a way of specifying that one variable will always contain whatever is assigned to another variable. privateTestVar and the TestVar` property each have their own value. Assigning something to one variable does not affect the other.
I'd suggest making a private variable really a private one, using getters instead. This will work correctly:
var Public = {
init: init,
getVar: function() { return privateTestVar; }
}
MyNs.Global.init();console.log( 'Called: ' +MyNs.Global.getVar());
Issue is as stated by #jfriend00. Change the code to
var init = function () {
if (privateTestVar == null ) {
privateTestVar = "this is a test" ;
Public.TestVar = privateTestVar;
console.log( 'Init: ' + privateTestVar);
}
};
I didn't test this out but theoretically it should work.
I think this is the structure you are looking for:
function PrivateFunc(private, public){
this.privateVar = private;
this.publicVar = public;
}
function PublicFun(public){
this.publicVar = public;
if(this.publicVar == null)this.publicVar = 'This is a public variable.';
this.PrivateFun = function(private){
return new PrivateFunc(private, this.publicVar);
}
}
var pf = new PublicFun('public variable');
var pv = pf.PrivateFun('private variable');
console.log('pf.publicVar = '+pf.publicVar);
console.log('pf.privateVar = '+pf.privateVar);
console.log('pv.publicVar = '+pv.publicVar);
console.log('pv.privateVar = '+pv.privateVar);
Notice that PrivateFunc is not PrivateFun. The real factor comes down to the key word this. this refers to the current Object as when you type this. var is only accessible inside your method. You should think of a JavaScript Object as an Associative Array. If that doesn't suit your needs try:
var jsObject = {
publicVar: null,
PrivateFun: function(private){
var privateVar = private; //cannot access with dot
return this;
},
PublicFun: function(public){
this.publicVar = public;
if(this.publicVar == null)this.publicVar = 'This is a public variable';
return this;
}
}
var pf = jsObject.PublicFun();
var pv = jsObject.PrivateFun('private variable');
console.log('pf.publicVar = '+pf.publicVar);
console.log('pf.privateVar = '+pf.privateVar);
console.log('pv.publicVar = '+pv.publicVar);
console.log('pv.privateVar = '+pv.privateVar+' //cannot access with dot');
Note that Object Literals are not Constructors, so you cannot make new instances. Also, in the Object Literal case, var privateVar is virtually useless, unless you don't want the privateVar returned. this must be returned in order to access jsObject, which holds the reference to publicVar.

Dynamically firing a named-spaced method via JavaScript

I have multiple external JavaScripts that are namespaced based on the section of the site. I am trying to dynamically fire methods, but am unable to get the methods to fire. Can anyone tell me what the problem is?
If I add this, the method fires:
Namespace.Something.init()
But when I try to do it like this, nothing happens (note: namespace equals Namespace.Something and functionname equals init):
namespace[functionname]();
Unless you want to use eval which I am sure you don't the following works.
This assumes that all your methods are the same level deep i.e namespace.somename.somemethod
var Namespace = {
Something: {
init: function() {
console.log('init called');
}
}
};
Namespace.Something.init();
var namespace = "Namespace";
var section = "Something";
var method = "init";
this[namespace][section][method]();
as Namespace is part of the global scope you can access it from this[namespace]
I asked the same question a few weeks ago, though I think I phrased it slightly differently. See this.
Basically, you need to parse the string functionname one piece at a time.
By the way, using the walk_path code from that answer, here's a general purpose function I wrote to run a function from a string including arguments.
// run an arbitrary function from a string. Will attempt to parse the args from parenthesis, if none found, will
// use additional arguments passed to this function.
utils.runFunction = function (funcdef) {
var argPos = funcdef.indexOf('(');
var endArgPos = -1;
var args = undefined;
var func = funcdef;
if (argPos > 0) {
endArgPos = funcdef.indexOf(')', argPos);
if (endArgPos > 0) {
args = funcdef.substring(argPos + 1, endArgPos).split(',');
func = funcdef.substring(0, argPos - 1);
}
} else {
args = Array.prototype.slice.call(arguments, 1);
}
var func = walk_path(window, func);
return !args ? func() : func.apply(null, args);
};
var methodName = 'Namespace.Something.init';
var methodParts = methodName.split('.');
var method = this;
for (var i=0; i < methodParts.length; i++) {
method = method[methodParts[i]];
};
method(the arguments you want);

Categories

Resources