Tuesday, January 3, 2023

GetValue abstract operation

GetValue abstract operation GetValue ( V )
  1. ReturnIfAbrupt(V).
  2. If Type(V) is not Reference, return V.
  3. If IsUnresolvableReference(V) is true, throw a ReferenceError exception.
  4. Let base be GetBase(V).
  5. If HasPrimitiveBase(V) is true, Set base to !ToObject(base)
  6. If IsPropertyReference(V) is true, Return ? base.[[Get]](GetReferencedName(V), Receiver = GetThisValue(V)).
  7. Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V))

note If IsSuperReference(V), GetThisValue(V) returns the thisValue component of the reference V; else returns GetBase(V).

abstract operation O.[[Get]](P, Receiver) works as:

  • Let desc be ? O.[[GetOwnProperty]](P).
  • If desc is undefined, Return ?O.[[Prototype]].[[Get]](P, Receiver).
  • If IsDataDescriptor(desc) is true, return desc.[[Value]].
  • Return ? Call(desc.[[Get]], Receiver)// Receiver is only used by AccessorDescriptor

above all

  1. super is parent and super.super is grandpa
  2. desc.[[Get]] can accept base, base.super, base.super.super... as Receiver
  3. refer to new.target for more info regarding the super keyword

ToString.FromNum

ToString.FromNum

abstract operation

  1. If m is NaN, return the String "NaN".
  2. If m is +0 or -0, return the String "0".
  3. If m is less than zero, return the String concatenation of the String "-" and ToString(-m).
  4. If m is infinity, return the String "Infinity".
  5. let n, k, and s be integers such that k >= 1, s in [10^(k-1), 10^k), the Number value for s * 10^(n-k) is m. Note that k is the number of digits in the decimal representation of s, that s is not divisible by 10.
  6. if both k and n are no greater than 21:
    • if k is no greater than n, return the string-concatenation of:
      • the k digits of the decimal representation of s
      • n−k occurrences of the character 0
    • if n is greater than 0, return the string-concatenation of:
      • the code units of the most significant n digits of the decimal representation of s
      • the code unit 0x002E (FULL STOP)
      • the code units of the remaining k - n digits of the decimal representation of s
  7. ...

example 0.12300

k=3, s=123, n=0

example 123.4

n=k1=3, k2=1, s=123.4

example 0.0423

k=3, s=423, n=-1 ==> k1=n=-1,pow(10,k1-1)=0.04

example 42300

k=3, s=423, n=5 ==> pow(10, n-1) = 4

Wednesday, December 28, 2022

Symbol

Symbol

The Symbol Constructor

Symbol ( [ description ] )

  1. If NewTarget is not undefined, throw a TypeError exception.
  2. Note: the Symbol Constructor is not intended to be used with the new operator(not the target for new)
  3. If description is undefined, let descString be undefined; Else, let descString be ? ToString(description).
  4. Return a new unique Symbol value whose [[Description]] value is descString.
  5. Note: the Symbol() function returns a Symbol type instead of a Symbol object

Symbol Prototype Object

abstract operation thisSymbolValue(value)

  1. If Type(value) is Symbol, return value.
  2. If Type(value) is Object and value has a [[SymbolData]] internal slot
  3. then Return value.[[SymbolData]] //a Symbol Object
  4. Throw a TypeError exception.

Example

mySymbol = Symbol( "my symbol" )

// Object() performs a type conversion when called as a function rather than as a constructor.
mySymObj = Object(mySymbol)

console.log(mySymObj.toString()) // Symbol(my symbol)

Tuesday, December 27, 2022

Function.prototype.call

Function.prototype.call ( thisArgument, argumentsList )

Example

function anInstanceOfFunction(data)
{
    this.data = data;
}

thisArgument = {"data" : null};

// all instances of Function(function definitions or dynamical functions by `new Function`) has
// their [[prototype]] chained to the Function constructor's prototype property(Function.prototype)
anInstanceOfFunction.call(thisArgument, "dat");

console.log(thisArgument.data);

