I have the following code:
Javascript:
slideShow = {
ImgsFolder: "images/",
ImgsSrc: ['img.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg', 'img5.jpg'],
MainElem: document.getElementById('SlideShow'),
ImgElem: (this.MainElem.firstElementChild) ? this.MainElem.firstElementChild : this.MainElem.firstChild
doit: function(){
for (i = 0; i < this.ImgsSrc.length; i++) {
document.writeln(this.ImgsFolder + this.ImgsSrc[i] + "<br/>");
}
}
}
When print the value of ImgElem variable , gives me error message this.MainElem is undefined, and the problem in the last line.
I don' know what's the problem in this part of code
As I mentioned in a comment, it is not possible to refer to the object being created via object literal notation from within the notation itself.
You need to fully create the object before you can reference it.
slideShow = {
ImgsFolder: "images/",
ImgsSrc: ['img.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg', 'img5.jpg'],
MainElem: document.getElementById('SlideShow')
}
slideShow.ImgElem = slideshow.MainElem.firstElementChild ||
slideshow.MainElem.firstChild
To refer to the object during creation, you need a constructor function.
function SlideshowMaker() {
this.ImgsFolder = "images/",
this.ImgsSrc = ['img.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg', 'img5.jpg'],
this.MainElem = document.getElementById('SlideShow')
this.ImgElem = this.MainElem.firstElementChild ||
this.MainElem.firstChild
}
// use "new"----v----to create a new object
var slideshow = new SlideshowMaker()
In order to use the this keyword you have to instantiate object with the new keyword. Otherwise the this keyword will point to the window object in this case.
When you use the object literals such as { key: value, ... }, the object is actually created after the whole block is parsed/executed.
var a = {
// a is not defined here
key: value
};
// it is defined here
Also, you cannot use this as a reference to the object you are about to create. this can only be used in methods of an object (functions bound to the object or executed in their context).
You have two options:
1.) You need to either create a getter function such as
var a = {
b: value,
c: function () { return this.b.c; }
};
and call it in order to access b.c: a.c()
2.) The better way in your case is to define the property ImgElem after the object is actually created:
var slideShow = {
MainElem: document.getElementById('SlideShow')
};
slideShow.ImgElem = slideShow.MainElem.firstElementChild || slideShow.MainElem.firstChild;
Notice the usage of slideShow instead of this.
Maybe you have missplaced some parentheses?
var slideShow = {
ImgsFolder: "images/",
ImgsSrc: ['img.jpg', 'img2.jpg', 'img3.jpg', 'img4.jpg', 'img5.jpg'],
MainElem: document.getElementById('SlideShow'),
ImgElem: (this.MainElem.firstElementChild ? this.MainElem.firstElementChild : this.MainElem.firstChild)
}
Related
JavaScript really behaves weirdly in case of Objects. Although I'm not sure if it is the correct behaviour.
Inside a new Object(), I set some properties in the object. Next time when I do again new Object(), instead of default values I get values set in previous instance. Argh.
Below example explains the problem clearly
function testo() {}
testo.prototype = {
obj: {
what: {
value: 5
}
},
done: function () {
console.log(this.obj.what.value);
this.obj.what = {value: 10};
}
};
var x = new testo();
x.done();
var y = new testo();
y.done();
The output of above code is:-
5
10
I was expecting it to be:-
5
5
Why? Because I'm creating new Class() and in the previous instance I had set the value using 'this', it is not static and default properties of all objects inside it should show up.
I have created above example as the demo. I'm facing this issue in my library. I know it has to do with objects are stored as the reference.
How should I proceed to get the expected output? Any thoughts?
You could move the prototype property (which is for all instances the identical) to just a this object in the class.
function testo() {
this.obj = { what: { value: 5 } };
}
testo.prototype = {
done: function () {
console.log(this.obj.what.value); this.obj.what = { value: 10 };
}
};
var x = new testo();
x.done();
var y = new testo();
y.done();
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.
Basicly, i want "theId" to be equal to what "getId" returns. But how?
var Quiz = {
getId : function() {
var params = 1;
return params;
},
theId : getId(),
};
An object literal can't refer to properties/methods within itself, because at the time the object literal is evaluated the object doesn't exist yet. You have to do it as a two-step process:
var Quiz = {
getId : function() {
var params = 1;
return params;
}
};
Quiz.theId = Quiz.getId();
Note that that sets theId to whatever getId() returned at that time, it doesn't somehow automatically update theId if your real-world function is more dynamic than your example and potentially returns different values each time it's called.
Alternatively if the function is declared before the object you can create both object properties at once, with one being a reference to the function and the other being the result of calling it.
Seems a bit like a duplicate of Self-references in object literal declarations, but you could use a simple getter function for your property:
var Quiz = {
get theID() {
var params = 1;
return params;
}
};
While searching the web, I've encountered a post that shows why the following example of dynamically generated methods does not work as planned:
// Create a new user object that accepts an object of properties
function User( properties ) {
// Iterate through the properties of the object, and make sure
// that it's properly scoped (as discussed previously)
for ( var i in properties ) { (function(){
// Create a new getter for the property
this[ "get" + i ] = function() {
return properties[i];
};
// Create a new setter for the property
this[ "set" + i ] = function(val) {
properties[i] = val;
};
})(); }
}
The reason for that is the anonymous function, which uses the "this" keyword is context of the "window", instead of "User".
1) Why does the this keyword in the anonymous function refers to "window instead of "User"?
2) Is there an accepted and common way to create "Dynamically Generated Methods"?
Thanks,
Joel
The reason that this refers to the window object, rather than User, is because this depends on the caller. In this case, the foreach contains an anonymous function that is immediately called. The caller will be considered to be the window object.
The reason it's not working is because the code is poorly written. It would be a simple thing to pass both context and the i-variable to be scoped:
function User( properties ) {
// Iterate through the properties of the object, and make sure
// that it's properly scoped (as discussed previously)
for ( var i in properties ) { (function(x){
// Create a new getter for the property
this[ "get" + x ] = function() {
return properties[x];
};
// Create a new setter for the property
this[ "set" + x ] = function(val) {
properties[x] = val;
};
}).call(this, i); }
}
I did try all your examples, but no one has worked perfectly.
This is the working code:
function User( properties ) {
// Iterate through the properties of the object, and make sure
// that it's properly scoped (as discussed previously)
var that = this;
for ( var i in properties ) { (function(){
// Create a new getter for the property
that[ "get" + i ] = function(i) {
return function (){
console.debug(i);
return properties[i];
}
}(i);
// Create a new setter for the property
that[ "set" + i ] = function(i) {
return function (val){
properties[i] = val;
}
}(i);
})(); }
}
var user = new User({
name: "Bob",
age: 44
});
console.log(user.getname(), user.getage()) //Bob, 44
user.setname("Antonio");
user.setage(33);
console.log(user.getname(), user.getage()) //Antonio, 33
More explanation to the following link
computerone.altervista.org
You need to set a proper reference of the "this" element. You are inside an anonymous scope.
As the first line of the function "User" you should declare a variable like
var _this = this;
Then, instead of calling this[ "get" + i], you have to call _this[ "get" + i]
Try:
// Create a new user object that accepts an object of properties
function User( properties ) {
// Iterate through the properties of the object, and make sure
// that it's properly scoped (as discussed previously)
var self = this;
for ( var i in properties ) { (function(){
// Create a new getter for the property
self[ "get" + i ] = function() {
return properties[i];
};
// Create a new setter for the property
self[ "set" + i ] = function(val) {
properties[i] = val;
};
})(); }
}
The problem there is the missing new operator. If you instance your User without it, the this inside will be window.
This will not work:
var george = User(properties);
This will work:
var george = new User(properties);
This tutorial it's interesting to follow.
var vehiclePage = (function(){
// defined these 3 public variable. to share between zoomNoShowFee & submitVehicle
this.obj;
this.rate;
this.idx;
var setPara = function(o,t,i){
this.obj = o;
this.rate = t;
this.idx = i;
}
return {
zoomNoShowFee : function(o,t,i){
// this is existing function. I need to access o,t,i inside submitVehicle function.
setPara(o,t,i); // wrote this private function to set values
},
submitVehicle : function(){
// here I need to access zommNoShowFee's parameter
alert(this.rate);
}
} // return
})();
vehiclePage.zoomNoShowFee(null,5,3);
vehiclePage.submitVehicle(); // getting undefined
zoomNoShowFee is already existing. Some other fellow developer wrote this. I want to use the values passed into zoomNoShowFee parameters inside submitVehicle.
For that I declared 3 public variables at the top and trying to store the values using setPara private function. so that I can access those public variables inside submitVehicle function.
But getting undefined when calling vehhiclePage.submitVehilce()
Fundamentally, I doing something wrong. But don't know where...
Thanks for any help...
In your use of the module pattern, you're mixing a few things. this.obj, this.rate and this.idx are properties of the wrong this object. In fact, they are properties of the global object, and you can verify this:
vehiclePage.zoomNoShowFee(null,5,3);
alert(rate); // alerts '5'
So, you have to store your values somewhere else. It's quite easy, though : just use regular variables instead of properties and you're good to go :
var vehiclePage = (function(){
var obj, rate, idx;
var setPara = function(o,t,i){
obj = o;
rate = t;
idx = i;
}
return {
zoomNoShowFee : function(o,t,i){
setPara(o,t,i);
},
submitVehicle : function(){
alert(rate);
}
} // return
})();
vehiclePage.zoomNoShowFee(null,5,3);
vehiclePage.submitVehicle();