How to set up classes in Sencha - javascript

Forgive me because I have not researched enough on this topic but I don't know how to google this one out. Here is my question, very often in jQuery Objects are instantiated something like this
myApp({
property1: 'something',
property2: true
});
I am learning Sencha and I want to be able to do something similar so here is my code.
var Person = new Ext.Class({
name: "Mr.unkown",
constructor: function(name){
this.name = name;
return this;
},
steps: 10,
constructor: function(steps){
this.steps = steps;
return this;
},
function(name, steps) {
alert(name + " " + steps );
}
});
I want to be able to be able to do initialize it by doing something like this
var Jason = new Person({"Jason",10});
I know my question is very vague and not upto the point. But please help. Any links to any learning resources would be appreciated.
UPDATE: I was able to do it using the code below
var Person = new Ext.Class({
name: "Mr.unkown",
constructor: function(name){
this.name = name;
return this;
},
steps: 10,
constructor: function(steps){
this.steps = steps;
return this;
},
constructor: function(name, steps) {
alert(name + " " + steps );
}
});
var Jason = new Person("Jason",10);

You use Ext.define to declare a class.
Ext.define('Person', {
constructor: function(name) {
this.name = name;
},
getName: function() {
return this.name;
}
});
var o = new Person();
console.log(o.getName());
Relevant docs: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext-method-define

Related

How to use constructors as a prototype chain?

