Below is the entire contents of a JS/JQuery file. I didn't write it, but I'm trying to add on to it. I am having trouble understanding what this is referring to. I haven't seen functions set up in this style before (SmartPhone = function() {})
SmartPhone = function()
{
this.miniMap = new GameModeMap();
this.init = function()
{
var self=this;
var $PhoneContainer = $("#PhoneContainer");
$PhoneContainer.append("<div id='PhoneScreen'></div>");
$PhoneContainer.append("<div class='PhoneButton'></div>");
$('.PhoneButton').click(function(){self.toggleClicked()});
this.miniMap.init("#PhoneScreen");
//append the appMenu
$("#PhoneScreen").append("<div id='AppMenu'></div>");
$("#AppMenu").hide();
initMenu();
//toggleClicked();
}
this.toggleClicked = function()
{
console.log(this);
$('#PhoneContainer').toggleClass ('clicked');
$('#PhoneScreen').toggleClass ('vertical');
this.miniMap.toggle();
$('#AppMenu').toggle();
}
this.init();
}
They're using the Object Functionality of JavaScript.
SmartPhone is essentially a class structure in this example, with init() being the construct (called by the last this.init() line within SmartPhone.
this is refering to the scope, and in this case the object being created.
How this works
Live Example
var Construct = function() {
this.magic = 42;
}
var c = new Construct();
alert(c.magic === 42);
The "this" variable in JavaScript can point to many different things depending on your context. There is a great blog post on this called: Understanding JavaScript’s this keyword
In the context you are showing, this will be bound to the object created from the SmartPhone constructor.
this refers to the SmartPhone object. For instance, this.init is defining the init method for the SmartPhone. Later, you could access it by using SmartPhone.init().
Related
I have a commercial application that has an existing JavaScript object structure using prototype chains. I have had success extending this API by adding more methods to the prototypes of objects. However, I realize that it would be best to add a namespace in front of my methods in case the application vendor decides to name a new method the same as one of my methods in a future release.
If I have an existing object called State, I would add a method called getPop like so:
State.prototype.getPop = function(){return this.pop;};
var Washington = new State('Washington',7000000);
Washington.getPop(); //returns 7000000
What I want to do is add a namespace called 'cjl' before my custom method to avoid name collision so that I can call it like so:
Washington.cjl.getPop();
I tried:
State.prototype.cjl = {};
State.prototype.cjl.getPop = function(){return this.pop;};
The problem is this. It doesn't point to the instance but instead points to the 'cjl' object.
I tried various methods, including using .bind() but none of them seemed to work. I finally found an answer here: Is it possible to organise methods on an object's prototype into namespaces? This works using the Object.defineProperty() method. The problem is the commercial application only works in compatibility mode in IE which doesn't support the Object.defineProperty() method for non-DOM elements.
Is there another way to accomplish this? I don't want to have to call multiple functions, which is the result of some techniques, e.g.:
Washington.cjl().getPop();
You could namespace in the following way, reading your comments I see that you can't change the original constructor so you'll have to replace the original with your own and save the original in a closure.
Every state instance will have it's own cjl instance but that only has a reference to current State instance, all the cjl functions are shared as they exist only once:
[UPDATE]
Forgot to get State.prototype in myState's prototype chain.
//the original constructor
function State(name, pop){
this.name=name;this.pop=pop;
}
State.org="original constructor";
//original constructor is available through
// closure and window.State is replaced with
// your constructor having the cjl namespace
(function(State){
//cjl namespace
function cjl(stateInstance){
this.stateInstance=stateInstance;
};
//cjl functions
cjl.prototype.getPopInThousands=function(){
//do not use this, instead use this.stateInstance
return this.stateInstance.pop/1000;
}
function myState(){
//apply State constructor
State.apply(this,arguments);
//create a clj instance, all methods
// are on cjl.prototype so they're shared
this.cjl = new cjl(this);
}
//inherit from State (use polyfil for older browsers)
myState.prototype = Object.create(State.prototype);
//replace window.State with your constructor
window.State=myState;
}(State))
var s = new State("Wasington", 7000000);
console.log(s.cjl.getPopInThousands());
//non standard, name
console.log("constructor name",s.constructor.name);
console.log("constructor tostring",s.constructor.toString());
More on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941
I have to agree with friend and cookie that pre fixing the function names may be the better solution but if you want to use the same methods for an object named Country then you may think of using the previous code as you can re use the cjl object.
Instead of defining State.prototype.cjl outside of the function, try to set the cjl "namespace" inside the constructor function.
function State(){
var thisObject = this;
this.cjl = {
getPop: function(){
return thisObject.pop;
}
};
}
Then you can do Washington.cjl.getPop();.
Try:
var State = function(name, pop) {
this.name = name;
this.pop = pop;
};
State.prototype.cjl = function(method) {
return this.cjlDefs[method].apply(this, Array.prototype.slice.call(arguments, 1) );
};
State.prototype.cjlDefs = {
getPop: function() {return this.pop;}
};
var Washington = new State('Washington', 80000);
console.log( Washington.cjl('getPop') );
https://jsfiddle.net/ghbjhxyh/
Or another shape if you prefer:
var State = function(name, pop) {
this.name = name;
this.pop = pop;
};
State.prototype.cjl = function(method) {
this.cjlDefs.obj = this;
return this.cjlDefs;
};
State.prototype.cjlDefs = {
assertObj: function() { /* Make sensible assertion */ },
getPop: function() { this.assertObj(); return this.obj.pop; }
};
var Washington = new State('Washington', 75000);
console.log( Washington.cjl().getPop() ); // 75000
https://jsfiddle.net/7vjrz2mn/
I am trying to create an api that extends some functionality of Tizen.
Tizen has a way of creating objects such as: 'new tizen.ContactName(...)' and 'addressbook = tizen.contact.getDefaultAddressBook();'.
This seems to be a nice way to group together methods and objects when there are a lot of them.
So, for example I want to extend the contact handling:
(An external js-file)
function ContactManager(){ //edited by comment
var self = this;
this.add = function(details, posCallback, negCallback){
//do stuff to add contact
this.otherMethod(){...}
}
etc.
I can call this by using: var contactManager = new ContactManager(); and it works fine.
Now I want to access by include it in another object(?) so that it looks like: var contactManager = new myTizen.ContactManager().
I tried:
function myTizen(){
this.ContactManager = function(){
//methods and stuff
}
}
This doesn't work. Why? How should I build my "API"?
I see it like this
define some object myTizen
then set myTizen.ContactManager = somefunction();
Here's what you want:
function myTizen() {
function whatevername() {
// methods and stuff
}
// you can even extend whatevername's prototype down here
this.ContactManager = whatevername; // please note the lack of parentheses
}
// here's another way you could do it:
function alternateMyTizen() {
}
function alternatewhatever() {
// methods and stuff
}
// extend the prototype if you choose
alternateMyTizen.prototype.ContactManager = alternatewhatever;
The main difference between option 1 and option 2 is that in the second method, your "subclass" remains in scope and can be used independently of your myTizen class, in the first method once the constructor goes out of scope, you can only access it through myTizen.ContactManager.
I'm trying to understand Javascript OOP. I'm trying to overwrite a method inside a class. The class has a default functionality when a 'click' in made. I want to override that function, so something new happens when a click is made.
I have a Javascript class that looks like this:
AlertModal = function(){
var x = *this is my close object;
x.onclick = destoryAlert;
function destroyAlert(){
console.log('destroy');
}
}
My HTML file shows:
<script type="text/javascript">
window.alert = function (message) {
var newAlert = new AlertModal();
newAlert.destroyAlert = function(){
console.log('new alert destroy');
};
newAlert.destroyAlert();
};
I get 'new alert destroy' which is great. But when I click the 'x', it says destroy as well. So it is overwritten, but not?! It's like it creates a new 'destroyAlert' function, when it's called, but leaves the default.
Can anyone please show me how I would do this, to create a class, with default functionality, but how to overwrite it if needed?
I'm use to programming in Java and Actionscript, extending classes and overwritting public/protected methods, but doing it Javascript seems so much different and I can't understand the logic to do so.
Thanks,
You can override methods on instance level:
AlertModal = function() {
this.init();
};
AlertModal.prototype.init = function() {
var modal = this;
var x = ...;
x.onclick = function() {
// Note that I'm not using `this` here, because it would
// reference `x` instead of the modal. But we can pass the modal
// from the outer scope. This is called a lexical closure.
modal.destroy();
};
};
AlertModal.prototype.destroy = function() {
console.log('destroy');
};
var myalert = new AlertModal();
myalert.destroy = function() {
console.log('new destroy');
};
myalert.destroy();
But if you want to do the same override in multiple places, it would probably be better to create a specialized OtherAlertModal by inheriting from AlertModal class. Here's a good approach to inheritance in JavaScript: http://ejohn.org/blog/simple-javascript-inheritance/
x.onclick = destroyAlertl
sets x's onclick handler to a reference local function
whereas
newAlert.destroyAlert = ...
sets this object's destroyAlert property set to a different function. It does not change the reference stored in x.onclick.
You need to put the "default" function on the prototype of AlertModal:
AlertModal.prototype.destroyAlert = function() {
...
}
and register the handler differently:
var self = this;
x.onclick = function() {
self.destroyAlert();
}
If you subsequently overwrite the destroyAlert property of such an object then the new function will be called instead.
I was reading an article here:
http://javascriptweblog.wordpress.com/2010/03/16/five-ways-to-create-objects/
It tells about five ways of creating objects. But my question is one of his way (3) is:
myApp.Notepad = function(defaultFont) {
var that = {};
that.writeable = true;
that.font = defaultFont;
that.setFont = function(theFont) {
that.font = theFont;
}
return that;
}
myApp.notepad1 = myApp.Notepad('helvetica');
As per author, we can use it when multiple instances are needed we can use any pattern from 3 (above) to 5.
But as far as I know, we do need to use this keyword which reflects back newly created instances and refers to only that instance. However above, author uses that object instead of this and also there is no new keyword used above. How will it apply to multiple object instances ? Is it essentially same as using this?
In your example, that is a new object created by this line:
var that = {};
The function then proceeds to set the properties of this object.
On the other hand, this is used with a constructor function -- when called using new, a new object is automatically created and passed to the function as this. The same example could be written as:
myApp.Notepad = function(defaultFont) {
this.writeable = true;
this.font = defaultFont;
this.setFont = function(theFont) {
this.font = theFont;
}
}
myApp.notepad1 = new myApp.Notepad('helvetica');
One advantage of the using the object literal constructor (your code) that hasn't been pointed out yet is that when you are creating a new instance of an object, the new keyword is not necessary. Or in other words, if you simply forget to use the new keyword, your code will still run as intended as you are no longer relying on the use of the new keyword to give the scope of this to your newly created object in your constructor function; The that object is now taking care of the scope for you.
This is the approach that the YUI library (and Douglas Crockford) takes for constructors.
Consider the following simple constructor:
var Car = function(model){
this.model = model;
};
If you were to call Car('Dodge Viper'); or even var MyCar = Car('Dodge Viper');, the this in the function would actually refer to the global window object. So now the property Model above is actually a global variable, which is probably not what was intended.
var Car = function(model) {
var that = {};
that.model = model;
return that;
};
// Both work the same.
var MamsCar = new Car("Mini Cooper"); // with 'new'
var DadsCar = Car("Bugatti Veyron"); // without 'new'
alert("Mam's car is a " + MamsCar.model + " and dad's car is a " + DadsCar.model);
I have a variable in a global scope which is assigned an instance of a class like this:
window.someInstance = new MyClass();
At some point later, I need to replace that variable with a new instance, but is it possible/acceptable to do that from within a method of the class itself? For example:
function MyClass () {
this.myClassMethod = function () {
window.someInstance = new MyClass();
};
}
window.someInstance = new MyClass();
window.someInstance.myClassMethod.call();
An odd scenario I know but it works cleanly, I'm just not sure if this creates any memory or referencing issues?
Only if everyone always accessess the instance indirectly via window.somereference. As soon as anyone does var x = window.someinstance then you lose the indirection and your trick would stop working.
You might acheieve a more robust implementation by placing the indirection in a variable of the instance itself instead of in a global variable
function Instance(){
this.impl = ...;
}
Instance.prototype = {
changeImpl: function(){ this.impl = new Impl(); },
//delegate all other methods
f1: function(){ return this.impl.f1(); }
}