Function.prototype.call ( thisArgument, argumentsList )

note Function.prototype itself is a function object(to ensure compatibility with es2015), which returns undefined when called; but the call here is `Function.prototype.` instead of `Function.prototype(`

  1. If IsCallable(F) is false, throw a TypeError exception.//F is anInstanceOfFunction in our example
  2. Pop from the execution context stack//the top execution context has no further use and optimized out
  3. Let calleeContext be PrepareForOrdinaryCall(F, undefined):
            calleeContext = {
                "Function" : F,
                "LexicalEnvironment" : new NewFunctionEnvironment(F),
            }
            calleeContext.VariableEnvironment = calleeContext.LexicalEnvironment
            Push calleeContext onto the execution context stack
            return calleeContext
        
    
  4. calleeContext.LexicalEnvironment.EnvironmentRecord.[[ThisValue]] = thisArgument
  5. Let result be Evaluate F with argumentsList.
  6. Remove(exactly, Pop) calleeContext from the execution context stack
  7. If result.[[Type]] is return, return NormalCompletion(result.[[Value]]).
  8. ReturnIfAbrupt(result).
  9. Return NormalCompletion(undefined).

Function.prototype.bind

Function.prototype.bind( boundThis, ...boundArgs )

Example

const person = {
    getFullName: function () {
        return this.firstName + " " + this.lastName;
    }
}

const thisPerson = {
	firstName   :   "John",
	lastName    :   "Xu",
}

let getFullName = person.getFullName.bind(thisPerson);

console.log( getFullName() )

Function.prototype.bind( boundThis, ...boundArgs )

  1. Let targetFunction be the this value. // for our example, person.getFullName
  2. If IsCallable(targetFunction) is false, throw a TypeError exception.
  3. Let boundArgs be a new List consisting of all of the argument values provided after boundThis(for our example, empty) .
  4. Let F be ?BoundFunctionCreate(targetFunction, boundThis, boundArgs)
            return {
                [[BoundTargetFunction]]: targetFunction,
                [[BoundThis]]: boundThis,
                [[BoundArguments]]: boundArgs,
                [[Prototype]]:targetFunction.[[Prototype]],
            }
        
  5. Perform SetFunctionName(F, name = Get(Target, "name"), prefix = "bound").

NewTarget and new.target

NewTarget

example 01


base_obj = {
    "constructor" : my_constructor,
}

function my_constr_stub()
{
    console.log("in constructor stub:new.target=" + new.target);//undefined
}

function my_constructor()
{
    console.log("in constructor:new.target=" + new.target);// function my_constructor(){...
    my_constr_stub();
}

my_constructor.prototype = base_obj;

new my_constructor()

Object [[Construct]](a List of any, newTarget)

The second argument is the object to which the new operator was initially applied. For example, in following code, the new operator is initially applied to the Square object:

class Rectangle {
  constructor(height, width) {
    console.log("in Rectangle:new.target=" + new.target);
    this.name = 'Rectangle';
    this.height = height;
    this.width = width;
  }
}

class Square extends Rectangle {
  constructor(length) {
    console.log("in Square:new.target=" + new.target);
    super(length, length);

    this.name = 'Square';
  }
}

aS = new Square(2);
console.log(
    "name=" + aS.name +
    ";height=" + aS.height
);

Friday, December 23, 2022

function expression

function expression
factit = function factorial(n) {
    console.log(n)
    if (n < 2) {
      return 1;
    }
    return n * factorial(n - 1);
}

non_recursive = function(){}

/*
can't visit factorial here:
as is indicated in `Runtime Semantics: Evaluation` of NAMED function expression,
we will NewDeclarativeEnvironment(scope) as a middle env to recv factorial

from ecma:
The BindingIdentifier in a FunctionExpression can be referenced
 from inside the FunctionExpression's
FunctionBody to allow the function to call itself recursively.

However, unlike in a FunctionDeclaration, the BindingIdentifier in
a FunctionExpression cannot be referenced from and does
not affect the scope enclosing the FunctionExpression.
*/