Category: JavaScript

  • `this` in Arrow functions

    Arrow functions in JavaScript do not have their own bindings of this. In other words, in an arrow function, this refers to the this object where the arrrow function is created. By contrast, this in an ordinary anonymous function does not refer to a fixed object.

    For example, consider the following code:

    let o = {
        f1: function() { console.log(this.name); },
        f2: () => { console.log(this.name); },
        name: 'foo'
    };
    

    Under strict mode, o.f1() prints foo while o.f2 prints undefined, since f2 is created in the global level code and this is undefined (under non-strict mode, this refers to globalThis).

    The following implementation is functionally equivalent to the code above: f2 never uses this, but accesses _this set by the outer scope code.

    let o = {
        f1: function() { console.log(this.name); },
        f2: (function(_this) {
             return function() {
                 console.log(_this.name);
             }
         })(this)
    };

  • Whether a JavaScript object is an array?

    Typically, an array is created with the following code:

    let arr = [1, 2, 3];

    or using Array function:

    let arr = Array(1, 2, 3);

    The prototype of the created arrays is Array.prototype. Hence, the expression arr instanceof Array return true.

    However, we can create Array-like objects, and make them behave like a real array. For example:

    let arr = {0: 10, 1: 12, 2: 14, length: 3};

    Currently arr is still a plain object. We can make it become this of a function defined on Array.prototype, for example:

    Array.prototype.push.call(arr, 16);

    Then the content of arr will become:

    {0: 10, 1: 12, 2: 14, length: 3};

    We can also forcefully set the prototype of arr to Array.prototype:

    Object.setPrototypeOf(arr, Array.prototype);

    Then any function on Array.prototype can be invoked as a arr, like push above. And arr instanceof Array returns true.

    However, Array.isArray(arr) still returns false, and Object.prototype.toString.call(arr) still returns “[object Object]” rather than “[object Array]".

    The two function calls determine whether arr is an actual array by checking whether it is created via Array constructor. This is not changeable after the array is created.

    The package is-array uses the following way to determine whether arr is an array:

    1. if Array.isArray is available, use Array.isArray(arr);
    2. Otherwise, use Object.prototype.toString.call(arr) === '[object Array]'
  • “__proto__” in JavaScript

    This post is about the “__proto__” property name in JavaScript.

    There are two types of “__proto__” in JavaScript:

    (1) Directly used as the property name in object initialization, for example:

    { __proto__: {a: 1} }

    Note that the property can be surrounded with quotes, and the value must be null or an object. This usage of “__proto__” can be regarded as a special syntax.

    (2) Object.prototype.__proto__

    This usage is deprecated. In current Node.js implementation, “__proto__” is a getter and setter in Object.prototype. For example, the expression a.__proto__ is equivalent to the following code:

    var _get = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get;
    
    _get.call(a);

    And the expression a.__proto__ = b is equivalent to the following code:

    var _set = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
    
    _set.call(a, b);

    If an object is created by Object.create(null), or its prototype is set to null after creation, it cannot access “__proto__”.

    For example, at first:

    var a = {};

    We then set the prototype of a to null:

    a.__proto__ = null

    At this time, the prototype of a is actually null. However, if we attempt to access the property “__proto__” of a:

    a.__proto__

    The result is undefined.

    And then the code a.__proto__ = b does not call the setter, but directly adds a property named “__proto__” on a, and the value refers to b.