Asked  6 Months ago    Answers:  5   Viewed   43 times

I recently stumbled upon the Object.create() method in JavaScript, and am trying to deduce how it is different from creating a new instance of an object with new SomeFunction(), and when you would want to use one over the other.

Consider the following example:

var test = {
  val: 1,
  func: function() {
    return this.val;
  }
};
var testA = Object.create(test);

testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2

console.log('other test');
var otherTest = function() {
  this.val = 1;
  this.func = function() {
    return this.val;
  };
};

var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1 
console.log(otherTestB.val); // 2

console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2

Notice that the same behaviour is observed in both cases. It seems to me that the primary differences between these two scenarios are:

  • The object used in Object.create() actually forms the prototype of the new object, whereas in the new Function() from the declared properties/functions do not form the prototype.
  • You cannot create closures with the Object.create() syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.

Are the above statements correct? And am I missing something? When would you use one over the other?

EDIT: link to jsfiddle version of above code sample: http://jsfiddle.net/rZfYL/

 Answers

74

The object used in Object.create actually forms the prototype of the new object, where as in the new Function() form the declared properties/functions do not form the prototype.

Yes, Object.create builds an object that inherits directly from the one passed as its first argument.

With constructor functions, the newly created object inherits from the constructor's prototype, e.g.:

var o = new SomeConstructor();

In the above example, o inherits directly from SomeConstructor.prototype.

There's a difference here, with Object.create you can create an object that doesn't inherit from anything, Object.create(null);, on the other hand, if you set SomeConstructor.prototype = null; the newly created object will inherit from Object.prototype.

You cannot create closures with the Object.create syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.

Well, you can create closures, e.g. using property descriptors argument:

var o = Object.create({inherited: 1}, {
  foo: {
    get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
  }
});

o.foo; // "foobar"

Note that I'm talking about the ECMAScript 5th Edition Object.create method, not the Crockford's shim.

The method is starting to be natively implemented on latest browsers, check this compatibility table.

Tuesday, June 1, 2021
 
ramdemon
answered 6 Months ago
43

Some basics first.

With objects, you need to deal with their attributes. Ordinarily, we do instance.attribute. Sometimes we need more control (when we do not know the name of the attribute in advance).

For example, instance.attribute would become getattr(instance, attribute_name). Using this model, we can get the attribute by supplying the attribute_name as a string.

Use of __getattr__

You can also tell a class how to deal with attributes which it doesn't explicitly manage and do that via __getattr__ method.

Python will call this method whenever you request an attribute that hasn't already been defined, so you can define what to do with it.

A classic use case:

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

Caveats and use of __getattribute__

If you need to catch every attribute regardless whether it exists or not, use __getattribute__ instead. The difference is that __getattr__ only gets called for attributes that don't actually exist. If you set an attribute directly, referencing that attribute will retrieve it without calling __getattr__.

__getattribute__ is called all the times.

Tuesday, June 15, 2021
 
capsid
answered 6 Months ago
62

Javascript's inheritance is prototype based, so you extend the prototypes of objects such as Date, Math, and even your own custom ones.

Date.prototype.lol = function() {
 alert('hi');
};

( new Date ).lol() // alert message

In the snippet above, I define a method for all Date objects ( already existing ones and all new ones ).

extend is usually a high level function that copies the prototype of a new subclass that you want to extend from the base class.

So you can do something like:

extend( Fighter, Human )

And the Fighter constructor/object will inherit the prototype of Human, so if you define methods such as live and die on Human then Fighter will also inherit those.

Updated Clarification:

"high level function" meaning .extend isn't built-in but often provided by a library such as jQuery or Prototype.

Sunday, June 27, 2021
 
octern
answered 6 Months ago
79

More terminology (C, not C++): a prototype for a function declares the types of its arguments. Otherwise the function does not have a prototype.

void f();                      // Declaration, but not a prototype
void f(void);                  // Declaration and prototype
void f(int a, int b, float c); // Declaration and prototype

Declarations that aren't prototypes are holdovers from pre-ANSI C, from the days of K&R C. The only reason to use an old-style declaration is to maintain binary compatibility with old code. For example, in Gtk 2 there is a function declaration without a prototype -- it is there by accident, but it can't be removed without breaking binaries. The C99 standard comments:

6.11.6 Function declarators

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

Recommendation: I suggest compiling all C code in GCC/Clang with -Wstrict-prototypes and -Wmissing-prototypes, in addition to the usual -Wall -Wextra.

What happens

void f(); // declaration
void f(int a, int b, float c) { } // ERROR

The declaration disagrees with the function body! This is actually a compile time error, and it's because you can't have a float argument in a function without a prototype. The reason you can't use a float in an unprototyped function is because when you call such a function, all of the arguments get promoted using certain default promotions. Here's a fixed example:

void f();

void g()
{
    char a;
    int b;
    float c;
    f(a, b, c);
}

In this program, a is promoted to int1 and c is promoted to double. So the definition for f() has to be:

void f(int a, int b, double c)
{
    ...
}

See C99 6.7.6 paragraph 15,

If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions.

Answer 1

What happens at compile time in cases 1 and 2 when we call f with the correct arguments, wrong arguments and no arguments at all? What happens at run time?

When you call f(), the parameters get promoted using the default promotions. If the promoted types match the actual parameter types for f(), then all is good. If they don't match, it will probably compile but you will definitely get undefined behavior.

