CLARIFICATION to moderator
As some moderators are a whee bit quick when scanning questions, I have to underline that I am not asking why to use Object.prototype.hasOwnProperty.call instead of myObject.hasOwnProperty. The devil is in the details.
The ESLint rule no-prototype-builtins forbids the use of built-ins coming from the Object prototype. It's there to provide you against code such as this:
function serverMethodToParseClientInput(json){
const o = JSON.parse(json);
if (o.hasOwnProperty("foo")) {
doSomethingMeaningful();
}
}
const stringFromClient = "{\"hasOwnProperty\":1, \"reason\": \"Crash your system\"}";
serverMethodToParseClientInput(stringFromClient);
Trying to call the method on objects created with null as their prototype will also fail, which I think is an even more reasonable thing to guard against. Example: const o = Object.create(null);.
Instead of obj.hasOwnProperty(field), you are supposed to use Object.prototype.hasOwnProperty.call(obj, field). I don't really see the difference between this and Object.hasOwnProperty.call(obj, field). Granted, Object is not its own prototype, so there is a difference of sorts, but since you can overwrite the props on either object, there isn't really much of a safeguard here, IMHO.
So I'm wondering if there is any point in reaching for the prototype of Object when Object will do?
Using Object.hasOwnProperty is weird because it makes it seem like you are using a static method like Object.assign().
It still works because if a property is not found on Object, it falls back to Function.prototype object. And, this object inherits from Object.prototype. So, if you have a custom implementation for Function.prototype.hasOwnProperty, then Object.hasOwnProperty will use that implementation instead of Object.prototype.hasOwnProperty
console.log( Object.hasOwnProperty === Object.prototype.hasOwnProperty ) // true
console.log( Object.getPrototypeOf(Object) === Function.prototype ) // true
console.log( Object.getPrototypeOf(Function.prototype) === Object.prototype ) // true
Function.prototype.hasOwnProperty = _ => 'custom implementaion in Function.prototype'
const obj = { prop: 10 }
console.log(Object.hasOwnProperty.call(obj, 'prop')) // custom implementaion
console.log(Object.prototype.hasOwnProperty.call(obj, 'prop')) // true
Note: The difference between Object.prototype.hasOwnProperty.call(myObj, prop) and myObj.hasOwnProperty(prop) is explained here
According to documentation here, Array.of() is an alternative to new Array() that lets you create an array literal at run-time even if it's only got one element (a case where new Array() breaks down). I like that, and have replaced most new() calls on my custom Array subclass with .of(), but since converting I am now finding errors when I try certain things.
The link claims that .of() is equivalent to this:
Array.of = function() { return Array.prototype.slice.call(arguments); }
To check if that's true, I wrote this test to compare the real of() with that polyfill:
Array.of_polyfill = function( ...args ) // Fake of().
{
console.log( args );
return Array.prototype.slice.call( args );
}
class A extends Array // So we can peek inside what the real of() is doing.
{
constructor( ...args ) // Using of() on an "A" calls this constructor.
{
console.log( args );
return Array.prototype.slice.call( args );
}
}
var a1 = A.of ( 5,6,7,8 );
var a2 = A.of_polyfill( 5,6,7,8 );
Both a1 and a2 ultimately contain the correct value [5,6,7,8], but internally working with the two lines is inconsistent, as shown in the console log:
[4]
(4) [5, 6, 7, 8]
From the first line there, calling .of() did not result in the whole literal being in scope, but just [4], as if internally it's calling the A constructor to preallocate four slots, which is not something the polyfill mentions it does.
I care about the internal behavior because one of the main suggested uses of of() is custom Array subclasses like my A above, to allow me to specify array literals of my new type. To that end my A constructor should be able to do manual stuff with the literal (the arguments that were passed in) but it just can't access it due to the above. Is there some other way that gives me access?
Is that suggested polyfill for of() accurate or am I misunderstanding some aspect of JavaScript and constructors?
Minor point... Array.of lets you create an Array, not an "Array literal". The "literal" refers to the syntax that lets you describe and create an array with its initializing data if any, like var a = [1, 2, 3].
Ultimately, the docs make no claim of complete equivalence of the polyfill. MDN is a wiki, so if the polyfill can be improved, then anyone is welcome to contribute changes. Keep in mind though that it will be expected to work in ES5 and lower, so approaching the full subclassing behavior will be much more work.
So we are mixing multiple things in the question. You are using spread operators where you shouldn't, and there seems to be a misunderstanding about what native code is. Array.of is a static function; creating a constructor doesn't mimic its' behaviour. You can however override the static method and use the spread operator. In this case, it would be
class B extends Array {
static of(...args) {
return args;
}
}
Or using arguments
class A extends Array {
static of() {
return Array.prototype.slice.call(arguments);
}
}
Or just
class A extends Array {
static of() {
return Array.from(arguments);
}
}
Again, your "polyfill" does too much. By using the spread operator, you'll already get an array. This would suffice:
Array.of_polyfill = function (...args) {
return args;
};
Below you'll get three times the same array:
Array.of_polyfill = function (...args) {
return args;
};
class A extends Array {
static of() {
return Array.prototype.slice.call(arguments);
}
}
class B extends Array {
static of(...args) {
return args;
}
}
var a1 = A.of(5, 6, 7, 8);
var a2 = A.of_polyfill(5, 6, 7, 8);
var b = B.of(5,6,7,8);
console.log(a1);
console.log(a2);
console.log(b);
Here's the function declaration in ecmascript6:
/**
#param {...null} items
#static
#return {Array}
*/
Array.of = function(items) {};
You're assuming that your constructor function is called with the arguments that you pass to A.of. That's wrong.
Let's take a look at the specification of Array.of:
Let len be the actual number of arguments passed to this function.
Let items be the List of arguments passed to this function.
Let C be the this value.
If IsConstructor(C) is true, then
a. Let A be ? Construct(C, « len »).
Else,
a. Let A be ? ArrayCreate(len).
[...]
In our case, "C" is A, the class that you defined, which is a constructor. A new instance of A is created, the constructor is called with "len", the number of arguments that we passed to Array.of.
Normally, the constructor would be Array, so Array(len) would be called. Here, A(4) is called. Thus, ...args is [4].
After that, the algorithm will fill the newly constructed array with the correct values.
That means that the results of Array.of and Array.prototype.slice.call are equivalent, but not the way they work internally.
after some tests, it seems that the actual implementation of Array.of() is something like this:
Array.of = function() {
//check wether `this` is a constructor, otherwise fall back to the `Array` constructor
//maybe there's a better way to determine wether `this` is a constructor _before_ calling it.
var constructor = typeof this === "function" && "prototype" in this? this: Array,
result = new constructor(arguments.length);
for(var i=0; i<arguments.length; ++i)
//FF and Chrome use defineProperty()
Object.defineProperty(result, i, {
value: arguments[i],
writable: true,
enumerable: true,
configurable: true
})
//Edge simply assigns the values
//result[i] = arguments[i];
//didn't test IE, Opera, Safari or any mobile browser
//and again, setting the length after the items have been defined
result.length = arguments.length;
return result;
}
Why just "something" - didn't you read the spec?
No, this was driven/deduced by the actual behaviour in the browser. And only "something like", because I might have missed something.
Especially the part with determining wether this is an actual constructor is something I'm not entirely satisfied with. It may produce a false match (and then throw) if you take an arrow function and manually add a property named prototype; but that kind of hacks should be pretty rare.
"After some tests" - what did you test?
how the function behaves in different environments,
attached to functions, to consturctor functions, to functions that ain't constructors, to general objects,
wether there's a difference between attaching it to some Object, or calling it with Function#call,
wether and what arguments are passed to the functions constuctor.
how it behaves if constructor and constructor.prototype.constructor are not the same,
wether it needs Array in the prototype-chain (to fall back to the Array-constructor),
Basically how it determines the constructor function to initialize the returned object
what happens if I predefine the indices and the length-proeprty (it throws an error if the property ain't configurable:true, but only in FF and Chrome)
I am fully aware of other very similar posts about object.create but I really cannot arrive to answer on this particular question.
I saw a code once where it looks like it was using object.create to create new prototype and then adding back to constructor
function blah(){
// typical constructor
}
blah.prototype = Object.create(somethingelse.prototype);
blah.prototype.constructor = blah;
Something like that .. and I tried that in chrome dev tool but did not see them as equal.. Now trying to see what that code I did see was trying to accomplish? I assume there is more difference in Object create and new(than just missing constructor?)
function blah(){
//...
}
undefined
function somethingelse(){
//
}
undefined
somethingelse.prototype = {
// something else
}
Object {}
blah.prototype = Object.create(somethingelse.prototype);
Object {}
blah.prototype.constructor = blah;
blah(){
//...
}
blah == somethingelse;
false
You've created two different objects (blah and something).
I think you are confused about what inheritance means.
when you compare (==) 2 objects the reference is being evaluated - and it is different.
Similar to this question, I am following Douglas Crockford's JavaScript, The Good Parts. In chapter 4, he talks about augmenting types, which I find very confusing. He writes this sample code:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Number.method('integer', function ( ) {
return Math[this < 0 ? 'ceil' : 'floor'](this);
});
He then tests the new integer method:
document.writeln((-10 / 3).integer()); // -3
I don't understand the syntax of this.prototype[name] (in particular, the brackets) or Math[this < 0 ? 'ceiling' : 'floor'](this) (again, the brackets and also where Math came from). More importantly, can someone explain how the code in general works, and why the test code works?
By extending Function.prototype you add a method available to every function. Remember that functions in JavaScript are objects, and as such they can have properties and methods eg. call or apply.
The method function method lets you add a method to the prototype of any given function. Number is a function; the constructor of numbers, which has a prototype. Functions that you add to the prototype are available for all instances of the object, in this case a number.
Math is a built-in object in JavaScript, by using bracket notation you can dynamically access the property of an object. Remember that object keys are just strings, even if you don't write them as string, they can still be accessed with bracket notation with a string, for example:
var obj = {
key: 'hello'
};
var k = 'key';
obj[k]; //=> 'hello'
In the case of Math it's simply deciding if it should use ceil (not "ceiling") or floor based on a condition, you could write like this:
if (this < 0) {
Math.ceil(this);
} else {
Math.floor(this);
}
Javascript is weird.
In most languages you do foo = someObject.someMember and JS allows that too.
But it also lets you do foo = someObject["someMember"] which seems silly... until you realize that the string could be replaced with a variable
var memberName="someMember"
foo = someObject[memberName]
Now you're able to write very dynamic code that can leverage object members without knowing the names of those members when you write the code. This is what the code you posted is doing. It feels dirty at first but that feeling will pass ;)
I am using jQuery 1.5 in my open source project and following line is also present in my own Javascript code:
/**
* Object.isEmpty()
*
* #returns {Boolean}
*/
Object.prototype.isEmpty = function ()
{
/**
* #deprecated Since Javascript 1.8.5
* #see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object
*/
if ( this.__count__ !== undefined )
{
return this.__count__ === 0 ? true : false;
}
/* Less-aesthetic method, if above method fails */
for ( var property in this )
{
if ( this.hasOwnProperty(property) )
{
return false;
}
}
return true;
};
which just extends Object.prototype adding isEmpty() method to it [that checks whether the object is empty or not). Because of this addition, I am getting "c.replace is not a function" error in my Firebug console; and my research on the web lead me to jQuery bug tracker message, where I "learned" that extending Object.prototype not only breaks jQuery, but also is bad coding practice. My question is, why?
ECMA-262 5th Edition (and JavaScript 1.8.5) has ways to do it through the Object.defineProperty and Object.defineProperties methods, by setting the enumerable field of the property to false. That is available in Chrome 5, Safari 5, Firefox 4 and Internet Explorer 9 or any recent server side implementation that uses V8 (like Node.js).
Basically, that because extending Object.prototype breaks the for ... in idiom.
In Javascript, if you have an object:
var obj = { "foo": 0, "bar": 42 };
You can iterate over its members by doing:
for (var key in obj) {
// Do Something.
}
Extending Object.prototype will result in the extended members being present in all object instances, so the code above would iterate over more keys than foo and bar, with probably unexpected results.
You can find a fiddle demonstrating the problem here.
1) How to add (extend) additional methods (not properties) to Object?
As long as third party code is running on your page you shouldn't.
2) If you can distinguish immediate children of your object from global ones, with help of hasOwnProperty(), why it is a bad coding?
Because there's a likelihood that other programmers are lazy, and you break their code. It is a good practice not to modify what you don't own. Object.prototype is one of these things.
Use MyLib.isEmpty(obj), or isEmpty(obj) inside your own scope so there's no chance to collide.