Can't call methods on subclass of native window object in javascript - javascript

I am trying to subclass native window object, but when I do so none of the window methods are callable in child class.
Here is an example below:
<script type="application/javascript" >
function baseWindow () {
}
baseWindow.prototype = window;
var mywindow = new baseWindow();
window.alert('works'); // works of course
alert(window.document); // accessing property of course works
mywindow.alert('doesn\'t work'); // alert doesn't work in subclass error: TypeError: Illegal invocation
mywindow.__proto__.alert('works') // accessing it directly via __proto__ works
alert(mywindow.document); // accessing document property works
</script>
Can someone explain why that doesn't work and if there is workaround ?
Thanks

As you figured out already, some properties of window are inherited properly, while others are not. Those that are not are methods that expect the object they are invoked on to be window which is obviously not the case in your example. By "expect" i mean they throw an error if the expectation is not met.
What you can do to avoid it is override those particular functions, perhaps by using the original functions somehow (depending on what you want to do with them).
function MyWindow(){
this.alert = window.alert.bind(window); // override it to work!
}
MyWindow.prototype = window;
var mine = new MyWindow();
mine.alert(mine.location);
If you want many instances of Window and a single alert function shared between them and you don't want to alter window.alert, you need to add another object that inherits from window as prototype for Window:
function MyWindow() {
}
MyWindow.prototype = Object.create(window);
MyWindow.prototype.alert = window.alert.bind(window);
var mine = new MyWindow();
mine.alert(mine.location);

I am trying to subclass native window object,
You cant.
Why? because window is not a function, and you cant call Window constructor.
Why? because the DOM is built that way.
function baseWindow () {
}
baseWindow.prototype = window
it's not even proper prototypal inheritance.
if Window constructor was callable one could write
function BaseWindow () {
Window.call(this);
}
BaseWindow.prototype = Object.create(Window.prototype)
But you cant do that.
EDIT just to be clear,
window is an instance of Window, they are not the same.

Related

"Uncaught TypeError: undefined is not a function" Error message in Javascript when calling a method in an object

I have a problem when calling a function from a button in HTML that gives me the: "Uncaught TypeError: undefined is not a function" error. I don't think there's anything wrong here.. Or there is something that I haven't taken into account. Thanks in advance for answering!
I have a lot of JS files, this is because this is a school assignment and we're now learning the Model, View, Controller (MVC) method.
I have this button:
<button onClick="ControllerBKE.reageerOpKlik()">Ok!</button>
I then have this Javascript code that creates an object of ^ "ControllerBKE":
"use strict"
window.onload = reageerOpStart();
function reageerOpStart()
{
var controllerBKE = new ControllerBKE();
}
Here is the line of code that is in the "ControllerBKE" that should, but is not reacting to the button:
function ControllerBKE(){
this.reageerOpKlik = reageerOpKlik;
function reageerOpKlik(){
alert('hoi');
}
}
This is just a small portion of a big code. But I get the error message when I click on the button instead of getting an alert with 'hoi'.
reageerOpKlik is an instance method. You have to use it from an instance. The simplest solution (not the best) is to create a global controller instance. There are many ways you could get rid of that global variable, but it's beyond the scope of the question.
function reageerOpStart()
{
window.controllerBKE = new ControllerBKE();
}
<button onClick="window.controllerBKE.reageerOpKlik()">Ok!</button>
The problem is that your code
<button onClick="ControllerBKE.reageerOpKlik()">Ok!</button>
is trying to call reageerOpKlik on your prototype object ControllerBKE.
What you probably mean is
<button onClick="controllerBKE.reageerOpKlik()">Ok!</button>
where controllerBKE is an instance of your prototype.
However, you have another problem. The function:
function reageerOpStart()
{
var controllerBKE = new ControllerBKE();
}
Creates controllerBKE in the scope of the reageerOpStart function, meaning that it's not avaiable in the global scope, which is where your button click handler would expect it.
You might want to consider:
<button onClick="APP.controllerBKE.reageerOpKlik()">Ok!</button>
APP = {}
function reageerOpStart()
{
APP.controllerBKE = new ControllerBKE();
}
Or, better still:
<button id="myButton">Ok!</button>
function reageerOpStart()
{
var controllerBKE = new ControllerBKE();
document.getElementById("myButton").addEventListener("click", function() {
controllerBKE.reageerOpKlik();
});
}
What you have is referred to as a closure. Your function has a limited scope. That is, it can only be called inside of ControllerBKE() where it is defined, not from outside the function.
What you have effectively done though is expose that closure via a property on your instance of ControllerBKE. While this works, it would fit more with the prototypal structure of JavaScript to add it to ControllerBKE.prototype.
It's important to remember that JavaScript is Prototypal not Object Oriented. While this may act similar to object oriented encapsulation, the two have different concepts and uses.
Look at the following example:
HTML:
<button onclick="controllerBKE.reageerOpKlik()">Ok!</button>
JavaScript:
"use strict";
window.controllerBKE = new ControllerBKE();
function ControllerBKE () { }
ControllerBKE.prototype.reageerOpKlik = function () {
alert('hoi');
}
I've simplified some of your code and refactored it to support the prototype object that JavaScript provides us with.
The first line is adding the controllerBKE variable to the window object. This gives it a global scope across the page, allowing your onclick function to have access to it.
The next line is a simple function wrapper. This will create an instance of ControllerBKE of type object.
The function you're trying to call is now attached to the prototype of ControllerBKE. This means that any instances of ControllerBKE created with the new keyword will have access to this function.
Check out the full functionality in the fiddle below:
FIDDLE
References:
Object.prototype
Object Oriented JavaScript

