How do I declare class variables in Javascript.
function Person(){
fname = "thisfname"; //What needs to be put here
}
alert(Person.fname) //It should alert "thisFrame"
I don't want to use this approach.
function Person(){
}
Person.fname = "thisfname";
alert(Person.fname) //alerts "thisframe"
JavaScript does not have classes like others have said. Inheritance is resolved through prototyping which in essence does nothing more than create non-deletable property references on a newly created object. JavaScript also has alternatives for simple data objects, namely object literals.
The variation of a 'Class' in JavaScript should be defined as such:
// I use function statements over variable declaration
// when a constructor is involved.
function Person(name) {
this.name = name;
}
// All instances of Person create reference methods to it's prototype.
// These references are not deletable (but they can be overwritten).
Person.prototype = {
speak: function(){
alert(this.name + ' says: "Hello world!"');
}
};
var Mary = new Person('Mary');
Mary.speak(); // alerts 'Mary says: "Hello world!"'
The this reference always points to the owner of the function. If you call Person without the new operator, the owner will be the global scope (window). If you do not use this reference to assign properties to your instance, then the properties will simply be declared as variables. If you do not use the var statement, then those declarations will create global variables which are bad!
more about this
Using the this reference in a constructor function is exceedingly important if you want to add properties to the current instance. Without using this, you only create a variable (which is not the same as a property) and as mentioned, if you don't use the var statement either, you create global variables.
function Person(){
name = 'Mary'
}
var p = new Person();
alert(p.name); // undefined, did not use 'this' to assign it to the instance.
alert(name); // 'Mary', boo, it created a global variable!
Use this!
function Person(){
this.name = 'Mary'
}
var p = new Person();
alert(p.name); // 'Mary', yay!
alert(name); // undefined, yay!
Note, anything assigned to an instance through the function constructor CANNOT BE INHERITED unless you assign it to the prototype and overwrite it again in the function constructor to make it an owned property.
When you create a new instance of through a function doubling as a constructor, actually the following happens.
pseudo code:
copy Person.prototype as person
invoke Person function on person
return person
Actually, this is what happens in every classical language when you create an instance of a class. But the main difference in JavaScript is that it's not encapsulated inside a nice Class statement. Originally JavaScript didn't even have function constructors but was added on later because SUN demanded they wanted JavaScript to be more like Java.
Object literals
The alternative for function constructors for objects that carry only intrinsic data and no methods are object literals.
var Mary = {
firstName: 'Mary',
lastName: 'Littlelamb'
};
Which is the prefered way of declaring intrinsic objects rather then:
// do not ever do this!
var Mary = new Object();
Mary.firstName = 'Mary';
Mary.lastName = 'Littlelamb';
With object literals in your skill set, you can create a factory pattern for intrinsic data objects using the module pattern (which is usually for singletons).
var createPerson = function(firstName, lastName){
return {
firstName: firstName,
lastName: lastName
}
}
var Mary = createPerson('Mary', 'Littlelamb');
This achieves some comfortable encapsulation, but can only be used for intrinsic data objects.
Another thing you can do with Object literals and JavaScript is delegation, which should be preferred.
var personMethods = {
speak: function(){
alert(this.firstName + ' says: "Hello world!"');
}
};
var Mary = {
firstName: "Mary",
lastName: "Littlelamb"
};
var Peter = {
firstName: "Peter",
lastName: "Crieswolf"
};
personMethods.speak.apply(Mary); // alerts 'Mary says: "Hello world!"'
personMethods.speak.apply(Peter); // alerts 'Peter says: "Hello world!"'
Why should this be preferred? Because it keeps your objects minute and readable, even prototypical references take up memory and when using inheritance and 'subclassing' you end up with child instances that have lots of unused method references. Delegation is always better.
The way you mentioned is how to define class variables, the other way (inside function Person) is to define instance properties.
function Person(name){
this.name = name;
}
Person.specie = "Human";
alert(Person.specie) //alerts "Human", a class variable.
var john = new Person('John');
alert(john.name); //alerts "John", an object property.
It is important to understand that there is no such thing as classes in JavaScript. There are some frameworks out there that simulate a classical inheritance pattern, but technically it all boils down to constructor functions and prototypes.
So, you may want to do something like
PersonProto = { // the "class", or prototype
fname: "thisfname"
};
function Person() { // the constructor function
this.instanceVar = 'foo';
}
Now, connect the constructor to the prototype:
Person.prototype = PersonProto;
And, voilà:
var a = new Person();
alert(a.fname);
function Person(){
this.fname = null;
this.lname = null;
this.set_fname = set_fname;
this.set_lname = set_lname;
this.get_name = get_name;
}
/* Another way
function Person(fname, lname){
this.fname = fname;
this.lname = lname;
this.get_name = get_name;
}*/
function set_fname(fname){
this.fname = fname;
}
function set_lname(y){
this.lname = lname;
}
function get_name(){
with (this) {
return fname + ' ' + lname;
}
}
person_obj = new Person();
person_obj.set_fname('Foo');
person_obj.set_lname('Bar');
// person_obj = new Person('Foo', 'Bar');
person_obj = get_name(); // returns "Foo Bar"
Can't think of better example.
3 ways to define a variables to JavaScript class:
1)To define properties created using function(), you use the 'this' keyword
function Apple (type) {
this.type = type;
this.color = "red";
}
To instantiate an object of the Apple class, set some properties you can do the following:
var apple = new Apple('macintosh');
apple.color = "reddish";
2) Using Literal Notation
var apple = {
type: "macintosh",
color: "red"
}
In this case you don't need to (and cannot) create an instance of the class, it already exists.
apple.color = "reddish";
3) Singleton using a function
var apple = new function() {
this.type = "macintosh";
this.color = "red";
}
So you see that this is very similar to 1 discussed above, but the way to use the object is exactly like in 2.
apple.color = "reddish";
You can also try this approach:
function name() {
this.name;
this.lastname;
}
name.prototype.firstName = function(name) {
this.name = name;
alert(this.name);
}
var x = new name();
x.firstName("Kartikeya");
Related
Trying to learn how to create a durable object with JavaScript, but as you can see from the example below one can easily access any of the Person instance's members - What am I doing wrong?
function Person(name, age, job){
"use strict";
//create the object to return
var o = new Object();
//optional: define private variables/functions here
o.name = name;
o.age = age;
o.job = job;
//attach methods
o.sayName = function(){
alert(name);
};
//return the object
return o;
}
var newGuy = Person("Guy", 21, "Seeker");
newGuy.name; // "Guy" <- Shouldn't this return an error or "undefined"?
You get "Guy" because you set it as name property of o, and then return o to the outside, making it public.
If you want private variables, you can use
function Person(name, age, job){
"use strict";
// name, age, job are private variables
// sayName is a privileged method
this.sayName = function(){
alert(name);
};
}
var newGuy = new Person("Guy", 21, "Seeker");
newGuy.name; // undefined
Note you don't need to create a new o object and return it, just call the constructor with new operator and assign public/privileged properties to this.
I suggest reading Private Members in JavaScript, by Douglas Crockford.
There are a lot of different ways to create private properties. They all find ways to take advantage of the fact that variables are scoped locally within functions, but can be captured in functions.
For example rather than returning o, which will have all the properties exposed, you can return a different object that has private access. There's a bit of redundancy in this snippet, but I wanted to keep it close to your example:
function person(name, age, job){
"use strict";
//optional: define private variables/functions here
var name = name;
var age = age;
var job = job;
//return the object that uses variable, that are only visible within the function
return {
sayName: function(){
alert(name);
},
sayJob: function(){
alert(job);
}
}
}
var newGuy = person("Guy", 21, "Seeker");
newGuy.sayName();
newGuy.sayJob();
alert("undefined: ", newGuy.name); // "Guy" <- Shouldn't this return an error or "undefined"?
For a durable object, Douglas Crockford recommends avoiding "this" and "new" altogether. This is how you would go about accomplishing what you want:
var person = function (vals) {
var that = {}; // create object to avoid constructing with "new" and using "this"
that.sayName = function () { // bind accessor functions
return vals.name; // use passed values to ensure privacy
};
return that;
};
var guy = person({name: "Guy"}); // avoided use of "new"
alert(guy.name); // undefined as should be
guy.sayName(); // "Guy"
You can find more info in his book: Javascript: The Good Parts on page 52. I hope this helps.
So I am designing a grade book interface and I have a course defined as:
<script>
course = new Object();
var name;
var gradingareas;
var finalgrade;
</script>
then later I want to create a new instance:
var gradingareas = new Array("Homework", "Classwork", "Exams");
course1 = new course("CS1500", gradingareas, 85);
I have also tried without the var in front to no avail. I get an "Uncaught TypeError: Object is not a function" I am very new to javascript so I don't even know if Im going about this the correct way. Any help is appreciated Thanks.
Your existing code:
// Creates a new, empty object, as a global
course = new Object();
// Creates three new variables in the global scope.
var name;
var gradingareas;
var finalgrade;
There is no connection between the variables and the object.
It looks like you want something more like:
function Course(name, gradingareas, finalgrade) {
this.name = name;
this.gradingareas = gradingareas;
this.finalgrade = finalgrade;
}
Then:
var course1 = new Course("CS1500", gradingareas, 85);
Note the use of a capital letter for naming the constructor function. This is a convention in the JS community.
JS is prototypical, rather than class based and if you are new to it there are advantages to learning this immediately rather than trying to mush classical inheritance models from it, however, classical inheritance is alive and well in JS.
Anyhow, to answer how you would access your variables:
course1.name works fine with the example above.
If you wanted to privatise your data you could take this approach using closure:
var Course = function(name, grade) {
// Private data
var private = {
name: name,
grade: grade
}
// Expose public API
return {
get: function( prop ) {
if ( private.hasOwnProperty( prop ) ) {
return private[ prop ];
}
}
}
};
Then instantiate a new object:
var course = new Course('Programming with JavaScript', 'A');
and start using all that private data:
course.get('name');
Of course, you'd probably want setters to manipulate that data too ;)
The code that you described does the following:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Declares three variables
var name;
var gradingareas;
var finalgrade;
These declared variables aren't automatically connected to the object. If you want these properties declared on the object you have 2 options:
Declare them as properties of the object
Declare them on the prototype of of the object
Example1: declare them as properties of the object:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Access or create new properties with . or [] operator
course.name = 'math';
course.gradingareas = 'muliple';
course['finalgrade'] = 'A'
console.log(course);
Example2: Declare them on the prototype:
// Create a constructor function
function Course (name, grade) {
this.name = name;
this.grade = grade;
}
// course is added on the prototype
Course.prototype.gradingareas = 'some gradingareas';
// the name and the grade are added on the object itself
var course = new Course ('willem', 10);
console.log(course);
To create a very simple object with constructor and default values, you can do :
//My object with constructor
var myObjectWithConstrutorFunction = {
//construtor function with default values in constructor
myConstrutor: function(Name = 'bob', Age = 18){
this.Name = name;
this.Age = age;
}
};
// instance
var myInstance = new myObjectWithConstrutorFunction.myConstrutor();
// show on console
console.log('object with constructor function: ', myInstance);
// show properties
console.log(myInstace.Name, myInstance.Age);
PS : It's a good practice create a constructor's name with the same name of the class, if you are creating a external class.
The Object class has both methods and functions meaning they both are accessed through Object.nameOfMethodOrFunction(). The following question What is the difference between a method and a function explains the difference between a method and and a function, but it doesn't explain how to create them within an object. For example, the code below defines the method sayHi. But how do you define a function inside the same object?
var johnDoe =
{
fName : 'John',
lName: 'Doe',
sayHi: function()
{
return 'Hi There';
}
};
The following defines two classes, ClassA and ClassB, with equal functionality but different in nature:
function ClassA(name){
this.name = name;
// Defines method ClassA.say in a particular instance of ClassA
this.say = function(){
return "Hi, I am " + this.name;
}
}
function ClassB(name){
this.name = name;
}
// Defines method ClassB.say in the prototype of ClassB
ClassB.prototype.say = function(){
return "Hi, I am " + this.name;
}
As shown below, they doesn't differ much in usage, and they are both "methods".
var a = new ClassA("Alex");
alert(a.say());
var b = new ClassB("John");
alert(b.say());
So now what you mean for "function", according to the msdn link that you gave as a comment, seems that "function" is just a "static method" like in C# or Java?
// So here is a "static method", or "function"?
ClassA.createWithRandomName = function(){
return new ClassA("RandomName"); // Obviously not random, but just pretend it is.
}
var a2 = ClassA.createWithRandomName(); // Calling a "function"?
alert(a2.say()); // OK here we are still calling a method.
So this is what you have in your question:
var johnDoe =
{
fName : 'John',
lName: 'Doe',
sayHi: function()
{
return 'Hi There';
}
};
OK, this is an Object, but obviously not a class.
Quoting Aaron with "A method is on an object. A function is independent of an object".
Logically a method is useless without a "this" defined.
Consider this example:
var johnDoe =
{
fName: 'John',
lName: 'Doe',
sayHi: function () {
return 'Hi There, my name is ' + this.fName;
}
};
function sayHi2() {
return 'Hi There, my last name is ' + this.lName;
}
//Will print Hi there, my first name is John
alert(johnDoe.sayHi());
//An undefined will be seen since there is no defined "this" in SayHi2.
alert(sayHi2());
//Call it properly now, using the oject johnDoe for the "this"
//Will print Hi there, my last name is Doe.
alert(sayHi2.call(johnDoe));
var johnDoe = {
fName: 'John',
lName: 'Doe',
sayHi: function(){
function message(){ return 'Hi there'; }
return message();
}
};
That's about as good as you're going to get with the object declaration method of creating a 'class' in JavaScript. Just keep in mind that function is only valid within sayHi's scope.
However, if you use a function as a class structure, you have a little more flexibility:
var johnDoe = function(){
this.publicFunction = function(){
};
var privateFunction = function(){
};
};
var jd = new johnDoe();
jd.publicFunction(); // accessible
jd.privateFunction(); // inaccessible
(though both are really considered methods since they have access to the object's scope within).
I play javascript with the book Professional JavaScript for Web Developers. I practice an example in section 6.2.6. the codes are listed below:
function creatPrototype(subType, superType)
{
function subTypePrototype(){};
subTypePrototype.prototype = superType.prototype;
subTypePrototype.constructor = subType;
subTypePrototype.str = "say";
return new subTypePrototype();
}
function Person(name, age)
{
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
writeln("bill say");
}
function itMan(name, age){
Person.apply(this, arguments);
}
itMan.prototype = creatPrototype(itMan, Person);
var Bill = new itMan("bill", 25);
writeln(itMan.prototype.str); //expect "say"
writeln(Person.prototype == itMan.prototype.prototype); //expect true
Bill.say(); //expect "bill say"
the result is:
undefined
False
bill say
Why?
itMan.prototype.str is suppose to "say"
Person.prototype AND itMan.prototype.prototype should point to a same object
Bill.say() run correctly, so the prototype chain is OK.
You have to think about which property belongs to the constructor function and which one belongs to the instance. prototype is a property of the function, but constructor and str should be both properties of the instance.
This should do it:
function createPrototype(subType, superType)
{
function subTypePrototype(){};
subTypePrototype.prototype = superType.prototype;
var newPrototype = new subTypePrototype();
newPrototype.constructor = subType;
newPrototype.str = "say";
return newPrototype;
}
But, as you are also passong subType, you can actually assign the prototype directly:
function inherit(subType, superType)
{
function tconstr(){};
tconstr.prototype = superType.prototype;
subType.prototype = new tconstr();
subType.prototype.constructor = subType;
subType.prototype.str = "say";
}
and then just call it with
inherits(itMan, Person);
Person.prototype AND itMan.prototype.prototype should point to a same object
Remember that prototype is a property of a function, not of objects. But itMan.prototype is a an object. You cannot access an objects prototype unless you explicitly refer to it (but I would not do so).
With ECMAScript 5, there is a way to get the prototype, using Object.getPrototypeOf [MDN]. This only works in newer browsers though.
Here is a working example of your code.
There were some mistake with the code, try this code
function creatPrototype(subType, superType)
{
function subTypePrototype(){
this.prototype = superType.prototype;
this.constructor = subType;
this.str = "say";
}
return new subTypePrototype();
}
function Person(name, age)
{
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
document.writeln("bill say");
}
function itMan(name, age){
Person.apply(this, arguments);
}
itMan.prototype = creatPrototype(itMan, Person);
var Bill = new itMan("bill", 25);
document.writeln(itMan.prototype.str); //expect "say"
document.writeln(Person.prototype == itMan.prototype.prototype); //expect true
Bill.prototype.say(); //expect "bill say"
In your code, you were not using this object so itMAn had no variable str,
you were using
subTypePrototype.constructor = subType;
and subTypePrototype.prototype = superType.prototype;
therefore Bill.say was working and Person.prototype == itMan.prototype.prototype was not working.
Prototype is a reserved keyword and you have to be very careful while using it
Articles on prototype keyword
You have several issues in your code.
Then within your createSubPrototype :
return new subTypePrototype();
You are creating a function and then you are returning the executed function result where you should return a pointer to your function like
return subTypePrototype;
But you should not create a function cause it seems you want to retrieve parent "prototype" :)
So indeed your code should look more like :
function createPrototype(subType, superType)
{
subTypePrototype = superType.prototype;
subTypePrototype.constructor = subType; //- beware this is wrong !!!
subTypePrototype.str = "say";
return subTypePrototype;
}
Check the line I have marked as wrong, by doing so you are updating both sub & parent type
How to do it :
That being said if you want to extend an object I would advise you to use existing libs. (jQuery, Mootools, etc ). Here a sample on how to do it properly
I have some simple OO code I've written that I'm playing with:
//define a constructor function
function person(name, sex) {
this.name = name;
this.sex = sex;
}
//now define some instance methods
person.prototype.returnName = function() {
alert(this.name);
}
person.prototype.returnSex = function() {
return this.sex;
}
person.prototype.talk = function(sentence) {
return this.name + ' says ' + sentence;
}
//another constructor
function worker(name, sex, job, skills) {
this.name = name;
this.sex = sex;
this.job = job;
this.skills = skills;
}
//now for some inheritance - inherit only the reusable methods in the person prototype
//Use a temporary constructor to stop any child overwriting the parent prototype
var f = function() {};
f.prototype = person.prototype;
worker.prototype = new f();
worker.prototype.constructor = worker;
var person = new person('james', 'male');
person.returnName();
var hrTeamMember = new worker('kate', 'female', 'human resources', 'talking');
hrTeamMember.returnName();
alert(hrTeamMember.talk('I like to take a lot'));
Now this is all well and good. But I'm confused. I want to include namespacing as part of my code writing practice. How can I namespace the above code. As it is now I have 2 functions defined in the global namespace.
The only way I can think to do this is to switch to object literal syntax. But then how do I implement the pseudo-classical style above with object literals.
You could for example do following:
var YourObject;
if (!YourObject) {
YourObject = {};
YourObject.Person = function(name, sex) {
// ...
}
YourObject.Person.prototype.returnName = function() {
// ...
}
// ...
}
You don't have to use object literals, at least, not exclusively.
Decide on the single global symbol you'd like to use.
Do all your declaration work in an anonymous function, and explicitly attach "public" methods as desired to your global object:
(function(global) {
// all that stuff
global.elduderino = {};
global.elduderino.person = person;
global.elduderino.worker = worker;
})(this);
I may not be completely understanding the nuances of your issue here, but the point I'm trying to make is that Javascript makes it possible for you to start with your symbols being "hidden" as locals in a function, but they can be selectively "exported" in various ways.