3
\$\begingroup\$

I am currently learning javascript and I attempted to make a Person class (note - this was part of a practice exercise, so some of the design decisions may have been due to the requirements).

Specifically, I am looking for feedback on:

  • Usage of prototypes (i.e. from my understanding, prototype should be used when the particular behaviour/property is shared with all objects. This means there is only 1 instance of the function (e.g.) getFullName() which is shared across all objects, whereas the properties fullName, firstName and lastName which are declared directly in the Person function, thus a new unique copy will be created in every instance.

  • Usage of undefined (i.e. exercise required us to initially have obj.firstName to be equal to undefined. But does it make more sense to have these properties equal to undefined, or to have it equal to null, or to equal an empty string (like "").

  • Usage of this (am I generally correct in the usage of this? Particularly when prototypes are used)

var Person = function(firstAndLast) {
    this.fullName = firstAndLast;  
    this.firstName = undefined;
    this.lastName = undefined;       
};

Person.prototype.setFullName = function(firstAndLast){
    this.fullName = firstAndLast;
};
Person.prototype.setFirstName = function(first){
    this.firstName = first;
};
Person.prototype.setLastName = function(last){
    this.lastName = last;
};
Person.prototype.getFullName = function(){
    return this.fullName;
};
Person.prototype.getFirstName = function(){
    //exercise required a default firstName to be set, only if this function was called
    if(this.firstName === undefined){
        this.firstName = this.defaultFirst();    
    }
    return this.firstName;
};
Person.prototype.getLastName = function(){
    //exercise required a default lastName to be set, only if this function was called
    if(this.lastName === undefined){
        this.lastName = this.defaultLast();
    }
    return this.lastName;
};

Person.prototype.defaultFirst = function(){
    var first = "";
    for(var i=0;i<this.fullName.length; i++){     
        if(this.fullName[i] !== " "){     
            first += this.fullName[i];
        }else{
            break;
        }
     }
    return first;
};

Person.prototype.defaultLast = function(){
    var last = "";
    for(var i=this.fullName.length-1; i>0; i--){
        if(this.fullName[i] !== " "){
            last += this.fullName[i];
        }else{
            break;
        }
    }
    return last.split("").reverse().join(""); 
};
\$\endgroup\$
2
\$\begingroup\$
  • Just so you know, undefined in JS is mutable. It's value can be changed. You could resort to using void 0 instead of undefined.

  • In JS, assignment operations are as good as values, equivalent to the value assigned. Also, the || acts like a "default" operation, where if the left-side value is falsy (ie, blank string, undefined, null, false, 0), the right-side value is used. And so, getFirstName (and similarly, getLastName) can be simplified into:

    return this.firstName = this.firstName || this.defaultFirst();
    
  • For defaultFirst and defaultLast, essentially you're splitting by space and getting the first and last contiguous word, respectively. And so, it can be simplified using split and shift or pop:

    // For first name:
    return this.fullName.split(' ').shift();
    
    // For last name:
    return this.fullName.split(' ').pop();
    
\$\endgroup\$
0
\$\begingroup\$

(1) Usage of prototypes

"from my understanding, prototype should be used when the particular behaviour/property is shared with all objects"

Yes, this is more or less correct. Functions on prototype are shared with all objects, which inherit it. They are not recreated, but simpyl executed within a different context (this) for each object. However, it depends on your design, if this is desirable. For instance the Getters and Setters in your case can syimply be by-passed:

var Person = function (firstAndLast) {

    this.fullName = firstAndLast;  

    ...

}

Person.prototype.setFullName = function(firstAndLast){
    this.fullName = firstAndLast;
};

var p = new Person("Foo Bar");
p.fullName = "lala";

console.log(p.getFullName()) // 'lala'

If you want fullName to be truly private, you would have recreate Getters and Setters for each object.

var Person = function (firstAndLast) {

    var fullName = firstAndLast;  

    this.getFullName = function () { return fullName; };
    this.setFullName = function (str) { fullName = str; };

    ...
}

(2) Usage of undefined

If your requirements state, it has to be undefined, then make it undefined. But whether that's useful, depends on the use-case. I would go with neutral elements of the desired type for each property.

(3) Usage of this

Also correct, this is the common usage of this.

PS: Also bear in mind, this approach tries to emulate classes. However, JavaScript has no real concept of classes. Emulating foreign language features is not necessarily a good idea. http://www.crockford.com/javascript/inheritance.html

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.