"Undefined behavior" is spec-speak for "we make no guarantees about what will happen." Maybe your program will crash, maybe it will work fine, maybe it will invite your in-laws over for dinner.

There are two ways to get diagnostics at compile-time. If you have a sophisticated compiler with cross-module static analysis capabilities, then you will probably get an error message. You can also get messages for un-prototyped function declarations with GCC, using -Wstrict-prototypes -- which I recommend turning on in all your projects (except for files which use Gtk 2).

Answer 2

If I declare f with arguments, but define it without them, will it make a difference? Should I be able to address the arguments from the function body?

It shouldn't compile.

Exceptions

There are actually two cases in which function arguments are allowed to disagree with the function definition.

  1. It is okay to pass char * to a function that expects void *, and vice versa.

  2. It is okay to pass a signed integer type to a function that expects the unsigned version of that type, or vice versa, as long as the value is representable in both types (i.e., it is not negative, and not out of range of the signed type).

Footnotes

1: It is possible that char promotes to unsigned int, but this is very uncommon.

Sunday, June 27, 2021
 
treeface
answered 6 Months ago
19

You're in luck. There's a very simple explanation:

Step One: Create an Object

Say you want to circle:

var circle = {};

Step Two: Give it Some Properties

A circle can be drawn, so let's create a property called draw:

circle.draw = function () {
    // drawing logic
};
  1. A property is simply a variable belonging to an object. A variable by itself is not a property.
  2. Properties and variables can hold any kind of data. Functions in JavaScript is data.
  3. When a property holds a function it's called a method.

Hence we have a method called draw belonging to the object circle.

Step Three: Extend an Object

Now I want a ball and a ball is kind of like a circle. So let's extend circle to create a ball:

var ball = Object.create(circle);
  1. Here we took the object circle and used it to create a new object called ball.
  2. The object ball now has all the properties of circle. So we can call ball.draw.
  3. The object circle is the prototype of ball.

Step Four: Give it Some Properties

Every ball has a radius, so let's give ours one:

ball.radius = 5;

Step Five: Create a Constructor

There's a problem here. Every time I want to create a new ball I extend circle and manually define the radius of the ball. Instead I would like a function to create the ball and give it a radius for me. This function is called a constructor:

function createBall(radius) {
    var ball = Object.create(circle);
    ball.radius = radius;
    return ball;
}

var baseball = createBall(5);
var basketball = createBall(10);

baseball.draw();
basketball.draw();

That's pretty much all you need to know about prototypes, objects and constructors.

Of course there's a lot more explanation but it's too much for one StackOverflow answer. I wrote a blog post on it, and I'm not planning to rewrite the same thing here. You should read my blog. It's worth it: http://aaditmshah.github.io/why-prototypal-inheritance-matters


Edit: Sure, I'll explain what happening in that code: http://cssdeck.com/labs/4ksohwya

First, scroll down to the very end:

window.addEventListener(
    'load',
    init(null),
    false);

When the page loads it executes init:

function init(images) {

    canvas= document.getElementById('s');
    ctx= canvas.getContext('2d');
    canvas.width= window.innerWidth;
    canvas.height=window.innerHeight;

    garden= new Garden();
    garden.initialize(canvas.width, canvas.height, 300);

    lerp(0,2000);

    time= new Date().getTime();
    interval = setInterval(_doit, 30);
}

The init function creates an instance of Garden (garden = new Garden();) and executes the initialize method of garden. It also calls the _doit function in intervals of 30 milliseconds.

initialize : function(width, height, size)  {
  this.width= width;
  this.height= height;
  this.grass= [];

  for(var i=0; i<size; i++ ) {
    var g= new Grass();
    g.initialize(
        width,
        height,
        50,      // min grass height 
        height*2/3, // max grass height
        20,     // grass max initial random angle 
        40      // max random angle for animation 
        );
    this.grass.push(g);
  }

  this.stars= [];
  for( i=0; i<this.num_stars; i++ )  {
    this.stars.push( Math.floor( Math.random()*(width-10)+5  ) );
    this.stars.push( Math.floor( Math.random()*(height-10)+5 ) );
  }
},

The initialize method of garden then creates some instances of Grass, calls their initialize methods and stores them in an array.

function _doit()    {

  ctx.fillStyle= gradient;
  ctx.fillRect(0,0,canvas.width,canvas.height);
  var ntime= new Date().getTime();
  var elapsed= ntime-time;
  garden.paint( ctx, elapsed );

  // lerp.
  if ( elapsed>nextLerpTime ) {
    lerpindex= Math.floor((elapsed-nextLerpTime)/nextLerpTime);
    if ( (elapsed-nextLerpTime)%nextLerpTime<lerpTime ) {
      lerp( (elapsed-nextLerpTime)%nextLerpTime, lerpTime );
    }
  }

}

The _doit function calls the paint function of garden, and the paint function of garden calls the paint function of each grass.


So here there are two constructors:

  1. Grass
  2. Garden

Here are the two prototypes:

  1. Grass.prototype
  2. Garden.prototype

Inside the init function we create a single instance of Garden (that's one object):

var garden= new Garden();

Inside the initialize method of garden we create multiple instances of Grass:

var g= new Grass();

That's it.

Thursday, August 5, 2021
 
Gil
answered 4 Months ago
Gil
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share