javascript - Should functions be attached to object or its prototype? - Stack Overflow

I am learning javascript and I am wondering about the concept of functions and prototypes inside an obj

I am learning javascript and I am wondering about the concept of functions and prototypes inside an object.

My understanding of the concept

As I understand it, functions should be attached to object's prototype in order to allocate less memory.

For example (if what I said is true), both version will do the same job but second version will allocate less memory:

var collectionOfObjects = [];
for(var i=0; i<1000; i++){
    collectionOfObjects.push({id: 2, sayHi: function(){console .log('hi')}})
}
//vs
function Foobar(id){
    this.id = id || 0;
}
Foobar.prototype.sayHi = function(){
    console.log('hi');
}
var otherCollection = [];
for(var i=0; i<1000; i++){
    otherCollection.push(new Foobar());
}

Question

//this attaches sayHi function to the object instead of its prototype
var foobar = {
    id: 0,
    sayHi: function(){
        console.log('Hi');
    }
}

Since I shouldn't use __proto__, how do I attach sayHi function to foobar's prototype instead of foobar object? I assume that adding sayHi to Object.prototype isn't a good solution as it would add sayHi function to every object.

I am learning javascript and I am wondering about the concept of functions and prototypes inside an object.

My understanding of the concept

As I understand it, functions should be attached to object's prototype in order to allocate less memory.

For example (if what I said is true), both version will do the same job but second version will allocate less memory:

var collectionOfObjects = [];
for(var i=0; i<1000; i++){
    collectionOfObjects.push({id: 2, sayHi: function(){console .log('hi')}})
}
//vs
function Foobar(id){
    this.id = id || 0;
}
Foobar.prototype.sayHi = function(){
    console.log('hi');
}
var otherCollection = [];
for(var i=0; i<1000; i++){
    otherCollection.push(new Foobar());
}

Question

//this attaches sayHi function to the object instead of its prototype
var foobar = {
    id: 0,
    sayHi: function(){
        console.log('Hi');
    }
}

Since I shouldn't use __proto__, how do I attach sayHi function to foobar's prototype instead of foobar object? I assume that adding sayHi to Object.prototype isn't a good solution as it would add sayHi function to every object.

