What is the difference between the "in" operator and the "hasOwnProperty" method in Javascript?

Asked

Viewed 146 times

4

An unexpected behavior (at least for me) occurred with the following excerpt of code that I will demonstrate below:

const str = new String('olá SOpt');

console.log('Usando "in"', 'length' in str); // true
console.log('Usando "hasOwnProperty"', str.hasOwnProperty('length')); // true

Note that so far, nothing new, worked as expected, but the code below made me have doubts:

const str = 'olá SOpt';

console.log('Usando "hasOwnProperty"', str.hasOwnProperty('length'));
console.log('Usando "in"', 'length' in str); // vai lançar um erro

If you run the code above, the second console.log will have a mistake saying something like:

Uncaught Typeerror: Cannot use 'in' Operator to search for 'length' in olá Sopt

That’s when the doubts arose...I hoped it would work normally the use of the in because a string has a property length

const str = 'olá SOpt';

console.log('Usando "hasOwnProperty"', str.hasOwnProperty('length'));
console.log('lenght: ', str.length); // 8

Only using 'length' in str returned an error. Obviously, my line of reasoning in finding that in and hasOwnProperty were the same thing, only one way "dry" of writing, had failed:

const str = new String('olá SOpt');

console.log('Usando "in"', 'length' in str);
console.log('Usando "hasOwnProperty"', str.hasOwnProperty('length'));

const str2 = 'olá SOpt';

console.log('Usando "hasOwnProperty"', str2.hasOwnProperty('length'));

try {
  console.log('Usando "in"', 'length' in str2); // ocorre um erro
} catch (error) {
  console.log(
    `Erro ao usar o "in" em: console.log('Usando "in"', 'length' in str2);`,
  );
}

Questions

  • What is the difference between the operator in and the method hasOwnProperty?
  • When using one or the other?
  • Why the in in string declared using new String('foo') works, but does not work with 'foo'?

Just out of curiosity, I tried to use in structure Map, but apparently, only .has() works for the same:

let map = new Map();

map.set('name', 'Cardeal');

console.log('name' in map);              // false
console.log(map.hasOwnProperty('name')); // false
console.log(map.has('name'));            // true

1 answer

5


What is the difference between the operator in and the method hasOwnProperty? When using one or the other?

Operator in

The operator in can be used in objects to verify the existence of some property. The in runs through the entire prototyping chain to find the property, returning falso otherwise.

The operator in verifies the existence of any type of property, which includes properties whose key is a Symbol and non enumerable properties.

Use it when you want to check if a given object has its own property, or inherited via a prototype chain.

Method Object.prototype.hasOwnProperty and function Object.hasOwn

Already the method hasOwnProperty is defined in the prototype of the manufacturer Object. Thus, almost every Javascript value has this method since almost all native objects of the language extend, prototypically, Object.prototype.

The hasOwnProperty works in a similar way to in. However, it does not traverse the prototype chain. Only the properties of the "object itself" (from English, Own Property) are swept for verification.

Utilize hasOwnProperty when you want to check if the object in question has a certain property, disregarding prototypically inherited.

The function Object.hasOwn, introduced recently in the language, has the same semantic behavior when compared to the method hasOwnProperty. If the environment supports, it is preferable to use Object.hasOwn for reasons here explicit.*


The operator in only works with objects

The error mentioned in the question, such as:

Cannot use 'in' operator to search for 'length' in [...]

It occurs in view of the operator in works only in objects. When you try to apply it directly to a primitive (such as string, number, symbol etc.), the error in question will be launched, since the values are not an object, but a primitive value.

That’s why:

let strObject = new String('oi');
let strPrimitive = 'oi';

console.log('length' in strObject); // -> true    Não lança erro.
console.log('length' in strPrimitive); // Error   Lança erro.

When using new String, occurs the instantiation of a new string object. Therefore, in will work (since it has been applied to an object). However, when trying to apply in in strPrimitive (which was assigned to the value assessed by the literal 'oi', which is a primitive string), the error is thrown.

Of specification of language:

RelationalExpression : RelationalExpression in ShiftExpression

  Let lref be the result of evaluating RelationalExpression.
  Let lval be ? GetValue(lref).
  Let rref be the result of evaluating ShiftExpression.
  Let rval be ? GetValue(rref).
  If Type(rval) is not Object, throw a TypeError exception.
  Return ? HasProperty(rval, ? ToPropertyKey(lval)).

Note that the algorithm explicitly throws an error in the case of the second operand of in is not from guy object.

It is worth noting that the operator in can still perform the calls private Brand checks, that are not possible with Object.prototype.hasOwnProperty or Object.hasOwn. However, this goes beyond the scope of this answer. See more about this here and here.


Notes and concluding remarks

  1. It is worth noting that primitives (like string) can have access to the methods of the respective constructor by a Javascript engine called "Primitive wrapping". This means that, internally, it is a primitive, but that it is "surrounded" by an object, which allows access to the methods (such as itself hasOwnProperty, that comes from prototypical inheritance). For some reason language was made to consider access to primitive properties as something doable, but it does not allow to apply them to in. It’s confusing, but it’s the language. That we accept.
    More details on these other answers.

  2. In relation to Map, so much in how much hasOwnProperty cannot be used to verify the existence of a value per key on the map in view of the operation of the Map is different from a "normal object". The values of the Map are not stored as if they were mere properties of an object, that is, the map values are not exactly "properties". Therefore, the existence of these values cannot be tested by hasOwnProperty or in, who work with estates.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.