admin管理员组

文章数量:1180511

I don't understand in JavaScript when to use the word "prototype" vs. using simple "dot" notation without the word "prototype". Can someone look at these code blocks and help me understand when you'd want to use one over the other?

with "prototype":

function employee(name,jobtitle)
{
  this.name=name;
  this.jobtitle=jobtitle;
}

var fred=new employee("Fred Flintstone","Caveman");
employee.prototype.salary=null;
fred.salary=20000;
console.log(fred.salary);

without "prototype":

function employee(name,jobtitle,salary)
{
  this.name=name;
  this.jobtitle=jobtitle;
  this.salary=salary;
}

var fred=new employee("Fred Flintstone","Caveman", 20000);
console.log(fred.salary);

I don't understand in JavaScript when to use the word "prototype" vs. using simple "dot" notation without the word "prototype". Can someone look at these code blocks and help me understand when you'd want to use one over the other?

with "prototype":

function employee(name,jobtitle)
{
  this.name=name;
  this.jobtitle=jobtitle;
}

var fred=new employee("Fred Flintstone","Caveman");
employee.prototype.salary=null;
fred.salary=20000;
console.log(fred.salary);

without "prototype":

function employee(name,jobtitle,salary)
{
  this.name=name;
  this.jobtitle=jobtitle;
  this.salary=salary;
}

var fred=new employee("Fred Flintstone","Caveman", 20000);
console.log(fred.salary);
Share Improve this question edited Jul 12, 2012 at 17:05 user229044 239k41 gold badges344 silver badges346 bronze badges asked May 3, 2012 at 11:51 tim petersontim peterson 24.3k63 gold badges184 silver badges302 bronze badges 2
  • 1 Adding members to the prototype property of the constructor function makes sense if the member is a method - instead of defining the common methods on each instance, you simply put it in the prototype and all instances inherit them. – Šime Vidas Commented May 3, 2012 at 11:59
  • 1 If I may suggest you, I would probably mark the @Mark Reed's answer as correct one as he explains it better than anyone else. It's probably possible to still change the correct answer somehow. But it's just a suggestion. Thanks. – Dawid Zbiński Commented Sep 19, 2017 at 18:51
Add a comment  | 

7 Answers 7

Reset to default 11

JavaScript objects have a property which is a pointer to another object. This pointer is the object's prototype. Object instances by default share the same prototype:

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

Employee.prototype.company = "IBM";

Employee.prototype.who = function(){
  console.log("My name is", this.name, "I work for", this.company);
}

var bob = new Employee('Bob');
var jim = new Employee('Jim');

// bob and jim are seperate objects, but each is linked to the same 'prototype' object.

jim.who(); // jim doesn't have a property called 'who', so it falls back to it's 'prototype', where who exists
// My name is Jim I work for IBM

bob.who();
// My name is Bob I work for IBM

// Bob leaves IBM for Microsoft
bob.company = "Microsoft"; // bob now has a property called 'company'. The value of which is 'Microsoft', which overrides bob's prototype property of the same name.

bob.who();
// My name is Bob I work for Microsoft

Employee.prototype.company = 'Facebook';

jim.who(); 
// My name is Jim I work for Facebook

bob.who(); // Bob is not affected by the change.
// My name is Bob I work for Microsoft

delete bob.company;

bob.who(); // bob no longer has it's own property 'company', so like jim, it drops down to the prototype object.
// My name is Bob I work for Facebook

The issues around JS and inheritance may be complex, but the answer to your question is relatively simple. Consider this code:

 function Klass() { }
 var obj1 = new Klass();
 var obj2 = new Klass();

Now, if you add a property to obj1, that property exists only on obj1. Likewise obj2.

If you add a property to Klass, that property likewise exists only on Klass (the function object). It doesn't affect obj1 and obj2 at all.

But if you add a property to Klass.prototype, that property will then be present on both obj1 and obj2, as well as any future objects created via new Klass. If you then change the value of the property on the prototype, the changed value will be what you see on all those objects.

You could add code inside the body of the Klass function to add properties to this; that will then cause any future Klass objects to get those properties. But each object would have its own copy - which can add up, memory-wise, especially when the properties are methods -and those copies would not be affected by future changes to the body of Klass.

