1

I'm trying to create a new class, but it doesn't seem to be working. Here's the code:

<script>
var myClass = function(arg){
    return new init(arg);
}
var init = function(arg){
    return arg;
}
init.prototype.prop = true;
</script>

The problem is that myClass('foo') doesn't return 'foo' as expected. Instead, it returns init. Then I tried this code:

var init = function(arg){
    return [arg];//Now init returns an array
}

The myClass('foo') returns ['foo'], but then myClass('foo').prop turns into undefined. Does anyone know how to solve it?

EDIT: I want to create this class more or less as jQuery does. For example: $('div') returns directly a value (in case, all div tags), but not an object with a property that stores this values

Danilo Valente
  • 11,270
  • 8
  • 53
  • 67
  • Do you really want the constructor to return the same value you passed in? – bfavaretto Jun 01 '12 at 01:48
  • It's just an example. It could return a number multiplied by 2, for example – Danilo Valente Jun 01 '12 at 01:50
  • @MarkLinus `$('div')` doesn't return a value, it returns an object – Ja͢ck Jun 01 '12 at 02:16
  • Whatever, I want to return this object, however, not with literal properties, but with numeric properties (to work like an array) and with method/properties that can be declared by .prototype – Danilo Valente Jun 01 '12 at 02:19
  • While I don't really understand what you're after, if you want to return the string from the call to `new init(arg)`, you can do so as a String object wrapper. `return new String(arg);` Though overriding the object being created seems to defeat the purpose of `new`. –  Jun 01 '12 at 02:32
  • @MarkLinus—jQuery returns a "jQuery" object that has a nubmer of methods and properties, one of which is a (possibly empty) array of elements. – RobG Jun 01 '12 at 02:34
  • @amnotiam I tried it, but wasn't exaclty what I expected. – Danilo Valente Jun 01 '12 at 02:37
  • And @RobG, yes, that's what I mean. I want to return this "custom" object – Danilo Valente Jun 01 '12 at 02:38

4 Answers4

4

When you call new init() and within init() you return a non-object, it yields an instance of init instead of the returned value.

If you return an Array from your init() function, it gets returned instead; but Array doesn't take your init prototype into consideration :)

See also: https://stackoverflow.com/a/1978474/1338292

If you want to be like an array, you can do this:

function myClass(arg) {
    return new init(arg);
}
function init(arg) {
    this.push(arg);
}
init.prototype = [];
init.prototype.foo = true;

var x = new init('foo');
console.log(x) // ["foo"]
console.log(x.foo) // true

It makes init inherit from the Array prototype (i.e. []). After that you can add more properties and methods to the init prototype as you wish.

Community
  • 1
  • 1
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
3

In you code:

> <script>
> var myClass = function(arg) {
>   return new init(arg);
> }
> var init = function(arg){
>   return arg;
> }
>
> init.prototype.prop = true;
> </script>
>

The problem is that myClass('foo') doesn't return 'foo' as expected. Instead, it returns init. Then I tried this code:

Your code may be clearer if written as function declarations (which is more common):

function myClass(arg) {
  return new init(arg);
}

function init(arg) {
  return arg;
}

When you call myClass('foo'), you pass a string to init, which is called as a constructor. The function then attempts to return the string, however a function called as a constructor will always return an object. If you try to return a primitive, it will instead return its this object. It's not very clearly stated in ECMA-262. but it is there.

Then I tried this code:

var init = function(arg) { return [arg]; //Now init returns an array

Because an array is an object, so that is what is returned.

> }
> 

The myClass('foo') returns ['foo'], but then myClass('foo').prop turns into undefined. Does anyone know how to solve it?

Because your constructor returns an array, not its this object. The returned array inherits from Array.prototype, not init.prototype.

RobG
  • 142,382
  • 31
  • 172
  • 209
2

If you return a value from a function and try to use the new keyword with it, the return value will not be a newly instantiated object, but rather the value following the return. So in your case the 'foo' string is being returned, not a new object as you expect.

Steve
  • 6,618
  • 3
  • 44
  • 42
  • Thank you for the answer, but now it throws `TypeError: string is not a function` – Danilo Valente Jun 01 '12 at 01:52
  • I'm not sure how you got that. Functions are classes. If you intend to create an instance of `myClass`, you shouldn't be using `return` in the function (or at least not with a return value). What you have above is a function that returns an instance of `init`, except that it doesn't; it returns the original argument instead. – Steve Jun 01 '12 at 01:57
  • I've updated the question to explain better what I want. Please take a look on it – Danilo Valente Jun 01 '12 at 01:59
  • @Steve—Not true about the return statement. A function called as a constructor **always** returns an object. If you try to return a string (or any other non–object), it will instead return its *this* object. – RobG Jun 01 '12 at 02:07
  • @RobG -- ack, you're right, although I could swear I've seen some browser exhibit that behavior at some point, but maybe I'm thinking of object literals. – Steve Jun 01 '12 at 02:15
2

If you want to create a new class, you might want to consider this pattern:

var MyClass =function(arg) {
    this.init(arg);
};
MyClass.prototype = {
    init: function(arg) {
        // Do something with that arg
        this.someArg = arg;
    },
    myProperty: 'Hell world',
    someArg: null   
};

var myVar = new MyClass('Some arg');

Test is out:

console.log(myVar.myProperty);
console.log(myVar.someArg);

Check it out: http://jsfiddle.net/4zwpm/

MK_Dev
  • 3,291
  • 5
  • 27
  • 45