Suppose that I have a javascript constructor:
function Person(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
}
the Person "type" has a convenient method, hello that I would like to re-use on another type Student. I would like for a Student to have the following structure:
function Student(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
this.books = [];
}
One option is to use the code for Student as-is above. This is sub-optimal for the usual reasons, such as that if I want it to mirror the Person type, then I have to manually keep their code in sync. Anyway, this is not good.
A second option (from this answer) is to do something like:
function Student(name) {
Person.call(this, name);
this.books = [];
}
When I mario = new Student("mario") I get the following:
Object { name: "mario", hello: hello(), books: [] }
I've successfully achieved the inheritance that I wanted, but this has the unfortunate property of placing all of the desired properties into my object. Notably, for example, there is a "hello" property on mario. It would be nice if that "hello" property could be looked up in the prototype chain.
How can I neatly create a prototype chain given the relevant object constructors?
When you create an object with new, the this value of your constructor function is set to the object, and that object's prototype is set to the prototype of the constructor Function being called.
That's why your properties are currently being added to the created object.
function Student {
this.name = name
}
const student = new Student('John')
// is (almost) equivalent to the following
const student = {}
student.name = 'John'
But if you want to add properties to the prototype instead, so that you can use inheritance, then in ES5 Javascript you can do so by assigning properties directly to the prototype of your constructor function.
function Person(name) {
this.name = name;
}
// Person is a function
// Its prototype is an instance of Object, and it has no properties
// i.e. something like Person.prototype = new Object()
Person.prototype.hello = function() {
return 'It is I, ' + this.name
}
// Now Person.prototype has one property, "hello", which is a function.
function Student(name) {
Person.call(this, name)
this.books = [];
}
// Student is a function
// Its prototype is also an instance of Object with no properties
// the following is the magic line
Student.prototype = Object.create(Person.prototype)
// We replace the prototype of the Student function with a new object, but
// Object.create() allows us to set the prototype to an existing object, in this case Person.prototype,
// Person.prototype is itself an instance of Object, and we previously
// added the "hello" function to it as a property.
const student = new Student('John')
// So what happens here?
// First a new object is created, and its prototype is set to Student.prototype
// Then we call Person.call(this)
// Which executes the body of the Person function
// So you get the properties on the object itself through the body of the Person and Student functions
// And you get the shared functionality through the prototype chain of instance -> Student.prototype -> Person.prototype -> Object.prototype
Hope that helps!
You can use prototyping method or class sugar method as you want.
Here is a simple example :
function Student(name) {
this.name = name;
this.books = [];
}
Student.prototype.hello = function(){
return "It's a-me, " + this.name + "!";
}
Student.prototype.addBook = function(book){
this.books.push(book);
}
Student.prototype.getBooks = function(){
return this.books;
}
let mario = new Student("Mario");
console.log(mario.hello());
mario.addBook("prototyping");
mario.addBook("chain");
console.log(mario.getBooks());
class Person {
constructor(name) {
this.name = name;
this.books = [];
}
hello(){
return "It's a-me, " + this.name + "!";
}
addBook(book){
this.books.push(book);
}
getBooks(){
return this.books;
}
}
let luigi = new Person("Luigi");
console.log(luigi.hello());
luigi.addBook("classSugar");
luigi.addBook("classType");
console.log(luigi.getBooks());
For longer chains use Object.assign, here is an example of making a GradStudent that is both a Student and a Person and has the personality of a Comedian and also has the properties and methods of a 4th class GameCharacter:
(function() {
//Person
function Person(name) {
this.name = name;
this.helloString = "Hello my name is "
}
Person.prototype.name = "Bob";
Person.prototype.hello = function() {
return this.helloString + this.name;
};
//Student
function Student(name, books) {
Person.call(this, name);
this.books = books;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.books = ["math","reading"];
//Comedian
function Comedian(name) {
Person.call(this,name);
};
Comedian.prototype = Object.create(Person.prototype);
Comedian.prototype.constructor = Comedian;
Comedian.prototype.hello = function() {
return "I don't know what my parents where thinking when they name me Squat, just kidding, my name is " + this.name;
};
//GameCharacter
function GameCharacter(power) {
this.power = power;
};
GameCharacter.prototype = new Object();
GameCharacter.prototype.constructor = GameCharacter;
GameCharacter.prototype.gainPower = function(power) {
this.power += ", "+power;
};
GameCharacter.prototype.statePower = function() {
return this.power;
};
//GradStudent
function GradStudent(name, books, degree) {
Comedian.call(this, name);
Student.call(this,name,books);
GameCharacter.call(this, "jumping");
this.degree = degree;
this.gainPower("flying");
}
GradStudent.prototype = Object.create(Student.prototype);
Object.assign(GradStudent.prototype, Comedian.prototype, GameCharacter.prototype);
GradStudent.prototype.constructor = GradStudent;
var gradStudent = new GradStudent("Bill",["C", "C++", "JavaScript"], "B.S.");
console.log(gradStudent.hello() + " I have a " + gradStudent.degree +" I am studying " + gradStudent.books.toString() + ". \n In a game I play my power's are "+ gradStudent.statePower() + ". \n Is gradStudent also a Student? " + (gradStudent instanceof Student) + "" );
var otherStudent = new Student("Jennifer" ,["english", "science"]);
console.log(gradStudent.books.toString() + " " + otherStudent.books.toString());
})();
GradStudent is an instance of Student, it's a type of Student, and can also do all the things Comedian and GameCharacter does. The value of Object.assign is that kind of multiple inheritance.
I can accomplish such a thing with the following:
function Student(name) {
Object.setPrototypeOf(this, new Person(name));
this.books = [];
}
However, I'm not familiar enough with javascript to know what possible problems might arise with this solution. Coming from other OO style languages, it feels weird for the prototype of mario to be an actual instance of a Person, but I suppose everything in js is an instance, in some sense, so this might just be bias on my part.

extend or inherit an object prototypes when calling a native prototype method

I've been reading Inheritance and the prototype chain and somewhere it sais :
Bad practice: Extension of native prototypes
One mis-feature that is often used is to extend Object.prototype or
one of the other built-in prototypes.
This technique is called monkey patching and breaks encapsulation.
While used by popular frameworks such as Prototype.js, there is still
no good reason for cluttering built-in types with additional
non-standard functionality.
The only good reason for extending a built-in prototype is to backport
the features of newer JavaScript engines; for example Array.forEach,
etc.
What I'm trying to do in a real example is an angular service to handle http requests that returns a simple object instance with few attributes and 2 methods findAll() and findOne(id) that I'll use one of them (and only once) in my ui-router's resolve method :
resolve: {
Resource: 'Resource',
allImages: function(Resource) {
var images = new Resource('images');
return images.findAll();
},
singleImage: function(Resource) {
var image = new Resource('images');
return image.findOne(4);
}
},
Depending on which of the 2 methods I'll call, I'm trying to extend (or even replace) the whole instance Resource with another predefined one Item or Collection where each have its own structure and methods so in my Controller I can do stuffs like :
if (allImages.existNext()) allImages.nextPage();
var currentPage = allImages.meta.currentPage,
collection = allImages.data;
singleImage.url = 'abc';
singleImage.save();
Now, the only working solution I found so far (represented by a minimal example that have nothing to do with http requests) is this :
var myApp = angular.module('myApp',[]);
myApp.factory('Animal', Animal);
function Animal() {
var Cat = function() {
this.prefferedFood = 'fish';
};
Cat.prototype.sayMiau = function() {
console.log('Miau!')
};
var Dog = function(name) {
this.dogName = name;
};
Dog.prototype.sayGrr = function() {
console.log('Grrr!')
};
function Animal(age) {
this.age = age;
}
Animal.prototype = {
makeItCat: function() {},
makeItDog: function(name) {
Dog.call(this, name);
this.__proto__ = Dog.prototype;
},
};
return Animal;
}
So inside Controller I can do:
var Dan = new Animal(7);
Dan.makeItDog('Dan');
Console.log(Dan.age); // outputs "7"
Console.log(Dan.dogName); // outputs "Dan"
Dan.sayGrr(); // outputs "Grrr!"
And it works as you can see in this jsfiddle.
The Question is :
Is that Correct? I'm not breaking the way how Object.prototype should work or losing the performance gain it should provide? Is there a better way to do it? like maybe using angular.extend or maybe not extending (or replacing) prototype at all and using something like this instead:
var Dog = function(name) {
this.dogName = name;
this.sayGrr = function(string) {
console.log('Grrr!')
}
};
...
Animal.prototype = {
makeItCat: function() {},
makeItDog: function(name) {
Dog.call(this, name);
},
};
I think the way you are doing it may work. I'm not sure about the factory implementation you did. I did something similar once that may help:
View working jsFiddle here
This is your code with slight edits:
var myApp = angular.module('myApp', []);
myApp.factory('AnimalFactory', AnimalFactory);
function AnimalFactory() {
// This is the main class
var Animal = function(age, fullName) {
this.age = age;
this.fullName = fullName;
this.eat = function() {
console.log('I am eating');
};
};
// Dog should inherit from Animal
var Dog = function(age, fullName) {
// Calling the animal constructor
Animal.call(this, age, fullName);
// Augmenting object adding a new method
this.bark = function() {
console.log('I am ' + this.fullName + ' and I bark Woof woof');
};
};
// Setting the Dog prototype to Animal
Dog.prototype = Object.create(Animal);
var Cat = function(age, fullName) {
// Calling the animal constructor
Animal.call(this, age, fullName);
// Augmenting object adding a new method
this.meow = function() {
console.log('I am ' + this.fullName + ' and I meow');
};
};
// Setting the Cat prototype to Animal
Cat.prototype = Object.create(Animal);
function createDog(age, fullName) {
return new Dog(age, fullName);
}
function createCat(age, fullName) {
return new Cat(age, fullName);
}
// Interface returned to use factory
return {
createDog: createDog,
createCat: createCat
};
}
function MyCtrl($scope, AnimalFactory) {
var dan = AnimalFactory.createDog(7, 'Dan');
dan.bark();
console.log(dan);
$scope.dan = dan;
}
I think the above code has a cleaner implementation of prototypes inheritance between your classes. Let me know what you think so we can improve it.

RequireJS, Circular Dependencies and Exports "Magic" Method

I've been trying to get RequireJS set up to handle circular dependencies using the special 'exports' magic module as recommended by James Burke's answer to this question.
Following the example given by #jrburke in that question:
define("Employee", ["exports", "Company"], function(Company) {
function Employee(name) {
this.name = name;
this.company = new Company.Company(name + "'s own company");
};
exports.Employee = Employee;
});
define("Company", ["exports", "Employee"], function(Employee) {
function Company(name) {
this.name = name;
this.employees = [];
};
Company.prototype.addEmployee = function(name) {
var employee = new Employee.Employee(name);
this.employees.push(employee);
employee.company = this;
};
exports.Company = Company;
});
jsfiddle
The problem is that using his own example, the exports module is undefined, and therefore exports.Employee and exports.Company don't set. If I try to include exports as an argument of the define callback functions, it simply initializes in both cases as empty and does not carry the constructor functions it was assigned.
What am I doing wrong?
EDIT: Through trial and error, I got the above code working at: http://jsfiddle.net/jpk45vow/4/. Can anyone explain why it works, because it makes no sense to me.
Edit: I couldn't find more info about the magic exports method. I could, however, mimic its intended behavior with a dummy "Container" module. See it in this fiddle: http://jsfiddle.net/amenadiel/a7thxz98/
console.log("start");
define("Container",function() {
var Container={};
return Container;
});
define("Employee", ["Container"], function(Container) {
var Employee= function(name) {
this.name = name;
this.company = new Container.Company(name + "'s own company");
};
Container.Employee = Employee;
});
define("Company", ["Container"], function(Container) {
var Company=function(name) {
this.name = name;
this.employees = [];
};
Company.prototype.addEmployee = function(name) {
var employee = new Container.Employee(name);
this.employees.push(employee);
employee.company = this;
};
Container.Company = Company;
});
define("main", ["Container","Employee","Company" ], function ( Container) {
var john = new Container.Employee("John");
var bigCorp = new Container.Company("Big Corp");
bigCorp.addEmployee("Mary");
console.log(bigCorp);
});
require(["main"]);

What am I doing wrong when combining objects with the module pattern

This Possible duplicate did not help me, I failed on an interview because of a similar question.
The idea is to create a person Object that is a father of teacher and grandfather of Manager using module pattern and inheritance.
Something like that Manager->Teacher->Person
My code looks like that(My Plunk):
(function(undef)
{
/**Waiting till document is ready before applying next functions*/
$(document).ready(function(){
var person = new APP.Person('Aria Stark','223232');
document.write(person.getDetails());
})();
var APP = {};
APP.Person =(function() {
function Person(name, ID) {
this.name = name;
this.ID = ID;
}
Person.prototype.getDetails = function() {
return " name: " + this.name + " ID: " + this.ID;
};
return Person;
});
APP.Teacher =(function () {
function Teacher(name, ID, salary, hatColor) {
APP.Person.call(this, name, ID);
this.salary = salary;
this.hatColor = hatColor;
}
Teacher.prototype = new APP.Person();
Teacher.prototype.getDetails = function() {
return APP.Person.call(this) + " Salary: " + this.salary + " Hat: " + this.hatColor;
};
return Teacher;
});
APP.Manager =(function () {
function Manager(name, ID, salary, hatColor, car) {
APP.Teacher.call(this, name, ID, salary, hatColor);
this.car = car;
}
Manager.prototype = new APP.Teacher();
Manager.prototype.getDetails = function() {
return APP.Teacher.call(this) + " Car: " + this.car;
};
return Manager;
});
})();
I get an error on the first line:
var person = new APP.Person('Aria Stark','22323');
The error is: Uncaught TypeError: object is not a function
Can someone help me with with that? I'm also open to hear other improvements to this code.
This is how you create (and call) a self-executing function or IIFE:
(function () {})();
Simply writing (function () {}) does not call the function, it actually has no real effect in this case. With your way APP.Person will be a function, that returns another function (the constructor for Person) when called - it will not operate well with new.
Also, for the documentready, you don't want to execute the result of the .ready call, just pass the function as a parameter, it will be called when the event triggers:
$(document).ready(function(){
}); //removed () from here
Plunk with these changes
All your objects are declared like this:
APP.X=(function() {
function Y() {}
Y.prototype.method= function() {};
return Y;
});
That is not wrong in itself, though it is a bit odd. What you want to have is this:
APP.X=(function() {
function X() {}
X.prototype.method= function() {};
return X;
})(); // actually call the anonymous function you used to encapsulate variables
Then again, why do you bother with an IIFE? You might just as well do this:
APP.X = function () {}
X.prototype.method= function() {};
Encapsulating them brings absolutely nothing, there is nothing private you are hiding from the outer scope.
Also, my post might be better suited for CodeReview than StackOverflow, but your inheritance model has significant issues. Your Teacher.prototype is an instance of Person created with no parameters. Only under highly restrictive circumstances will that be safe.
A better model would be this one:
Teacher = function(){
Person.call(this /*, person parameters*/);
}
Teacher.prototype = Object.create(Person.prototype);
There are many good answers on SO dealing with this specific issue, here is one from me.
There is no need of jQuery to create these things. Well, I have not very good exposer on this, but I tried to show the things you want to know:
// Creating Person Class
var Person = function(name, id){
this.name = name;
this.id = id;
};
Person.prototype.getInfo = function(){
return "name: " + this.name + ", id: " + this.id;
};
// Instance of Person
var x = new Person("Ashish", 1);
x.getInfo();
// Creating Teacher Class
var Teacher = function(name, id, salary, hatColor){
Person.call(this, name, id);
this.salary = salary;
this.hatColor = hatColor;
};
// Inheriting Persons methods
Teacher.prototype = new Person();
// Adding new method to it
Teacher.prototype.getFullDetails = function(){
return this.getInfo() + ", salary: " + this.salary + ", Hatcolor: " + this.hatColor;
}
// Instance of Teacher Class
var teacher = new Teacher("John", 2, 15000, "red");
teacher.getInfo(); //output: "name: John, id: 2"
teacher.getFullDetails(); // output : "name: John, id: 2, salary: 15000, Hatcolor: red"
console.log(teacher.salary); // output : 15000
So, above you can see:
- A Person class is created with 2 properties and one method.
- and then we created a Teacher class and inherited the method from Person class in it.
- and then added another method called getFullDetails() in it which accesses the method coming from Person class.
And this is what you are doing in the DOM.ready:
alert(x.getInfo()); // in my example:
In your example:
var APP = {};
APP.Person = function Person(name, ID) {
this.name = name;
this.ID = ID;
}
APP.Person.prototype.getDetails = function () {
return " name: " + this.name + " ID: " + this.ID;
};
var person = new APP.Person('Aria Stark', '223232');
alert(person.getDetails());

Modifying object's prototype not working

I've been trying to figure out why this won't work. Would appreciate if some could help me out!
function Person(name, age) {
this.name = name;
this.age = age;
var ageInTenYears = age + 10;
this.sayNameAndAge = function() {
console.log(name + age);
}
}
Person.prototype.sayAge = function() {
console.log(this.age);
}
Person.prototype = {
sayName : function(){
console.log(this.name);
},
sayNameAfterTimeOut : function(time) {
setTimeout(this.sayName, time);
},
sayAgeInTenYears : function() {
console.log(ageInTenYears);
}
}
var bob = new Person('bob', 30);
bob.sayName();
I get this error:
Uncaught TypeError: Object #<Object> has no method 'sayAge'
You are overwriting the entire prototype by doing
Person.prototype = { /* ... */ };
which means that the sayAge method you added before is lost again. Either reverse the order of those assignments or move the sayAge into the other assignment as well.
With Person.prototype = { … };, you're rewriting the prototype object, i.e. replacing the old one with a completely new object. Cou can do that, but then make sure that you're not defining any methods beforehand (like you do with .sayAge above).
There are several things wrong with the code, I made some comments where I corrected it. If you have any questions you can comment on this answer:
function Person(name, age) {
this.name = name;
this.age = age;
//var ageInTenYears = age + 10; //<--Why var, you can't
// use this anywhere but in the Person constuctor body
this.ageInTenYears=age+10;
}
Person.prototype = {
sayName : function(){
console.log(this.name);
},
sayNameAfterTimeOut : function(time) {
// check out this link about what this can be
// https://stackoverflow.com/a/19068438/1641941
var me=this;
setTimeout(function(){
me.sayName();
}, time);
},
sayAgeInTenYears : function() {
// you defined it as var so cannot use
// ageInTenYears outside the constructor body
//console.log(ageInTenYears);
console.log(this.ageInTenYears);
}
};
Person.prototype.sayAge = function() {
console.log(this.age);
};
Person.prototype.sayNameAndAge = function() {
console.log(this.name + this.age);
};
//just for good measure, someone may do
// Person.prototype.haveBaby=function(){
// return new this.constructor();
Person.prototype.constructor=Person;
var bob = new Person('bob', 30);
bob.sayName();
More on prototype, inheritance/mixin, overriding and calling super: https://stackoverflow.com/a/16063711/1641941

Categories

Resources