added cactus theme files
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
---
|
||||
title: Js tips I can't remember
|
||||
date: 2019-03-22 09:00:00
|
||||
tags:
|
||||
- JavaScript
|
||||
category: tech
|
||||
keywords:
|
||||
- Javascript
|
||||
- ES2015
|
||||
- ES6
|
||||
---
|
||||
|
||||
## `__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 with `new`.
|
||||
|
||||
>The "cool kids" in JavaScript would generally pronounce `__proto__` as "**dunder proto**".
|
||||
|
||||
[https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript](https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript)
|
||||
|
||||
```javascript
|
||||
( new Foo ).__proto__ === Foo.prototype; // true
|
||||
( new Foo ).prototype === undefined; // true
|
||||
```
|
||||
<!--more-->
|
||||
|
||||
## `{}` VS `Object.create(null)`
|
||||
|
||||
`Object.create(null)` can create a *'pure'* empty object that is without the delegation to `Object.prototype`.
|
||||
```javascript
|
||||
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.
|
||||
```javascript
|
||||
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:
|
||||
```javascript
|
||||
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:
|
||||
```javascript
|
||||
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:
|
||||
```javascript
|
||||
// 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:
|
||||
```javascript
|
||||
Object.prototype.hasOwnProperty.call(obj,"a") //false
|
||||
```
|
||||
Or:
|
||||
```javascript
|
||||
// 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.
|
||||
```javascript
|
||||
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:
|
||||
```javascript
|
||||
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:
|
||||
```javascript
|
||||
// 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:
|
||||
```javascript
|
||||
// "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"](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch5.md#prototypal-inheritance)
|
||||
Reference in New Issue
Block a user