Share Improve this question edited Feb 26, 2020 at 9:42 askstackoverflow asked Feb 25, 2020 at 22:09 askstackoverflowaskstackoverflow 3014 silver badges13 bronze badges 3
  • 1 You should segregate your questions – Ele Commented Feb 25, 2020 at 22:11
  • 4 You should also probably check out some modern tutorials, because these are questions that make sense back in the "we only have functions and prototypes" days, but these days (unless you already know what you're doing) there's no good reason to not just use modern class syntax instead, which makes these questions entirely moot: functions go in your class, and there is no "constructor function" that you manually attach a prototype to, so there is nothing to decide. There's only one place things go. – Mike 'Pomax' Kamermans Commented Feb 25, 2020 at 22:15
  • 1 @Mike'Pomax'Kamermans I am asking this question just in case I have to work with some legacy code. But I am gald to hear that this isn't a problem when using class syntax – askstackoverflow Commented Feb 25, 2020 at 22:18
Add a ment  | 

3 Answers 3

Reset to default 3

The prototype chain is setup via the new keyword, a class or Object.create(). Either way, it's set when the object is created.

So you already know one way, which is is to add functions to the prototype of a constructor function and instantiate with new.

The modern way would be to use a class, but you specifically mention legacy code here, so I'm going to assume that's out for purposes of this discussion.

The last way is to use Object.create() which gives you an object with some prototype:

var myProto = {
  // There is only one of this function, ever.
  sayHi: function() {
    console.log('hi');
  }
}

var otherCollection = [];
for(var i=0; i<1000; i++){
    var obj = Object.create(myProto)
    obj.id = i // or other custom setup.
    otherCollection.push(obj);
}

That said, in modern javascript engines having unique functions per object is not a big deal. I've worked on some pretty large javascript apps and memory usage due to the number of function instances has not ever been a performance bottleneck at all.

In modern React with functional hooks, for instance, it would be incredibly cumbersome (if not impossible in some cases) to avoid creating hundreds of new functions on every render. It's designed to be that way and it still performs very well. And if it doesn't perform well, it's never due to too many functions.

You understanding is accurate. Objects created with the obj = { ... } notation inherit from Object.prototype, and changing their prototype with __proto__ or its modern equivalent Object.setPrototypeOf is especially slow in all JavaScript implementations. But there is another way to set the prototype of an object on creation.

The Object.create(proto) function lets you create an object which inherits from proto, so you don't have to use the confusing Foobar.prototype syntax and the magical new operator.

let Foobar = {
  id: 0,
  sayHi: function() {
    console.log('Hi');
  }
};

let obj = Object.create(Foobar);
obj.id = 1;
obj.sayHi(); // Hi

If you had a dozen properties to set on obj, having to assign each property manually after the object creation would be a bit lame, but you can use the nifty Object.assign function for that:

let Elephant = {
  name: 'an elephant',
  ears: 'boring',
  sayHi: function() {
    console.log(`Hi, I am ${this.name} and my ears are ${this.ears}.`);
  }
};

let dumbo = Object.assign(Object.create(Elephant), {
  name: 'Dumbo',
  ears: 'AWESOME'
});

dumbo.sayHi(); // Hi, I am Dumbo and my ears are AWESOME.

If you wanted to create a bunch of objects and give them all the same 3 methods, you could therefore replace this:

let t = { name: "Tom", eat, sleep, repeat };
let g = { name: "Garfield", eat, sleep, repeat };

with this:

let protoCat = { eat, sleep, repeat };
let t = Object.assign(Object.create(protoCat), { name: "Tom" });
let g = Object.assign(Object.create(protoCat), { name: "Garfield });

It would be more practical, however, to have some kind of constructor function instead. Using Object.assign for a single property is a bit overkill so I'll simplify this next example:

function cat(name) {
    const c = Object.create(protoCat);
    c.name = name;
    return c;
}

let t = cat("Tom");
let t = cat("Garfield");

Note that you don't call cat with new, since cat builds its own object. If you tried calling cat with the new operator here, it would create an object which inherits from the empty cat.prototype, but that object would eventually be discarded since cat has a return value.

UPDATE: While my answer gives a pretty plete explanation of how prototype works, I feel like I failed to point out that you don't have to use it at all. You could very well just assign the methods every time.

function cat(name) {
    return { name, eat, sleep, repeat };
}

Sure, all your cats now hold a reference to all their methods, which might take a tiny bit of extra memory, but writing hard to maintain code to save a few bytes isn't what I'd call an optimization.

JavaScript likes to treat objects like data, in a way similar to lisp, and if you just pretend it has classes, you might end up wishing you were using another language.

As Mike said in the ments, pseudo-classical inheritance has been deprecated by classes in ES2015 (ES6) and beyond, so Foobar.prototype should be discarted.

You allocate less memory by reusing a function definition instead of defining the function for every object you create. This can be done with Footbar.prototype, plain prototypes, classes, or a simple function definition without inheritance. As usual, JavaScript provides many ways to achieve the same goal, it is up to you which one you choose.

Your question already contains a pseudo-classical way to do it, you can also use a class or a plain prototype:

var footbarProptotype = {
    sayHi: function() {
        console.log('Hi');
    }
};

var footbar = Object.create(footbarProptotype);

footbar.sayHi()

And you can reuse the function definition yourself without using any kind of inheritance

function sayHi(){
    console.log('hi');
}

var collectionOfObjects = [];

for(var i=0; i<1000; i++){
    collectionOfObjects.push({ sayHi: sayHi });
}

The memory optimization only es from defining the function only once and reusing that definition every time you can.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745346849a4623589.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信