The small demo below illustrates my problem:
// 1 - Define a global reference to classA
(function() {
window.classA = new ClassA();
})();
// 2 - ClassA object definition
function ClassA() {
this.test1 = function() {
document.write('test1');
};
}
// 3 - ClassA inherits Array and has a test function
ClassA.prototype = new Array;
ClassA.prototype.test2 = function() {
document.write(this[0]);
}
// 4 - Test our ClassA
var c = new ClassA();
c.test1();
c.push('test2');
c.test2();
// 5 - Test our global ClassA
classA.test1();
classA.push('test2'); // doesn't work
classA.test2(); // doesn't work
Try it here: http://jsfiddle.net/SPSW4/
What is the proper way to define a global variable classA (ClassA instance)?
The correct approach would be to create the pseudo-sub-classed Array constructor within an immediately invoked function expression and then expose the result to an explicit global object.
(function( global ) {
// Declare the ArrayLike constructor
function ArrayLike() {
var args = [].slice.call( arguments ),
length = args.length, i = 0;
this.length = length;
for ( ; i < length; i++ ) {
this[ i ] = args[ i ];
}
return this;
}
// Define ArrayLike's prototype by creating a new Array instance
ArrayLike.prototype = new Array();
// Define your own proto method
ArrayLike.prototype.firstChar = function() {
var ret = [],
length = this.length, i = 0;
for ( ; i < length; i++ ) {
ret[ i ] = this[ i ][ 0 ];
}
return ret;
};
// Expose the ArrayLike constructor.
global.ArrayLike = ArrayLike;
})( this );
var a = new ArrayLike( "alpha", "beta", "gamma" );
console.log( a.push("delta") ) // 4
console.log( a ); // ["alpha", "beta", "gamma", "delta"]
console.log( a.firstChar() ); // ["a", "b", "g", "d"]
See it live: http://jsfiddle.net/rwaldron/gLdkb/
Your code appears to be binding the global classA variable before ClassA is fully defined. I believe you will have more luck if you do it like:
// 1 - define ClassA
window.ClassA = function() {
this.test1 = function() {
document.write('test1');
};
};
ClassA.prototype = new Array;
ClassA.prototype.test2 = function() {
document.write(this[0]);
}
// 2 - Define a global reference to classA
window.classA = new ClassA();
// 3 - Test our ClassA
var c = new ClassA();
c.test1();
c.push('test2');
c.test2();
// 4 - Test our global ClassA
classA.test1();
classA.push('test2'); // doesn't work
classA.test2(); // doesn't work
Here's an example: http://jsfiddle.net/SPSW4/2/
swap
// 2 - ClassA object definition
function ClassA() {
this.test1 = function() {
document.write('test1');
};
}
// 1 - Define a global reference to classA
(function() {
window.classA = new ClassA();
})();
declaration before calling functions in JavaScript, it is a scripting language.
Try this:
// 2 - ClassA object definition
function ClassA() {
this.test1 = function() {
document.write('test1');
};
}
// 3 - ClassA inherits Array and has a test function
ClassA.prototype = new Array;
ClassA.prototype.test2 = function() {
document.write(this[0]);
}
// 4 - Test our ClassA
var c = new ClassA();
c.test1();
c.push('test2');
c.test2();
// 1 - Define a global reference to classA
window.classA = new ClassA();
// 5 - Test our global ClassA
classA.test1();
classA.push('test2');
classA.test2();
Actually there were two problems:
1. Creating object before declaring class
2. Creating object before extending class
Define your class
ClassA = function()
{
this.test1 = function()
{
document.write('test1');
};
};
Then apply array prototype
ClassA.prototype = Array.prototype;
Then you can extend your class
ClassA.prototype.test2 = function()
{
document.write(this[0]);
};
About the “global reference” part. In the first part of your code your are not making a reference, you are instancing a class which has not been defined yet at that point. There is no need to do that also. What is your point with that part?
Move the class definition before the call.
Note: The only thing that really needs to come first is the prototyping, since your code first assigns the class, but never sees the effect of the prototyping, which occurs later. Your class assignment should come after the prototypes.
You're missing a ; after the test2() definition.
// Class Definition
function ClassA() {
this.test1 = function() { document.write('foo'); };
}
ClassA.prototype = new Array();
ClassA.prototype.test2 = function() { document.write(this[0]); };
// Init
(function() {
window.classA = new ClassA();
})();
// Method Calls
var c = new ClassA();
c.test1();
c.push('bar');
c.test2();
classA.test1();
classA.push('bar');
classA.test2();
Related
If I do:
Array.prototype.test = "test"
Array.prototype.t = function() {return "hello"}
Every new Array will have the property test and the method t.
How can I do the same without affecting all Arrays?
Like:
Names = function(arr){
// Contacts constructor must be the same of Array
// but add the property test and the function t
}
z=new Names(["john","andrew"])
So that z.test will return "test" and z.t() will return "hello"?
(but Array.test and Array.t would stay undefined)
I explain better:
Array.prototype.t="test";
Array.prototype.test = function(){ return "hello";}
z=new Array("john", "andrew")
console.log(z);
But this affects ALL arrays.
I want the same but with a new constructor Names that inherits Array constructor.
class Names extends Array {
constructor(...args) {
super(...args);
}
}
Names.prototype.t = 'test';
let z = new Names("john", "andrew")
z.push('Amanda')
console.log(z.t)
console.log(z)
You can easily set it at Names.prototype
Can't you just extend Array?
class Names extends Array {
constructor(...args) {
super(...args);
this.t = "test";
}
test() { return "hello" }
}
let z = new Names("john", "andrew")
Here is a crude implementation:
function Names(arr) {
this.contacts = enhanceArray(arr);
}
function enhanceArray(arr) {
arr.test = 'helloProp';
arr.t = function() {
return 'helloFunc'
}
return arr;
}
let z = new Names(["john", "andrew"]);
console.log(z.contacts[0]);
console.log(z.contacts.test);
console.log(z.contacts.t());
You can create your own extended Array constructor factory, something like
(() => {
const myArr = XArray();
let a = myArr(["John", "Mary", "Michael"]);
console.log(`myArr(["John", "Mary", "Michael"]).sayHi(1): ${a.sayHi(1)}`);
console.log("demo: myArr(1, 2, 3) throws an error");
let b = myArr(1, 2, 3); // throws
// an extended array
function XArray() {
const Arr = function(arr) {
if (arr.constructor !== Array) {
throw new TypeError("Expected an array");
}
this.arr = arr;
};
Arr.prototype = {
sayHi: function (i) { return `hi ${this.arr[i]}`; }
};
return arr => new Arr(arr);
}
})();
/* StackOverflow needs a console API */ console.log = function(x) { document.write(x + "<br />"); };
B = function() {}
B.prototype = Array.prototype;
var a = new Array();
var b = new B();
a[0] = 1;
b[0] = 1;
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
JSON stringifies the subclass as an object ( { "0": 1 } ) instead of as an array ( [1] )`
Is there any way to modify this behaviour?
EDIT
I'm using (non-negotiably) ES5. I've simplified the example slightly. In reality, the subclassing is set up through a function inherit() which does this:
var inherit = function(base, derived) {
function F() {}
F.prototype = base.prototype;
derived.prototype = new F();
derived.prototype.constructor = derived;
};
As far as I know, you cannot inherit from array. As soon as you create a constructor function, the instances of it will be objects. When you want the functionality of an array, rather create an array and add the methods on it you want. This can be done with a function:
function createExtendedArray () {
var a = [];
a.method1 = function() {};
return a;
}
I have a SuperClass "class", and this class is to be inherited (via the prototype chain) by SubClassA and SubClassB. However, while the inheritance appears to work for SubClassA, it fails for SubClassB. The code is below:
function SuperClass(childCell){
this.childCell = childCell;
this.children = new Array(9);
for(i=0; i<9; i++) {
this.children[i] = new this.childCell();
}
}
function SubClassA(){
this.num = 1;
}
SubClassA.prototype = new SuperClass(SubClassB);
function SubClassB(){
this.num = 2;
}
SubClassB.prototype = new SuperClass(SubClassC);
function SubClassC(){
this.num = 3;
}
var x = new SubClassA();
In this code, I set x to an object of SubClassA, and this should in turn give me a children property containing 9 SubClassB objects. It does this properly, but in turn, each SubClassB object should contain 9 SubClassC objects. However, after inspecting the console, I found that none of the SubClassB objects actually contain the childCell or the children properties that it was supposed to inherit via prototype.
In other words, x.children[0] returned SubClassB {num: 2}, and had none of the other properties.
Why does the inheritance work for SubClassA but not SubClassB?
try reorder your declaration sample like
function Parent(childCell){
this.childCell = childCell;
this.children = new Array(9);
for(var i=0; i<9; i++) {
this.children[i] = new this.childCell();
}
}
function ChildA(){
this.num = 1;
}
function ChildB(){
this.num = 2;
}
function ChildC(){
this.num = 3;
}
ChildB.prototype = new Parent(ChildC);
ChildA.prototype = new Parent(ChildB);
your problem - you call ChildB constructor before you add prototype to it
UPDATE
#Bagavatu when you create object you use prototype which set for constructor function, then you can change prototype properties and this changes will be apply to all objects with this prototype.
In your case you change reference to prototype so it does not apply to object which was created before. You can test it in simple example
function A() {this.cell = 10}
function B() {this.num =1}
var b1 = new B(); // b1 = {num:1}
B.prototype = new A();
var b2 = new B(); // b1 = {num:1}, b2 = {num:1, cell:10}
I usually dont dig that much deep.But when we use sub classing in javascript,folllow the following pattern.
function Superclass() { }
Superclass.prototype.someFunc = function() { };
function Subclass() { }
Subclass.prototype = new Superclass();
Subclass.prototype.anotherFunc = function() { };
var obj = new Subclass();
I am trying to create a function which will take arguments arg1, arg2... then pass them into a constructor for a new object C like so: new C(arg1, arg2...), so to make a new instance of C the user would simply have to call C(arg) instead of new C(arg). Here is my first attempt:
var C = function(a){ this.a = a; }
var Cn = function(){
new C.apply(this, arguments);
}
Cn(0) // Should make a new C with a property a equal to 0
new C(0) // ie the same as this
Edit: Note, I need it to take an arbitrary number of arguments and not use eval. I'm making a library implementing Algebraic Data Types in js.
Edit: The solution was to take Jeremy's Idea and adapt it to take an unbounded number of arguments:
var C = function() {
// A unique object so we can identify when we used the 'newless' constructor
var newlessConstructorObj = {}
// Check to see if C has been called with `new`
if(!(this instanceof C))
// If not pass arguments as single arg back to C
return new C(newlessConstructorObj, arguments);
// Check to see if we got here from the line above, if so the arguments were passed in the second arg
var args = (arguments[0] === newlessConstructorObj) ? arguments[1] : arguments
// Do stuff with args
this.a = args[0];
}
C(0);
new C(0);
If you want to be able to call the function with or without the new keyword, you have to follow this pattern:
C = function(a) {
if (!(this instanceof C)) {
return new C(a);
}
this.a = a;
}
so to create a new instance of "C":
c = new C(a);
and
c = C(a);
will both return a properly formed instance of C
I would have picked Fabrizio Calderan's solution any day, but because you want this specific functionality - here is what predecessors tell us:
you can apply arguments to prototype.constructor (but there are issues when doing it with native types, like Number):
var Cn = function(){
return C.prototype.constructor.apply(C, arguments);
}
Link: Instantiating a JavaScript object by calling prototype.constructor.apply
or.. use eval:
function construct(Constructor)
{
/*
* or Array.prototype.slice.call(arguments, 1).map(function() { ... })
* in JavaScript 1.6+, compatibles, and with augmented Array.prototype
*/
var args = [];
for (var i = 1, len = arguments.length; i < len; i++)
{
args[i - 1] = "arguments[" + i + "]";
}
/* or args.join(", ") if you need it pretty-printed */
return eval("new Constructor(" + args + ")");
}
function Foo()
{
window.alert(Array.prototype.slice.call(arguments, 0).join(", "));
}
var f = construct(Foo, /bar/g, {baz: 42});
Link: http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/ff1a104bdc33d5c8
something like this?
var C = function(obj){
var a;
for (a in obj) {
this[a] = obj[a];
}
}
var Cn = function(obj) { return new C(obj); }
instance = Cn({
a : 1,
b : 2
})
instance.a //1
instance.b //2
instance.c //undefined
Doing it with a fixed number of args is simple:
// assuming one arg
function Cn(arg) {
return new C(arg);
}
// assuming two args
function Cn(arg0, arg1) {
return new C(arg0, arg1);
}
and so on. You can even make a general version for any number of parameters by iterating over arguments to create a string, then eval it. Crass, but effective.
But what's the point? Just to save typing 4 characters?
If you don't care about having a correct instanceof check you can try this:
var C = function(a){ this.a = a; }
var Cn = function(){
return C.apply({}, arguments); // notice an empty object here
}
Cn(0) // Should make a new C with a property a equal to 0
new C(0) // ie the same as this
Updated for ES6, you can use the spread operator:
var C = function(a){ this.a = a; }
var Cn = function(...args){
return new C(...args);
}
assert.deepStrictEqual(Cn(10), new C(10));
I read crockford's page on private members http://javascript.crockford.com/private.html in Javascript and got a question which maybe somewhat related. Why should a developer use Prototype?
For example,
For example, I can do this
var Foo = new Object();
Foo.bar = function() { alert('Its a bar'); };
var x = Foo;
x.bar();
instead of
var Foo = function(){};
Foo.prototype.bar = function(){alert('Its a bar');};
var x = new Foo();
x.bar();
Both of these implementations do the same thing. How is one different from the other? Does this affect inheritance in any way?
When you use the prototype pattern, only one instance of attributes you add to the prototype exist.
// Lets create 1000 functions which do the same thing
for (var i=0;i<1000;i++) {
Foo = new Object();
Foo.bar = function() { alert('Its a bar'); };
var x = Foo;
x.bar();
}
// This is the same as #1, but is more common
function Foo() {
this.bar = function () { alert('It\'s a bar'); };
}
for (var i=0;i<1000;i++) {
var x = new Foo;
x.bar();
}
// Lets create 1 function
var Foo = function(){};
Foo.prototype.bar = function(){alert('Its a bar');};
for (var i=0;i<1000;i++) {
var x = new Foo();
x.bar();
}
The prototype pattern has the disadvantage of not being able to access private members.
// Lets create 1 function
var Foo = function(){
var private = 4;
this.baz = function () {
alert(private);
}
};
Foo.prototype.bar = function(){alert(private);};
var x = new foo;
x.bar(); // error; `private` is undefined
x.baz(); // ok