Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set class name for JavaScript object

I have some test class

TestKlass = (function() {

    function TestKlass(value) {
      this.value = value != null ? value : 'hello world';
      console.log(this.value);
    }

    return TestKlass;

})();

x = new TestKlass;
x instanceof TestKlass; (gives true)

I have new empty object

y = {}
y instanceof Object

Can I find any ways to set any properties for y, something like this

y.__proto__ = x.__proto__
y.constructor.prototype = x.constructor.prototype

for to have this result

y instanceof TestKlass => true

====================================================

UPD:

So. My main aim - it's to create CLONE function. Now my solution works for me. Please look at this code:

JavaScript JS object clone

Object._clone = function(obj) {
  var clone, property, value;
  if (!obj || typeof obj !== 'object') {
    return obj;
  }
  clone = typeof obj.pop === 'function' ? [] : {};
  clone.__proto__ = obj.__proto__;
  for (property in obj) {
    if (obj.hasOwnProperty(property)) {
      value = obj.property;
      if (value && typeof value === 'object') {
        clone[property] = Object._clone(value);
      } else {
        clone[property] = obj[property];
      }
    }
  }
  return clone;
};

CoffeeScript JS object clone

# Object clone
Object._clone = (obj) ->
  return obj if not obj or typeof(obj) isnt 'object'
  clone = if typeof(obj.pop) is 'function' then [] else {}

  # deprecated, but need for instanceof method
  clone.__proto__ = obj.__proto__

  for property of obj
    if obj.hasOwnProperty property
      # clone properties
      value = obj.property
      if value and typeof(value) is 'object'
        clone[property] = Object._clone(value)
      else
        clone[property] = obj[property]

  clone

Now you can try to do that

A = new TestKlass
B = Object._clone(A)
B instanceof TestKlass => true

It's work fine with Moz FF 13. But I think it's not cross-browser. and proto is deprecated.

I think there is no universal solution. But maybe It's will be helpful for somebody.

like image 453
the-teacher Avatar asked Jun 25 '12 08:06

the-teacher


People also ask

Can we change class name in JavaScript?

The document. getElementById() method is used to return the element in the document with the “id” attribute and the “className” attribute can be used to change/append the class of the element.

Can we declare class in JavaScript?

Classes Are Functions A JavaScript class is a type of function. Classes are declared with the class keyword. We will use function expression syntax to initialize a function and class expression syntax to initialize a class.


2 Answers

obj instanceof SomeConstructor checks whether SomeConstructor is found anywhere in the prototype chain of obj.

If you want inheritance, you need to set the .prototype of FirstConstructor to a newly created SomeConstructor object.

SomeConstructor = function() {}
FirstConstructor = function() {}
FirstConstroctor.prototype = new SomeConstructor();

var y = new FirstConstroctor();
y instanceof FirstConstructor; // true
y instanceof SomeConstructor ; // true, it bubbles from FirstConstructor.__proto__ to SomeConstructor
like image 21
Willem Mulder Avatar answered Oct 10 '22 05:10

Willem Mulder


Perhaps you should read the following answer first. What you are trying to achieve is really simple. However before I explain let's look at your solutions:

Solution 1

y.__proto__ = x.__proto__;

I wouldn't recommend doing this as the __proto__ property is now deprecated. The above code won't work in Rhino.

Solution 2

y.constructor.prototype = x.constructor.prototype;

This is a very bad solution. The reason is that y.constructor is actually y.__proto__.constructor and since y is an object y.__proto__ is the same as Object.prototype. This means that y.constructor is the same as Object and you're essentially changing the prototype property of Object. This could potentially break other code on your page. I strongly discourage this practice.

Solution 3 (my solution)

What you want to do is simply change the internal [[proto]] property of an object. Since there's no cross platform way to do so we need to employ a hack. A simple solution would be to create a new object with the desired __proto__ property and set getters and setters on it to change the original object. It would be as follows:

function setPrototypeOf(object, prototype) {
    var constructor = function () {
        for (var key in object) {
            if (object.hasOwnProperty(key)) {
                (function (key) {
                    Object.defineProperty(this, key, {
                        get: function () {
                            return object[key];
                        },
                        set: function (value) {
                            object[key] = value;
                        },
                        enumerable: true
                    });
                }).call(this, key);
            }
        }
    };

    constructor.prototype = prototype;

    return new constructor;
}

After this all you need to do is:

y = setPrototypeOf(y, TestKlass.prototype);

Here is a working fiddle.

Edit:

The problem with your clone function is that it only clones objects and arrays. You forgot to account for functions which are also passed by reference. Thus when you clone an object which has methods which close over the internal state of the object, the object and its clone will share the same internal state. See the following fiddle:

function Value(value) {
    this.get = function () {
        alert(value);
    };
    this.set = function (newValue) {
        value = newValue;
    };
}

var a = new Value(5);
var b = Object._clone(a);
b.set(10);                // setting b to 10 also sets a to 10
a.get();                  // alerts 10, should alert 5

There's absolutely no way in JavaScript to clone the internal state of an object so cloning objects and arrays in JavaScript will only work for objects which do not expose closures as methods.

To know more about the problems with cloning objects in JavaScript read this answer. Click on the following link to read John Resig's answer.

like image 59
Aadit M Shah Avatar answered Oct 10 '22 04:10

Aadit M Shah