How can I extend the document object?

I'm currently trying to get a better understanding of JavaScript and prototyping.
I wanted to add a function to the document but prototype is undefined on document.
This code:
document.prototype.writeLine = function(text){
this.write(text);
this.write("<br />");
};
Generates this error:
// In FireFox
TypeError: document.prototype is undefined
// In Chrome
Uncaught TypeError: Cannot set property 'writeLine' of undefined
How can I extend the document object to be able to call something similar to document.WriteLine('MyText') ?
Here is the Fiddle I'm working with.
I updated your fiddle. The problem you were having is that document object is an instance of the HTMLDocument object type. The instance itself doesn't have a prototype, however the HTMLDocument does.
Update: Here is a snippet which works in IE9 because under IE9 HTMLDocument is undefined.
if (typeof HTMLDocument !== 'undefined') {
HTMLDocument.prototype.writeLine = function(text){
this.write(text);
this.write("<br />");
};
} else {
Document.prototype.writeLine = function(text){
this.write(text);
this.write("<br />");
};
}
document.writeLine("Line 1");
document.writeLine("Line 2");
The problem is that document is of type object and not function. In JavaScript you use functions as constructors like this:
function MyClass() {
this.myProperty = "something";
}
You may create an instance of MyClass as follows:
var myInstance = new MyClass;
alert(myInstance.myProperty);
Every function also has a property called prototype which is an object. All the properties of the prototype are inherited my instances of the constructor function:
MyClass.prototype.displayProperty = function () {
alert(this.myProperty);
};
myInstance.displayProperty();
In your case since document is the instance of a constructor and not the constructor itself, there's no property called prototype on it.
For more information about inheritance in JavaScript read this answer.
is very easy, document and Document are both different, document is the document of the window and Document is the interface of the document (thats comone from DOM), if your like add a new prototype for you use in your document you need add this but into Document like this:
window.Document.prototype.Sayhi = "Hello World"
or Document.prototype.Sayhi = "Hello World"
and now you can call this from you document like
document.sayhi
thats happen because you need Set the prototype on Interfaces if you like for example add a new prototype in your Object window your need Set it at Window interface like:
Window.prototype.Saybye = "Bye Bro See You Later"
and you can call the prototype in you window.Saybye
remember, Window is an interface that contain window like Document and document****

Delegate Javascript Functions

As an siginificantly simplified scenario, say I have 2 Javascript objects defined as below:
var ClassA = Class.extend({
'say': function(message) {
console.log(message);
}
... // some more methods ...
});
var ClassB = Class.extend({
init: function(obj) {
this._target = obj;
}
});
I'd suppose that in Javascript there is some kind of mechanism could enable us to do the following trick:
var b = new ClassB( new ClassA() );
b.say("hello");
I'd like to find a way to detect if there is a method called upon ClassB, and the method is not defined in ClassB, then I can automatically forward the method call to be upon ClassA, which is a member variable in ClassB.
In a realworld scenario, ClassA is an object implemented as brwoser plugin and inserted into the webpage using <object> tag. It's method is implemented in C++ code so there is no way I can tell its methods from its prototype and insert it to ClassB's prototype beforehand.
I'd like to use the technical to create a native Javascript object, with a narraw-ed version of ClassA's interface. Is there a way I can do this?
I don't think there is a quick cross-browser solution to this.
If you only need Firefox, then use __noSuchMethod__
See here: is-there-such-a-thing-as-a-catch-all-key-for-a-javascript-object
and here: javascript-getter-for-all-properties
Otherwise, I would try something like this:
var b = new ClassB( new ClassA() );
// functionToCall is a string containing the function name
function callOnB(functionToCall) {
if(typeof b[functionToCall] === function) {
b[functionToCall]();
} else {
b._target[functionToCall](); // otherwise, try calling on A
}
}
This is using the Square Bracket Notation where
b.say('hello')
is the same as
b['say']('hello')
Of course, you should probably expand this to take arguments in:
function callOnB(functionToCall, listOfArguments) {...}
Thanks to jfrej's hint on noSunchMethod, I did some more research on it and it turns out what I need is quit fit with Harmony Proxies(here and here). And an example can be found at http://jsbin.com/ucupe4/edit#source
Another related post: http://dailyjs.com/2010/03/12/nosuchmethod/

