Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change Prototype class declarations into jquery?

I'm working with my Rails 3.1 migration and it's getting harder and harder to keep jquery and prototype living peacefully side by side. I'm investigating a way to change my Prototype-way implemented js-files into jquery format.

I've used heavily prototype-way of declaring classes and sub-classes:

// properties are directly passed to `create` method
var Person = Class.create({
  initialize: function(name) {
    this.name = name;
  },
  say: function(message) {
    return this.name + ': ' + message;
  }
});

// when subclassing, specify the class you want to inherit from
var Pirate = Class.create(Person, {
  // redefine the speak method
  say: function($super, message) {
    return $super(message) + ', yarr!';
  }
});

var john = new Pirate('Long John');
john.say('ahoy matey');
// -> "Long John: ahoy matey, yarr!"

I've read about John Resig's script: http://ejohn.org/blog/simple-javascript-inheritance/. Is this the way to go? Or should I choose some other approach?

I have about 15 js-files (one class per file). I'm willing to spend some time for this migration, so I'd like to do it right. Thanks for your professional help!

like image 830
hade Avatar asked Feb 01 '26 20:02

hade


2 Answers

Here's one possible way to implement your example with plain functions.

function Person(name) {
  this.name = name;
}

Person.prototype.say = function (message) {
  return this.name + ": " + message;
};

function Pirate(name) {
  this._super = Person.prototype;
  this._super.constructor.apply(this, arguments);
}

Pirate.prototype.say = function (message) {
  return this._super.say.apply(this, arguments) + ", yarr!";
};

john = new Pirate("Long John");
john.say("ahoy matey");

You'd probably want to extract the inheritance operations into a function, but this gives you the basic idea.

like image 177
Jimmy Avatar answered Feb 04 '26 09:02

Jimmy


This is a bit improved version of Jimmy's example. Firstly, I'd add an extra function that helps you to define prototype chain more conveniently. You could also use Object.create(), but that is not yet supported in all browsers, so this function should be a bit more bulletproof:

// A convenient function to define prototype chain

function inheritPrototype(child, parent) {
  function F(){}
  F.prototype = parent.prototype;
  child.prototype = new F();
  // set the constructor back to the original, explained later
  child.prototype.constructor = child;
}

Then define objects. Notice the extra function setName which enables us to set the name of the Person. (nevermind that in JS there's usually no need for getters/setters). Also notice the extra inheritPrototype call after Pirate function has been defined.

function Person(name) {
  this.name = name;
}

Person.prototype.say = function (message) {
  return this.name + ": " + message;
};

Person.prototype.setName = function(name) {
  this.name = name;
};

function Pirate(name) {
  this._super = Person.prototype;
  this._super.constructor.apply(this, arguments);
}

inheritPrototype(Pirate, Person);

Pirate.prototype.say = function (message) {
  return this._super.say.apply(this, arguments) + ", yarr!";
};

var john = new Pirate("Long John");
john.say("ahoy matey");

This style enables you to automatically call parent's functions, and you don't have to override each and every one of them, if they are the same as their parents'. Also this doesn't stop you from redefining functions that already exist for the parent (in this case say is overridden). And remember, all functions are 1-way, meaning that if you override a function in a children, then parent's function remains unchanged. An example:

// Should result in John "The Pirate" Long: ahoy matey, yarr! 
// instead of how it was defined in Person 
john.setName('John "The Pirate" Long');
john.say('ahoy matey');

// Notice that even though Pirate redefined say function, it
// still works as defined in Person, if it's called on a Person object
var president = new Person("Obama");
president.say('Vote for me!');

Also using this style allows you to check object types, if the child.prototype.construtor was redefined to child (replacing the prototype sets it to parent's constructor function). John is both Person and Pirate (because Pirate inherits from Person). An example:

john instanceof Person
> true
john instanceof Pirate
> true

Since president is directly a Person object and not a Pirate, the results would be the following:

president instanceof Person
> true
president instanceof Pirate
> false
like image 24
zatatatata Avatar answered Feb 04 '26 10:02

zatatatata