The werid this

2020-08-13

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

The weird This

  • This was property of a certain context, that is to say, in global context or a function contex

    The ECMA 2015

    expression this

Note:

A Reference is a resolved name binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var foo = (){console.log(this.value)};
=======>
var fooReference = {
base: EnvironmentRecord,
name: 'foo',
strict: false
};

var foo = {
bar: function () {
return this;
}
};
foo.bar();
========>
var BarReference = {
base: foo,
propertyName: 'bar',
strict: false
};
  • In strict mode , This in global context refers to undefined, in non-strict mdoe it refers to the window object
  • Inside a function , This pointer was determined when the function was invoked:
    • During the creation phase the this was initialized as undefined
    • Then during the execution phase the this
    • Therefore, whom the This pointer points to, is subjected to how the funciton was called, which means what is on the left of the () operator
  • A function can be invoked in the following ways by different CallExpression
    • Function invocation => CallExpression Arguments
    • Method invocation => CallExpression [ Expression ] CallExpression . IdentifierName
    • Constructor invocation => new MemberExpression Arguments
    • Indirect invocation =>MemberExpression Arguments

Function inovation & method invoation

  • When a function is called as a method of an object, the object is passed to the function as its this value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let value = 'window';
function foo() {
console.log(this.value)
}
let obj={
value:'obj',
foo(){console.log(this.value)}
inner:{
value:'inner',
foo
}
}
function doFoo (fn) {
fn()
}

doFoo(obj.foo)
foo() //window
obj.foo()//'obj'
obj.inner.foo()//'inner'
(obj.foo=obj.foo)()//'window'
doFoo(obj.foo) //window
  1. foo()

    ​ foo->MemberExpression=>ref: foo => declaritive enviorment record => global object

  2. obj.foo()

    ​ obj.foo => ref=> base=>obj

  3. obj.inner.foo()

    ​ obj.inner.foo => base => inner

  4. (obj.foo=obj.foo)()

    ​ ‘=’ assignmetn oprator ->call GetValue -> return a value not a reference => global

  5. doFoo(fn)=>fn()

    ​ arguments: fn = obj.foo => call GetValue -> return a value not a reference => global

Constructor invocation

According to ECMA2015, the new operator would call the [[construct]] inner method of a function

​ Let obj be a newly created native ECMAScript object.

​ Let result be the result of calling the [[Call]] internal property of F, providing obj as thethisvalue and providing the argument list passed into [[Construct]] as args.

​ If Type(result) is Object then return result.