Is it possible to add instance methods to all "classes" in JavaScript?

This is more of an exploratory question, seeing how the core JavaScript stuff works. I realize the convention is to not override any core JavaScript classes, but I just can't seem to wrap my head around this one.
You can create what acts like "class methods" in JavaScript by adding to the core Function prototype like this:
Function.prototype.class_method = function() {
console.log("class method called")
}
var User;
User = (function() {
function User() {}
return User;
})();
User.class_method(); // "class method called"
My question is, is there a way to add "instance methods" in a similar way? Something crazy like this, but what's below doesn't work (or make any sense):
alias = Function.prototype.constructor;
Function.prototype.constructor = function() {
child = this;
child.prototype.instance_method = function() {
console.log("instance method called");
}
alias.apply(child);
}
var user = new User();
user.instance_method(); // method doesn't exist
It's almost like you'd need to override the Function class' constructor method and access the prototype from there. Is this possible?
It does work if you add to the Object.prototype like this:
Object.prototype.instance_method = function() {
console.log("instance method");
}
var user = new User();
user.instance_method(); // "instance method called"
But that doesn't seem right either, mainly because seeing the output in the node.js console from console.log({}); change is confusing:
console.log({});
// {};
Object.prototype.instance_method = function() {
console.log("instance method");
}
console.log({});
// {"instance_method": [Function]}
If you are using node.js, you should be able to use Object.defineProperty [MDN] and make the new property non-enumerable:
Object.defineProperty(Object.prototype, 'instance_Method', {
value: function() {
console.log("instance method");
},
enumerable: false // it's already the default
});
This was introduced in ECMAScript5, so only newer browsers will support it.
It's important to understand when the prototype comes into play. It's simply an object that is a property of a function. It only has meaning when you use the new keyword. Example:
var Widget = function(val) {
this.value = val;
};
Widget.prototype.getValue = function() {
return this.value;
};
var widget1 = new Widget('test');
widget1.getValue(); // test
var widget2 = new Widget('test2');
widget2.getValue(); // test2
When new is used, the js interpreter will create a hidden _proto_ property on the instance. This proto link is simply a reference to the prototype object of the constructor function, e.g., Widget at the time the constructor was called.
When you override the Function constructor, you are literally adding something that will be on the _proto_ property of every function created after you modified Function.prototype.
If you make the statement child.prototype... = ... in your base 'class' constructor function, then that prototype will not have meaning until something 'instantiates' child, e.g., var child = new child();.
A great Resource.
To answer your question about 'instance methods', you simply need to do something like the following:
var Widget = function() {
this.method = function() {
return 'instance method';
};
};
Widget.prototype.method = function() {
return 'class method';
};
var widget1 = new Widget();
widget1.method(); // instance method
delete widget1.method;
widget1.method(); // class method
This is due to javascript's implementation of Prototypical Inheritance. The proto link I spoke of before is key here. When widget1 was first created, inside the constructor function Widget, method was attached specifically to widget1. This method will not be available to other instances. However, method on the prototype is shared across all instances of Widget.
At runtime, when the js interpreter sees widget1.method();, it first sees if widget1 has method as a property directly on it (objects in js are just hashmaps in essence, in which the keys are called 'properties'). It finds the instance method as a property in this case. However, once you delete the instance method, it will attempt to follow the _proto_ link, which is just an object reference to Widget.prototype (at the time the constructor was called). Widget.prototype.method is defined; therefore, the interpreter will execute that. If no method function is found when continuing to follow _proto_ links, it'll be a run-time error.

Using window object

I've seen lots of people using window. when calling some variable. But aren't all the variables of a same window actually in window?
Example:
window.onorientationchange = function() {
var orientation = window.orientation; // <-- WHY?
switch(orientation) {
/* ... */
}
}
But the same people use alert(), document, etc. So why?
At certain times you want to expose only certain functions/variables to be explicit properties of the window.
(function() {
var jQuery = function(selector) { alert( selector ) }
})();
jQuery // not defined
If we alter it to be:
(function() {
var jQuery = function(selector) { alert( selector ) }
window.jQuery = jQuery;
})();
then we "expose" it from a private namespace explicitly.
And yes, you do not have to explicitly declare window. to invoke methods such as alert, but everyone has their own style of coding and everyone has their own degree of how explicit their statements should be.
Some people explicitly prefix window. to global methods such as alert in order to avoid any confusion. Let's say you defined a function in a private namespace that was named alert, for example...
(function() {
function alert() {}
alert('lol'); // does nothing
window.alert('lol') // does something
})();
We cannot use alert inside of that private namespace to do our alerting, since we defined a function with exactly the same name. We have to explicitly reference the window.alert method to get around that.
But for general purposes, I would say it's perfectly fine to not prefix things with window. unless you are exposing things in a private namespace to the global namespace. So please use document and alert and such as is, in your code.
In many javascript tutorials alert(), document() and so on are used without fully qualified window object and I think they just repeat that code.

Categories