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.
Related
I recently read that using private method is bad because they are very memory inefficient because a new copy of the method would be created for each instance. In the example given, how is dispalyIncreasedSalary more efficient than increaseSalary?
var Employee = function (name, company, salary) {
this.name = name || ""; //Public attribute default value is null
this.company = company || ""; //Public attribute default value is null
this.salary = salary || 5000; //Public attribute default value is null
// Private method
var increaseSalary = function () {
this.salary = this.salary + 1000;
};
// Public method
this.dispalyIncreasedSalary = function() {
increaseSalary();
console.log(this.salary);
};
};
// Create Employee class object
var emp1 = new Employee("John","Pluto",3000);
// Create Employee class object
var emp2 = new Employee("Merry","Pluto",2000);
// Create Employee class object
var emp3 = new Employee("Ren","Pluto",2500);
In the following example is this.dispalyIncreasedSalary reused for all objects?
No. You are binding it to this. So each gets it's own copy of that. That is what an instance member means. They bind to instance and not to Class/Object.
What about this.name etc. properties?
Same.
Aren't the this.propName not copied for all the instances?
If that happens all instance see the same value and that's a big NO.
You are correct that it is wasteful/inefficient to duplicate what could be a shared function for each instance.
You should investigate how JavaScript prototypes work: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
So shared methods would be placed onto every object and shared like this:
Employee.prototype.dispalyIncreasedSalary = function() {
increaseSalary();
console.log(this.salary);
}
I am learning prototype in JavaScript and this is the code I am trying -
<script>
function employee(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var trialcoder = new employee('trialcoder', 26, 'M');
//employee.prototype.salary = null;
trialcoder.salary = 19000;
document.write("salary is "+ trialcoder.salary);
</script>
My thoughts- To add another property we need to use prototype like - employee.prototype.salary = null; so on un commenting this line, I was expecting an error but it was not..let me know where I am wrong in the prototype concept.
Code Source - http://www.w3schools.com/jsref/jsref_prototype_math.asp
Your code is correct, because when you called
var trialcoder = new employee('trialcoder', 26, 'M');
You got an object instance of employee and just like any other object you can add properties to your trialcoder object like
trialcoder.salary = 19000;
In this case, the salary property is only available to your trialcoder object and if you make another instance of employee like var another = new employee() you have no salary property in another object, but, if you do something like
function employee(name, age, sex) { //... }
employee.prototype.salary = 19000;
and then make instances like
var anEmp = new employee();
console.log(anEmp.salary); // 19000
Make another instance
var newEmp = new employee();
console.log(newEmp.salary); // 19000
if you want, you can
newEmp.salary = 10000;
console.log(anEmp.salary); // 10000
Which means, when you add a property in the prototype of a constructor (employee) then every object instance can share the same property and after making an instance from the constructor, you can change the property of an instance but this won't effect other instances. Hope it's clear enough now.
Your code is right and you will not receive error because using prototype your setting property salary of class employee and after creating an object of your class ur are setting the property for that specific object,if you create another object you can set its property salary too
If you set property using prototype then all objects of that class will share that (salary) property .
I have been trying to learn OOP with JavaScript before I start attempting to learn backbone.js.
I want to be able to data bind but I can't seem to get it to work.
I've just made a simple protoype of a budget website that you can put in a budget and input how much you've spent, and it will show if you've gone over.
function BudgetItem(spent, budget){
this.setSpent = function(spent){
this.spent = spent;
}
this.setBudget = function(budget){
this.budget = budget;
}
this.getSpent = function(){
return this.spent;
}
this.getBudget = function(){
return this.budget;
}
}
function BudgetType(type){
this.getType = function(){
return type;
}
}
BudgetType.prototype = new BudgetItem();
$(document).ready(function(){
var food = new BudgetType('food');
$('.budget').html(food.getBudget());
$('.editbudget').change(function(){
food.setBudget($('.editbudget').data())
});
})
That's my code thus far. I'm not sure if I'm doing it right. Am I supposed to extend things? Also, can someone explain how to dynamically data bind without a library?
First I'll give you some theory. A Javascript function is a dynamic object, just like Object is, and a new instance can be created using the new keyword much like you are doing in your listener. When this happens, the function itself will run as a constructor while the this keyword will be bound to the newly created object. What you're doing above then is in fact adding new properties on the fly as you're passing in their values for the first time... which is fine, but not very clear to another reader.
Now for the tricky part. Every function has a link to a "hidden" Prototype object. This is an anonymous (not accessible by name) object created by the JavaScript runtime and passed as a reference to the user object through the prototype property. This Prototype object also has a reference to the function through its constructor property. To test what I'm saying for yourself, try the following:
BudgetItem.prototype.constructor === BudgetItem // true
Putting it all together, you can now think of functions as constructors to (hidden) classes that are created for you behind the scenes, accessible through the function's prototype property. So, you could add the fields to the Prototype object directly as so:
function BudgetItem(spent) {
this.spent = spent
}
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };
Another problem is inheritance and passing parameters to the constructor. Again, your version is valid but you lose the ability to pass the spent and budget values when initializing a BudgetType. What I would do is forget prototypes and go:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.type = type;
return instance;
}
This is close to what Scott Sauyet suggested above but more powerful. Now you can pass both parameters (and more) and have a more complicated inheritance tree.
Finally, what you can do is create private (or pseudo-private, more accurately) properties by providing a getter to an otherwise automatic variable (one passed as an argument or initialised inside the function). This is a special feature of the language and it works like so:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.getType = function() {
return type;
}
return instance;
}
Now you can access the 'type' passed in the constructor by obj.getType() but cannot override the initial value. Even if you define obj.type = 'New Value' the getType() will return the initial parameter passed because it has a reference to another context which was created when the object was initialised and never got released due to the closure.
Hope that helps...
if you want all instances of objects to reference the same members/values you can use a closure:
// create a constrctor for you object wrapped in a closure
myCon = (function() {
// define shared members up here
var mySharedObj = new function () {
this.member = "a";
}();
// return the actual constructor
return function () {
this.mySharedObj = mySharedObj;
}
}());
// create two instances of the object
var a = new myCon();
var b = new myCon();
// Altering the shared object from one
a.mySharedObj.member = "b";
// Alters it for all
console.log(b.mySharedObj.member);
If you want to build objects from other objects(sort of like other languages' class whatever extends baseClass), but do not want them to share values via reference(instead a clone of values), you can use something like the following:
Object.prototype.extendsUpon = (function (_prop, _args) {
return function (base) {
for (var key in base) {
if (_prop.call(base, key)) {
this[key] = base[key];
}
}
function con(child){
this.constructor = child;
}
con.prototype = base.prototype;
this.prototype = new con(this);
this.__base__ = base.prototype;
var args = _args.call(arguments);
args.shift();
base.constructor.apply(this, args);
}
}(Object.prototype.hasOwnProperty, Array.prototype.slice));
Then to build objects ontop of objects:
// Base Object Constructor
function Fruit(name) {
this.fruitname = name;
}
Fruit.prototype.yum = function() {
return "I had an " + this.fruitname;
}
// Object constructor that derives from the Base Object
function Favorite() {
// Derive this object from a specified base object:
// #arg0 -> Object Constructor to use as base
// #arg1+ -> arguments passed to the BaseObject's constructor
this.extendsUpon(Fruit, "apple");
// From here proceed as usual
// To access members from the base object that have been over-written,
// use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();
// Outputs: "I had an apple and it was my favorite"
mmm.yum();
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");
I know how to use JSON to create objects, but there doesn't seem to be away to use JSON to create an object that is of a specific object type.
Here's an example of an Object and creating an instance of it:
Person = function() { };
Person.prototype = {
FirstName: null,
GetFirstName: function() {
return this.FirstName;
}
};
//Create an instance of the Person Object
var me = new Person();
me.FirstName = "Chris";
alert(me.GetFirstName()); //alert the FirstName property
Now, I would like to use JSON to create a new Person object so that the GetFirstName function works on it.
Here's something like that I'm looking to do (but this code doesn't work):
var you = new Person() { FirstName: "Mike" };
// OR
var you = new Person{ FirstName: "Mike" };
Is there anyway to use JSON to create an object that is of a specific type?
UPDATE: My sample with the Person object is just to simplify the question. In fact, I am unable to modify the constructors of the actual objects that I need to create instances of. The objects are part of a third-party library.
UPDATE: Using some of the suggestions below, I was able to figure out a way to create an object that inherits from the original, and accept JSON in it's constructor. This is neat!
personWrapper = function(obj){
for(var o in obj){
this[o] = obj[o];
}
};
personWrapper.prototype = new Person();
var you = new personWrapper({FirstName: "Chris"});
alert(you.GetFirstName());
alert(you instanceof Person); // returns True - we are successfully inheriting from Person!
I don't imagine so. I'd create a function on the Person class to initialise from a JSON object if I were you.
function Person() {
this.loadFromJSON = function(json) {
this.FirstName = json.FirstName;
};
}
If you didn't know what class the JSON object was representing beforehand, perhaps add an extra variable into your JSON.
{ _className : "Person", FirstName : "Mike" }
And then have a 'builder' function which interprets it.
function buildFromJSON(json) {
var myObj = new json["_className"]();
myObj.loadFromJSON(json);
return myObj;
}
Update: since you say the class is part of a third-party library which you can't change, you could either extend the class with prototyping, or write a function which just populates the class externally.
eg:
Person.prototype.loadFromJSON = function(json) {
// as above...
};
or
function populateObject(obj, json) {
for (var i in json) {
// you might want to put in a check here to test
// that obj actually has an attribute named i
obj[i] = json[i];
}
}
You could allow new Person() to accept an object to populate attributes with as a parameter.
var you = new Person({ firstName: 'Mike' });
You can derive an object from theirs. Your constructor can accept the object you want, but call their constructor in an unaffected fashion:
function yourWrapper(obj) {
theirObject.call(this);
for (var s in obj) {
this[s] = obj[s];
}
}
yourWrapper.prototype = new theirObject();
Or something like that :)