​ Return obj.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var name = 'window'
function Person (name) {
this.name = name
this.foo = function () {
console.log(this.name)
return function () {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')

person1.foo.call(person2)()//person2 window
person1.foo().call(person2)//person1 person2

Arrow function

Read More

Promise A+

2020-08-12

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

[toc]

Promise A+ step by step

https://promisesaplus.com/

A promise represents the eventual result of an asynchronous operation

State Machine

States: ‘pending’;’fulfilled’;’rejected’;

1
2
3
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

executor

executor will be executed immediately, it takes two function as parameters

1
2
3
4
5
6
7
8
9
10
11
12
13
function Promise(executor){
this.state = PENDING;
function resolve()
function reject()
//executor(resolve, reject);
//user input the executor, which may cause error, wrap it with try and catch
try{
//the executor would synchronously run using the resolve and reject function created in the constructor
executor(resolve, reject);
}catch(error){
reject(error);
}
}

resolve & reject function

these two function are to

  • pass the async results outside for chaining which avoids nested callback
  • change the state of current promise instance;

Only when the state is PENDING, a transition can be made;

1
2
3
4
5
const resolve=(value)=>{
if(this.state === PENDING){
this.state = FULFILLED;
}
}

then

chain revoke => Promise.prototype.then(onRes,onRej)

Methods in then can obtain the value passed from the promise instance => use this =>pass the value/reason out by passing them into the resolve/rejection function

1
2
3
4
5
6
7
8
9
10
Promise.prototype.then = function(onFulfilled, onRejected){
//check if onFuillfilled and onRejected are functions
if(this.state === FULFILLED){ //it must be called after promise is fulfilled, with promise’s value as its first argument.
typeof onFulfilled === 'function' && onFulfilled(this.value);
}
if(this.state === REJECTED){//it must be called after promise is rejected, with promise’s reason as its first argument.
typeof onRejected === 'function' && onRejected(this.reason);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//constructor:
const resolve=(value)=> {
if(this.state === PENDING){
this.state = FULFILLED;
//so the value was attached to the promise instance
//.then can recieve the value
this.value = value;
}
}
const resolve=(reason)=> {
if(this.state === PENDING){
this.state = FULFILLED;
this.reason = reason;
}
}

then() returns a new promise instance

1
2
const promise2 = new Promise((resolve, reject) => {})
return promise2;

the new promise instance, can keep calling then on itself and pass the previous value/reason to the next then by passing it to the resolve and reject functions of itself.

If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.

If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

the result (value/reson) should ‘penetrate’ to the next then.

Providing a default function: (value)=>value

1
2
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

so when onFulfilled /onRejected are not function , promise2:

1
2
3
4
  //let x=onFulfilled(this.value)==>this.value
if(this.state === FULFILLED){resolve(x)}
//let x = onRejected(this.reason)==>this.reason
if(this.state === REJECTED){reject(x)}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const promise2 = new Promise((resolve, reject) => {
if(this.state === FULFILLED){ //state of
let x = onFulfilled(this.value);
//for next `then`
resolve(x);
}
if(this.state === REJECTED){
let x = onRejected(this.reason);
reject(x);
}
if(this.state === PENDING){
// TODO
}
})
return promise2;

Read More

es6ds

2020-06-15

ES6 Data Type

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

A summary of data type that introduced in ES6.

Type Symbol Map Set
Summary Unique ‘string’ Ordered ‘object’ whose key can be primitive & reference ‘Array’ with all unique value
Construct let sb = Symbol() let m = new Map([iteratble]) let s = new Set([iteratble])
Key-value Description as ‘key’
Symbol.keyFor(sb)
key=>any type ordered
value=>any type
key<=>value
unique key
Loop N\A For…of forEach() for…of forEach()
Transfer sb.toString() […m] = Array.from(m) <=> new Map(arr). […s] = Array.from(s) <=> new Set(arr).

Symbol

An unique ‘string’ that would never be equvlient to others

  • primitive data type

  • Symbol(< description >) function returns an anonymous, unique value

    1
    Symbol('foo') === Symbol('foo')  // false

    This functon has its static propertise and methods

    1
    2
    3
    4
    let sb = Symbol.for('foo')
    let sb2= Symbol.for('foo') //saved the value in global env in the memory
    sb ===sb2//true
    Symbol.keyFor(sb) //'foo'
  • Not new Symbol()

    1
    let sym = new Symbol()  // TypeError
    1
    2
    3
    4
    let sym = Symbol('foo')
    typeof sym // "symbol"
    let symObj = Object(sym)
    typeof symObj // "object"

    But it has instance/prototype properties and methods

    1
    2
    3
    Symbol.prototype.toString()
    let sb = Symbol('context');
    console.log(sb.description); //context

    Returns a string containing the description of the Symbol. Overrides the Object.prototype.toString() method.

Use cases

To dealing with the same string name, use symbol to create unique value;

1
2
3
4
5
6
7
8
9
10
11
let user1= {
name:'Jack'
}
let user2 = {
name:'Jack'
}
let data = {
[user1]:{age:19},
[user2]:{age:22}
}
console.log(data[user1]) //{age: 22}

Read More

inheritance

2020-06-12

Inheritance of Object in JS

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

Prototype chain

Let subType’s prototype points to an instance of the superType;

1
SubType.prototype= new SuperType()

Problems:

  • The instance property of SuperType becoms the shared prototype property for SubType
  • There is no way to pass arguments to the constructor of superType

Constructor stealing

Calling the constructor of supertype inside the constructor of subtype.

1
2
3
4
function SubType(...arg){
//now it's avaliable to pass arguments to supertype
SuperType.call(this,arg)
}

Problems:

  • No access for Subtype to the prototype method/properties of the SuperType
  • The methods are defined inside the constructor which makes them instance method. Not shared with all instances;

Combination inheritance

Prototype chain + constructor stealing

1
2
3
4
5
function SubType (..args){
SuperType.call(this,args)
}
SubType.prototype = new SuperType()
SubType.prototype.constructor =Subtype;

Problems:

  • The constructor function always be called twice during the inheritance;

Prototypal inheritance

The constructor is not necessary to perform inheritance. It simply can be done by a object itself.

1
2
3
4
5
6
7
8
9
10
Object.create()
Object.prototype.create=(prototype)=>{
function F(){};
//points the prototype to the argument (an object)
F.prototype = prototype;
//return the instance of the temp constructor
return new F()
}
let Person = {greeting:'Hello'}
let Student =Object.create(Person)

Inheritance using constructor:

1
SubType = Object(SuperType.prototype)

Parasitic inheritance

Create a function only focus on encapsulation

1
2
3
4
5
6
7
8
9
10
11
function parasitic(prototype){
let object = Object.create(prototype);
object.method=function (){
console.log(this.name)
}
return object;
}
let super = {name:'super'}
let obj1= parasitic(super);
let obj2=parasitic(super);
obj1.method !=obj2.method;

Problems:

  • The methods are not shared with instances;

Parasitic combination

For combination inheritance, the constructor function was called twice.

The instance property of superType were created first to be the prototype property of subtype, (SubType.prototype = new Super())

then created as iinstance properties.(inside the constructor)

1
2
3
4
5
function inheritance(subType,superType){
let prototype=Object.create(superType.prototype);
prototype.construcotr = subType;
subType.prototype=prototype;
}

Mixing inheritance

JS dosen’t support multiple inheritance, but method of different class/object can be borrowed by mixing

1
2
3
4
5
6
7
8
9
10
11
12
13
let Student ={
study(book){
console.log('read'+book)
}
}
function Person(name){
this.name = name;
this.greeting=function(){
console.log(name)
}
}
let jack = new Person('jack')//jack Person {name:'jack'}
Obejct.assign(jack,Student);//jack Person {name: "jack", greeting: ƒ, study: ƒ}

Read More

browser rendering

2020-06-08

Browser rendering

Disclaimer

This article is originally based on my understanding of this concept. No guarantee on the accuracy.😅

Few key points:

  • The parsing and creation of DOM tree and CSSOM tree is independent.
  • The render tree can only be created when both CSSOM and DOM tree are ready.
browser rendering-Page-1
  • The sync < script > tag would block the building of DOM tree, because:

    • the Javscript has to wait the CSSOM tree to be built since it may need to manuplate or get information about the sytle. And the DOM tree has to stopped since it not sure if the js would interact with the DOM tree.
    • So the CSSOM tree keeps building. When the CSSDOM tree finishes, the browser starts to parse js and execute it.
    • If the script is trying to manipulate any dom element that hasn’t be created, it would fail. So normally the script tag was put at the end of the body tag.
    • Then the DOM tree re-start to build.
    • The mordern browser allows the rendering to perform bits by bits.

    ![browser rendering-Page-2](browser-rendering/browser rendering-Page-2.png)

  • To shorten the time before the first-screen-rendering, it’s better to make the scirpt tag async

  • Now the parsing of CSS and html can again performs parallelly.

browser rendering-Page-3

Read More