ES5's Object.create almost removes the need to hassle around with .prototype anymore.

So, to pick up @Gerry's example, you can go like

var Mammal = {
    walk: function() {}
};

var Dog = Object.create(Mammal, {
    bark: {
        value: function() {}
    }
}); // create a new object which [[prototype]] refers to Mammal

Dog.walk();
Dog.bark();

The prototype object is a little tricky to understand; however this article on OOP JavaScript can help shed some light.

In a nutshell, the prototype object provides a blueprint for a 'recipient' object - all you have to do is point the recipient's prototype property at your blueprint object. Note that you can have as many recipients of a prototype blueprint object as you like (so Car and Train can both point to a common Vehicle prototype object).

You are free to define both properties and functions in a prototype object which will any recipient objects will be able to use, eg:

var vehiclePrototype = {
    // A property which will be supplied to the recipient
    cost: 0,

    // A method which will be supplied the recipient
    move: function () { 
        // Your prototype can refer to 'this' still.
        console.log("Moving " + this.name);
    };
}

You can now create a Car which makes use of the vechiclePrototype:

// Factory method for creating new car instances.
function createCar(name) {
    // Define the Car's constructor function
    function Car(name) {
        this.name = name;
    }

    // Point the car's prototype at the vechiclePrototype object
    Car.prototype = vechiclePrototype;

    // Return a new Car instance 
    return new Car(name);
}

// Create a car instance and make use of the Prototype's methods and properties
var mustang = createCar(mustang);
mustang.cost = 5000;
mustang.move();

A new Train object could be created in a similar fashion:

function createTrain(whilstleSound) {
    // Define the Train's constructor function
    function Train(name) {
        this.whilstleSound = whilstleSound;
    }

    // Point the train's prototype at the vechiclePrototype object
    Train.prototype = vechiclePrototype;

    // Return a new Train instance 
    return new Train(name);
}

var ic125 = new Train("pooop pooop");
ic125.move();

One of the big advantages of using Prototypical inheritance all instances of both Car and Train share the exact same move function (instead of creating multiple instances of the same function) which results in a significant memory saving if there are many instances of these objects.

Ignore new, ignore .prototype they are just confusing notions. If you really want prototypical inheritance use Object.create but most of the time inheritance is completely overkill. (prototypical inheritance should only be used as an optimization technique).

When building classes just create objects and extend them.

var Walker = {
    walk: function() {}
}

var Eater = {
    eat: function () {}
}

var Dog = extend({}, Eater, Walker, {
    bark: function () {},
    sniffBehind: function () {}
})

function dog(dogName) {
    return extend({}, Dog, {
        name: dogName
    })
}

var steveTheDog = dog("steve")
console.log(steveTheDog.name === "steve")

Use any arbitrary arity extend function you want, _.extend, jQuery.extend, pd.extend, etc.

pd implements extend as follows

function extend(target) {
    [].slice.call(arguments, 1).forEach(function(source) {
        Object.getOwnPropertyNames(source).forEach(function (name) {
            target[name] = source[name]
        })
    })
    return target
}

With prototype, you can extend in a 'cleaner' way, because you are separating the logic inside your constructor function from the properties and methods that define your object.

var Mammal = function() { ... };
Mammal.prototype = {
  walk: function() { ... }
};

var Dog = function() { ... };

for (var prop in Mammal.prototype) {
  Dog.prototype[prop] = Mammal.prototype[prop];
}

Dog.prototype.bark = function() { ... };

However, the above without prototype could look like this:

var Mammal = function() {
  this.walk = function() { ... };
};

var Dog = function() {
  Mammal.apply(this);
  this.bark = function() { ... };
};

This way of extending Objects is however made irrelevant by modern JavaScript libraries like Underscore.js, or could be written much cleaner with the help of for example jQuery too.

You could use the word prototype to define some functionality across the application for particular type (Array, Function, Number of custom type)

For example you can extend all arrays with property sum:

const arrayPrototype = Array.prototype
Object.defineProperty(arrayPrototype, 'sum', { 
   get() { return this.reduce((a,b) => a + b, 0) }
})

When you've executed the chunk of code, all arrays have the property:

console.log([1,3,-1,10].sum) // prints 13

本文标签: When to use the word quotprototypequot in adding new properties to an object in javascriptStack Overflow