Js tips I can't remember
__proto__
VS prototype
__proto__
is the actual object that is used in the lookup chain to resolve methods and others.prototype
is the object that is used to build__proto__
when creating an object withnew
.
The “cool kids” in JavaScript would generally pronounce
__proto__
as “dunder proto”.
https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript
( new Foo ).__proto__ === Foo.prototype; // true
( new Foo ).prototype === undefined; // true
{}
VS Object.create(null)
Object.create(null)
can create a ‘pure’ empty object that is without the delegation to Object.prototype
.
let obj1 = {};
let obj2 = Object.create(null);
console.log(obj1.__proto__); // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(obj2.__proto__); // undefined
Computed Property Names
ES6 adds computed property names, which is helpful when declaring objects using the object-literal syntax.
var prefix = "foo";
var myObject = {
[prefix + "bar"]: "hello",
[prefix + "baz"]: "world"
};
myObject["foobar"]; // hello
myObject["foobaz"]; // world
Dangerous Function.prototype.name
comparison
Sometimes we may spectify a function by comparing the function name:
function Foo() {};
let foo = new Foo();
if (foo.constructor.name === 'Foo') {
console.log("'foo' is an instance of 'Foo'");
} else {
console.log('Oops!');
}
It may behave unexpectedly after building because most build tools compress the code to forms like:
function a() {};
let b = new a();
if (b.constructor.name === 'Foo') {
console.log("'foo' is an instance of 'Foo'");
} else {
console.log('Oops!');
}
A more robust way of performing object property check
Normally we use hasOwnProperty()
checks to see if object has the property or not. But consider objects created by:
// this will not consult the [[Prototype]] chain
let obj = Object.create(null)
Such object does not link to Object.prototype
, thus obj.hasOwnProperty(...)
would fail and raise error.
We can use a more robust way to perform property check:
Object.prototype.hasOwnProperty.call(obj,"a") //false
Or:
// this will check the current object or any higher level of the [[Prototype]] chain
"a" in obj
for...in
vs for...of
The for..in
loop iterates over the list of enumerable properties on an object (including its [[Prototype]]
chain).The for...of
iterate over the values directly instead of the array indices (or object properties). It asks built-in or custom @@iterator
of the thing to be iterated.
let arr = ['a', 'b', 'c']
arr.name = 'foo'
arr // ["a", "b", "c", name: "foo"]
for (key in arr)
console.log(key) // 0 1 2 name
for (value of arr)
console.log(value) // a b c
“(Prototypal) Inheritance”
When writing “prototype style” code like implementing Parent-Child class inheritance:
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
function Bar(name,label) {
Foo.call( this, name );
this.label = label;
}
// Then trying to build a family with Foo and Bar
// ...
A common mis-conception/confusion here is that either of the following approaches would also work, but they do not work as you’d expect:
// doesn't work like you want!
Bar.prototype = Foo.prototype;
// works kinda like you want, but with
// side-effects you probably don't want :(
Bar.prototype = new Foo();
the right way is:
// "make a new 'Bar dot prototype' object that's linked to 'Foo dot prototype'."
// pre-ES6
// throws away default existing `Bar.prototype`
Bar.prototype = Object.create( Foo.prototype );
// ES6+
// modifies existing `Bar.prototype`
Object.setPrototypeOf( Bar.prototype, Foo.prototype );
reference: You-Dont-Know-JS: “(Prototypal) Inheritance”