Role of 'prototype' property amidst design of `function` type object?

人走茶凉 提交于 2020-01-03 05:09:22

问题


As per the understanding, The main purpose for the existence of prototype property in a function type object is to allow properties/methods sitting under prototype to get inherited by other objects. This enables prototypical inheritance.

Considering window['Number'] function type object,

In general, Idea is to understand the thought process on what comes under prototype. So. I would like to take a specific example i.e., Number, with below questions.

From design perspective, how would I understand,

1)

why parseFloat()/parseInt()/isFinite()/isInteger()/isFinite()/isNaN()/NEGATIVE_INFINITY/NaN

are part of function type object Number?

2)

why methods toExponential()/toFixed()/toPrecision() are part of Number.prototype object?

Note: Have an idea on class based inheritance using java syntax, where both static/instance members can be inherited.


回答1:


If you understand classic class based inheritance, then Number.parseFloat is a static class method, while Number.prototype.toFixed is an instance method. The "class methods" do not need an instance of Number to work, you simply call them directly as Number.parseFloat(foo). Instance methods on the other hand require an instance first:

var foo = new Number(bar);
foo.toFixed();



回答2:


Properties declared on the prototype object are visible from all instances. Thus:

var n1 = new Number(1), n2 = new Number(2);

Those are two instances of Number, and via each instance it's possible to call the functions on the Number prototype:

alert( n2.toExponential() ); // "2e+0"

Because of the way that function invocation works in JavaScript, the .toExponential() function in that example will be invoked with this referring to the number instance used to make the function call — n2 in this case.

Now, the .toExponential() function could have been defined as a property of the Number constructor itself, but then the parameter would have to be passed explicitly (like Number.toExponential(2)). That's not how the runtime was designed, however. As with so many "why?" questions about how languages and APIs work, it's ultimately just a design preference on the part of the language designers. It should be clear that something like .parseFloat() would really not make any sense as a prototype method, because the whole point of .parseFloat() is to turn something that's not a number into a number. (It could have been added to one or more other prototype objects, but again the preference of the language designers was to just make it a callable function on the Number constructor itself; that's a recent ES6 addition to the spec of course.)

Finally note that in the particular case of the Number constructor, it's pretty rare that you'd actually explicitly instantiate a number object. Generally that happens implicitly when a number primitive value is used with the . or [ ] operators as if it were an object reference. Primitives are not objects, but the language automatically wraps a primitive value in a Number object in those cases, so the first example above would work the same if it were written like this:

var n2 = 2;
alert(n2.toExponential());

The variable n2 has a plain primitive 2 in it, but that will be wrapped in a Number instance in order to allow the method call.




回答3:


I do not know whether you mean a program design perspective or a language (core library) design perspective, so I'll try to answer both.

Before we begin, please forget "class" or "instance" or "static". JavaScript is not class based. There only object and inheritance.

Now, let's see the object diagram.

Note that new Number does not inherits Number.

Neither prototype nor constructor is an inheriting relationship.

This means number instances inherits toExponential, toFixed, etc. but does not inherits parseFloat, parseInt etc. So you call them like Number.parseFloat() and new Number(n).toFixed().

This is how JS is designed. If you don't like it you can design your own Number library.

For example, you may create your own Number that has toFixed methods on the Number object rather than on its prototype object, like this:

var SheepyNumber = {
   toFixed: ( n ) => Number.toFixed( n )
}
SheepyNumber.toFixed( 3.14159265358979323846 ) // Evaluates to '3'

Do not add toFixed to Number object. It may work for now, But if later specifications introduces this function with any different in parameter or logic, then your program may break when you use the standard implementation, or a third party library may break if you keep your own implementation. Either way, you lost.

Which leave us the question, why does JS not put toFixed to Number, like we just did, but instead put toFixed to Number.prototype?

The obvious answer is this is more object-oriented. Since new Number has an internal value property, toFixed can take that value, instead of taking in an extra argument.

The real answer is no one knows. JavaScript copied Java for its core API - you can find most of these methods in the Java Float class. Some of these Java methods are instance methods (corresponds to methods on Number.prorotype), some are static (corresponds to methods on Number), but most are both - including a counterpart of toFixed.

Why JavaScript did not put isFinite or isNaN to Number.prototype?

Why did no browsers implement toFixed on Number which can co-exists with the one on Number.prototype, during the first browser war that shaped the JavaScript as we know now?

Language design is an art. And you may not always know who is responsible or why, because it has been shaped by many hands.



来源:https://stackoverflow.com/questions/32521184/role-of-prototype-property-amidst-design-of-function-type-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!