Monthly Archives: September 2015

well-known-symbols-es6

By Axel Rauschmayer

In ECMAScript 6, the object Symbol has several properties that contain so-called well-known symbols (Symbol.iterator, Symbol.hasInstance, etc.). These let you customize how ES6 treats objects. This blog post explains the details.

Warning

Implementation of the features described here is work in progress. Consult the “ECMAScript 6 compatibility table” for what is supported where (spoiler: not much, in few engines).

Background

This section covers knowledge that is useful for the remainder of this post. Additionally, the following material may be of interest:

  • Chapter “Symbols” in “Exploring ES6”
  • Chapter “Values” (primitive values versus objects, etc.) in “Speaking JavaScript”

Internal properties

The ES6 specification uses internal properties to describe how JavaScript works. These are only known to the spec and not accessible from JavaScript. They may or may not exist in an actual implementation of the language. The names of internal properties are written in double square brackets.

For example: the link between an object and its prototype is the internal property [[Prototype]]. The value of that property cannot be read directly via JavaScript, but you can use Object.getPrototypeOf() to do so.

Overriding inherited properties

If an object obj inherits a property prop that is read-only then you can’t assign to that property:

    let proto = Object.defineProperty({}, 'prop', {
        writable: false,
        configurable: true,
        value: 123,
    });
    let obj = Object.create(proto);
    obj.prop = 456;
        // TypeError: Cannot assign to read-only property

This is similar to how an inherited property works that has a getter, but no setter. It is in line with viewing assignment as changing the value of an inherited property. It does so non-destructively: the original is not modified, but overridden by a newly created own property. Therefore, an inherited read-only property and an inherited setter-less property both prevent changes via assignment. You can, however, force the creation of an own property via Object.defineProperty():

    let proto = Object.defineProperty({}, 'prop', {
        writable: false,
        configurable: true,
        value: 123,
    });
    let obj = Object.create(proto);
    Object.defineProperty(obj, 'prop', {value: 456});
    console.log(obj.prop); // 456

Overview: all well-known symbols in ES6

All well-known symbols in ES6 are keys for properties. If you add a property to an object that has one of those keys, you change how ES6 treats that object. These are all well-known symbols in ES6:

  1. Customizing basic language operations:
    • Symbol.hasInstance (method)
      customizes instanceof.
    • Symbol.toPrimitive (method)
      customizes the coercion of an object to a primitive value.
    • Symbol.toStringTag (string)
      customizes the result returned by Object.prototype.toString().
  2. Iteration:
    • Symbol.iterator (method)
      A method with this key makes an object iterable (its elements can be iterated over language constructs such as the for-of loop and the spread operator (...)). Details: chapter “Iterables and iterators” of “Exploring ES6”.
  3. Forwarding calls from string methods to their parameters:
    • Symbol.match
    • Symbol.replace
    • Symbol.search
    • Symbol.split
  4. Miscellaneous:
    • Symbol.unscopables (Object)
      lets you hide some properties from the with statement.
    • Symbol.species (method)
      configures how built-in methods create objects that are similar to this.
    • Symbol.isConcatSpreadable (boolean)
      configures whether Array.prototype.concat() adds the indexed elements of an object to its result (“spreading”) or the object as a single element.

The following sections have more information on categories 1, 3 and 4.

Customizing basic language operations

Symbol.hasInstance (method)

A method with the key Symbol.hasInstance lets an object C customize the behavior of the instanceof operator. Signature of that method:

    [Symbol.hasInstance](potentialInstance : any)

x instanceof C works as follows in ES6:

  • If C is not an object, throw a TypeError.
  • If the method exists, call C[Symbol.hasInstance](x), coerce the result to boolean and return it.
  • Otherwise, compute and return the result according to the traditional algorithm (C must be callable, C.prototype in the prototype chain of x, etc.).
Uses in the standard library

The only method in the standard library that has this key is:

  • Function.prototype[Symbol.hasInstance]()

This is the implementation of instanceof that all functions (including classes) use by default. Quoting the spec:

This property is non-writable and non-configurable to prevent tampering that could be used to globally expose the target function of a bound function.

The tampering is possible because the traditional instanceof algorithm, OrdinaryHasInstance(), applies instanceof to the target function if it encounters a bound function.

Given that this property is read-only, you can’t use assignment to override it, as mentioned earlier.

Example: checking whether a value is an object

As an example, let’s implement an object ReferenceType whose “instances” are all objects, not just those that are subclasses of Object.

    const ReferenceType = {
        [Symbol.hasInstance](value) {
            return (value !== null
                && (typeof value === 'object'
                    || typeof value === 'function'));
        }
    };
    const obj1 = {};
    console.log(obj1 instanceof Object); // true
    console.log(obj1 instanceof ReferenceType); // true
    
    const obj2 = Object.create(null);
    console.log(obj2 instanceof Object); // false
    console.log(obj2 instanceof ReferenceType); // true

Symbol.toPrimitive (method)

Symbol.toPrimitive lets an object customize how it is coerced (converted automatically) to a primitive value.

Many JavaScript operations coerce values to the types that they need.

  • The multiplication operator (*) coerces its operands to numbers.
  • new Date(year, month, date) coerces its parameters to numbers.
  • parseInt(string , radix) coerces its first parameter to a string.

The following are the most common coercions:

  • Boolean: Coercion returns true for truthy values, false for falsy values. Objects are always truthy (even new Boolean(false)).
  • Number: Coercion converts objects to primitives first. Primitives are then converted to numbers (null0, true1, '123'123, etc.).
  • String: Coercion converts objects to primitives first. Primitives are then converted to strings (null'null', true'true', 123'123', etc.).
  • Object: The coercion wraps primitive values (booleans b via new Boolean(b), numbers n via new Number(n), etc.).

Converting an arbitrary value to a primitive is handled via the spec-internal operation ToPrimitive() which has three modes:

  • Number: the caller needs a number.
  • String: the caller needs a string.
  • Default: the caller needs either a number or a string.

The default mode is only used by:

  • Equality operator (==)
  • Addition operator (+)
  • new Date(value) (exactly one parameter!)

If the value is a primitive then ToPrimitive() is already done. Otherwise, the value is an object obj, which is converted to a promitive as follows:

  • Number mode: Return the result of obj.valueOf() if it is primitive. Otherwise, return the result of obj.toString() if it is primitive. Otherwise, throw a TypeError.
  • String mode: works like Number mode, but toString() is called first, valueOf() second.
  • Default mode: works exactly like Number mode.

This normal algorithm can be overridden by giving an object a method with the following signature:

    [Symbol.toPrimitive](hint : 'default' | 'string' | 'number')

In the standard library, there are two such methods:

  • Symbol.prototype[Symbol.toPrimitive](hint)
    prevents toString() from being called (which throws an exception).

  • Date.prototype[Symbol.toPrimitive](hint)
    This method implements behavior that deviates from the default algorithm. Quoting the specification: “Date objects are unique among built-in ECMAScript object in that they treat 'default' as being equivalent to 'string'. All other built-in ECMAScript objects treat 'default' as being equivalent to 'number'.”

Example

The following code demonstrates how coercion affects the object obj.

    let obj = {
        [Symbol.toPrimitive](hint) {
            switch (hint) {
                case 'number':
                    return 123;
                case 'string':
                    return 'str';
                case 'default':
                    return 'default';
                default:
                    throw new Error();
            }
        }
    };
    console.log(2 * obj); // 246
    console.log(3 + obj); // '3default'
    console.log(obj == 'default'); // true
    console.log(String(obj)); // 'str'

Symbol.toStringTag (string)

In ES5 and earlier, each object had the internal own property [[Class]] whose value hinted at its type. You could not access it directly, but its value was part of the string returned by Object.prototype.toString(), which is why that method was used for type checks, as an alternative to typeof.

In ES6, there is no internal property [[Class]], anymore, and using Object.prototype.toString() for type checks is discouraged. In order to ensure the backwards-compatibility of that method, the public property with the key Symbol.toStringTag was introduced. You could say that it replaces [[Class]].

Object.prototype.toString() now works as follows:

  • Convert this to an object obj.
  • Determine the toString tag tst of obj.
  • Return '[object ' + tst + ']'.
Default toString tags

The default values for various kinds of objects are shown in the following table.

Value toString tag
undefined 'Undefined'
null 'Null'
An Array object 'Array'
A string object 'String'
arguments 'Arguments'
Something callable 'Function'
An error object 'Error'
A boolean object 'Boolean'
A number object 'Number'
A date object 'Date'
A regular expression object 'RegExp'
(Otherwise) 'Object'

Most of the checks in the left column are performed by looking at internal properties. For example, if an object has the internal property [[Call]], it is callable.

The following interaction demonstrates the default toString tags.

    > Object.prototype.toString.call(null)
    '[object Null]'
    > Object.prototype.toString.call([])
    '[object Array]'
    > Object.prototype.toString.call({})
    '[object Object]'
    > Object.prototype.toString.call(Object.create(null))
    '[object Object]'
Overriding the default toString tag

If an object has an (own or inherited) property whose key is Symbol.toStringTag then its value overrides the default toString tag. For example:

    > ({}.toString())
    '[object Object]'
    > ({[Symbol.toStringTag]: 'Foo'}.toString())
    '[object Foo]'

Instances of user-defined classes get the default toString tag (of objects):

    class Foo { }
    console.log(new Foo().toString()); // [object Object]

One option for overriding the default is via a getter:

    class Bar {
        get [Symbol.toStringTag]() {
          return 'Bar';
        }
    }
    console.log(new Bar().toString()); // [object Bar]

In the JavaScript standard library, there are the following custom toString tags. Objects that have no global names are quoted with percent symbols (for example: %TypedArray%).

  • Module-like objects:
    • JSON[Symbol.toStringTag]'JSON'
    • Math[Symbol.toStringTag]'Math'
  • Actual module objects M: M[Symbol.toStringTag]'Module'
  • Built-in classes
    • ArrayBuffer.prototype[Symbol.toStringTag]'ArrayBuffer'
    • DataView.prototype[Symbol.toStringTag]'DataView'
    • Map.prototype[Symbol.toStringTag]'Map'
    • Promise.prototype[Symbol.toStringTag]'Promise'
    • Set.prototype[Symbol.toStringTag]'Set'
    • get %TypedArray%.prototype[Symbol.toStringTag]'Uint8Array' etc.
    • WeakMap.prototype[Symbol.toStringTag]'WeakMap'
    • WeakSet.prototype[Symbol.toStringTag]'WeakSet'
  • Iterators
    • %MapIteratorPrototype%[Symbol.toStringTag]'Map Iterator'
    • %SetIteratorPrototype%[Symbol.toStringTag]'Set Iterator'
    • %StringIteratorPrototype%[Symbol.toStringTag]'String Iterator'
  • Miscellaneous
    • Symbol.prototype[Symbol.toStringTag]'Symbol'
    • Generator.prototype[Symbol.toStringTag]'Generator'
    • GeneratorFunction.prototype[Symbol.toStringTag]'GeneratorFunction'

All of the built-in properties whose keys are Symbol.toStringTag have the following property descriptor:

    {
        writable: false,
        enumerable: false,
        configurable: true,
    }

As mentioned in an earlier section, you can’t use assignment to override those properties, because they are read-only.

Forwarding calls from string methods to their parameters

In ES6, the four string methods that accept regular expression parameters do relatively little. They mainly call methods of their parameters:

  • String.prototype.match(regexp) calls regexp[Symbol.match](this).
  • String.prototype.replace(searchValue, replaceValue) calls searchValue[Symbol.replace](this, replaceValue).
  • String.prototype.search(regexp) calls regexp[Symbol.search](this).
  • String.prototype.split(separator, limit) calls separator[Symbol.split](this, limit).

The parameters don’t have to be regular expressions, anymore. Any objects with appropriate methods will do.

Miscellaneous

Symbol.unscopables (Object)

Symbol.unscopables lets an object hide some properties from the with statement.

The reason for introducing this mechanism was that TC39 wanted to add new methods to Array.prototype. They couldn’t, because with would turn those new methods into local variables and break some existing code (such as the widely deployed Ext JS 4.2.1). For example, the existence of a property Array.prototype.values breaks the following function foo(), if you call it with an Array:

    function foo(values) {
        with (values) {
            console.log(values.length); // (A)
        }
    }

Inside the with statement, all properties of values become local variables, shadowing even values itself. Therefore, if values has a property values then the statement in line A logs values.values.length and not values.length.

Symbol.unscopables is used only once in the standard library:

  • Array.prototype[Symbol.unscopables]
    • Holds an object with the following properties (which are therefore hidden from the with statement): copyWithin, entries, fill, find, findIndex, keys, values

Symbol.species (method)

Symbol.species lets you configure how methods of built-in objects create instances they return. One example is that you can configure what Array.prototype.map() returns. By default, it uses the same constructor that created this to create the return value, but you can override that by setting Array[Symbol.species].

The details are explained in the chapter on classes of “Exploring ES6”.

Symbol.isConcatSpreadable (boolean)

Symbol.isConcatSpreadable lets you configure how Array.prototype.concat() adds an object to its result.

The default for Arrays is to “spread” them, their indexed elements become elements of the result:

    let arr1 = ['c', 'd'];
    ['a', 'b'].concat(arr1, 'e'); // ['a', 'b', 'c', 'd', 'e']

With Symbol.isConcatSpreadable, you can override the default and avoid spreading for Arrays:

    let arr2 = ['c', 'd'];
    arr2[Symbol.isConcatSpreadable] = false;
    ['a', 'b'].concat(arr2, 'e'); // ['a', 'b', ['c','d'], 'e']

For non-Arrays, the default is not to spread. You can use Symbol.isConcatSpreadable to force spreading:

    let obj = {length: 2, 0: 'c', 1: 'd'};
    console.log(['a', 'b'].concat(obj, 'e')); // ['a', 'b', obj, 'e']
    
    obj[Symbol.isConcatSpreadable] = true;
    console.log(['a', 'b'].concat(obj, 'e')); // ['a', 'b', 'c', 'd', 'e']

The default in ES6 is to spread only Array objects. Whether or not something is an Array object is tested via Array.isArray() (or rather, the same operation that that method uses). Whether or not Array.prototype is in the prototype chain makes no difference for that test (which is important, because, in ES5 and earlier, hacks were used to subclass Array and those must continue to work; see blog post “__proto__ in ECMAScript 6”):

    > let arr = [];
    > Array.isArray(arr)
    true
    
    > Object.setPrototypeOf(arr, null);
    > Array.isArray(arr)
    true

The default can be overridden by adding a property whose key is Symbol.isConcatSpreadable to the object itself or to one of its prototypes, and by setting it to either true or false.

No object in the ES6 standard library has a property with the key Symbol.isConcatSpreadable. This mechanism therefore exists purely for browser APIs and user code.

Consequences:

  • Subclasses of Array are spread by default (because their instances are Array objects).
  • A subclass of Array can prevent its instances from being spread by setting a property to false whose key is Symbol.isConcatSpreadable. That property can be a prototype property or an instance property.

  • Other Array-like objects are spread by concat() if property [Symbol.isConcatSpreadable] is true. That would enable one, for example, to turn on spreading for some Array-like DOM collections.

  • Typed Arrays are not spread. They don’t have a method concat(), either.

Symbol.isConcatSpreadable in the ES6 spec
  • In the description of Array.prototype.concat(), you can see that spreading requires an object to be Array-like (property length plus indexed elements).
  • Whether or not to spread an object is determined via the spec operation IsConcatSpreadable(). The last step is the default (equivalent to Array.isArray()) and the property [Symbol.isConcatSpreadable] is retrieved via a normal Get() operation, meaning that it doesn’t matter whether it is own or inherited.

Spelling: Why Symbol.hasInstance and not Symbol.HAS_INSTANCE (etc.)?

The well-known symbols are stored in properties whose names start with lowercase characters and are camel-cased. In a way, these properties are constants and it is customary for constants to have all-caps names (Math.PI etc.). But the reasoning for their spelling is different: Well-known symbols are used instead of normal property keys, which is why their “names” follow the rules for property keys, not the rules for constants.

Source:: 2ality

6 Practical Examples For Building Parallax Websites

By Danny Markov

6-practical-examples-parallax

Websites with scroll animations are all the rage these days. This is why today we’re going to show you a few practical examples for building them. You can think of this article as a collection of building blocks which you can mix and match into an impressive interactive web page.

The Basic Idea

The usual way that these websites are built is by using a JavaScript library. Some of the popular choices are Scrollr, scrollMagic, Parallax.js, scrollReveal.js and others. We are going to use Scrollr today as it is the most popular and works on mobile devices.

To use Scrollr, you only need to download it’s source and create a link to it in your HTML. After that’s done, calling skrollr.init(); will enable Scrollr for all elements on the page.

<script src="assets/skrollr.min.js"></script>

<script>
    skrollr.init();
</script>

The library is very powerful and you can create all kinds of scroll animations with it. See the website that we were able to build with it:

Parallax Website

Want to learn how it was made? Keep on reading!

Introduction to Scrollr

Once you have the Scrollr library in your page, you add data attributes to the elements you wish to animate while the page is scrolled. Here’s the most basic example, which animates a div from blue to red:

<div data-bottom-top="background-color: rgb(255,0,0);" 
data-center-center="background-color: rgb(0,0,255);">
</div>

We have a simple div with a pair of attributes. The first attribute will tell Scrollr when the animation starts and the second one when it should end. As you can see, the animation itself is done via CSS properties (note that you need to specify the colors as rgb). The library smoothly transitions from one to the other.

Using these data attributes, you can create all kinds of interesting effects. Here are a few practical examples that show you what you can do.

1. Parallax Intro

The parallax is probably the most popular scroll animation we see these days. It consists of a huge, fixed image spreading across the background, which we see only a portion of depending on how far we’ve scrolled.

Other than that our parallax is just an image inside a wrapper div, with transitions at different speeds and some smart CSS.

Parallax Intro

Parallax Intro

2. Body Text

Here we have three inline paragraphs which will appear one after the other. We’ve accomplished this using offsets, which tell the library to start the animation earlier than it normally should.

Body Text

Body Text

3. Feature List

Feature lists are the place where you showcase what your product is capable of. Big icons and text are a must have, but you can also spice things up with eye-catching animations. In our example, we will have the features appear from different sides of the screen.

Feature List

Feature List

4. About us

Our “About us” example consists of pretty circular avatars aligned on two rows. The images in the first row are rotated clockwise and the ones on the second row are flipped horizontally.

About Us

About Us

5. Gallery

We have prepared a beautiful scroll animation for our gallery example. It consists of a set of images on two rows. The first row moves from right to left and the second row moves in the opposite direction. This animation takes some time to complete, and since we don’t want our gallery leaving the screen without finishing its transition, we pause the scrolling for a while.

Gallery

Gallery

6. Footer

For the footer section we’ve used one of our freebie templates and we only changed up the colors. When the footer enters the screen, the width of the search bar inside it increases.

Footer

Footer

Hope you enjoyed our examples! There is a lot you can learn about Scrollr. It has a very detailed documentation that covers every aspect of the library.

Source:: Tutorialzine.com

__proto__ in ECMAScript 6

By Axel Rauschmayer

The property __proto__ (pronounced “dunder proto”) has existed for a while in most JavaScript engines. This blog post explains how it worked prior to ECMAScript 6 and what changes with ECMAScript 6.

For this blog post, it helps if you know what prototype chains are. Consult Sect. “Layer 2: The Prototype Relationship Between Objects” in “Speaking JavaScript”, if necessary.

__proto__ prior to ECMAScript 6

Prototypes

Each object in JavaScript starts a chain of one or more objects, a so-called prototype chain. Each object points to its successor, its prototype via the internal property [[Prototype]] (which is null if there is no successor). That property is called internal, because it only exists in the language specification and cannot be directly accessed from JavaScript. In ECMAScript 5, the standard way of getting the prototype p of an object obj is:

    var p = Object.getPrototypeOf(obj);

There is no standard way to change the prototype of an existing object, but you can create a new object obj that has the given prototype p:

    var obj = Object.create(p);

__proto__

A long time ago, Firefox got the non-standard property __proto__. Other browsers eventually copied that feature, due to its popularity.

Prior to ECMAScript 6, __proto__ worked in obscure ways:

  • You could use it to get or set the prototype of any object:

        var obj = {};
        var p = {};
        
        console.log(obj.__proto__ === p); // false
        obj.__proto__ = p;
        console.log(obj.__proto__ === p); // true
    
  • However, it was never an actual property:

        > var obj = {};
        > '__proto__' in obj
        false
    

Subclassing Array via __proto__

The main reason why __proto__ became popular was because it enabled the only way to create a subclass MyArray of Array in ES5: Array instances were exotic objects that couldn’t be created by ordinary constructors. Therefore, the following trick was used:

    function MyArray() {
        var instance = new Array(); // exotic object
        instance.__proto__ = MyArray.prototype;
        return instance;
    }
    MyArray.prototype = Object.create(Array.prototype);
    MyArray.prototype.customMethod = function (···) { ··· };

Subclassing in ES6 works differently than in ES5 and supports subclassing builtins out of the box.

Why __proto__ is problematic in ES5

The main problem is that __proto__ mixes two levels: the object level (normal properties, holding data) and the meta level.

If you accidentally use __proto__ as a normal property (object level!), to store data, you get into trouble, because the two levels clash. The situation is compounded by the fact that you have to abuse objects as maps in ES5, because it has no built-in data structure for that purpose. Maps should be able to hold arbitrary keys, but you can’t use the key '__proto__' with objects-as-maps.

In theory, one could fix the problem by using a symbol instead of the special name __proto__, but keeping meta-operations completely separate (as done via Object.getPrototypeOf()) is the best approach.

The two kinds of __proto__ in ECMAScript 6

Because __proto__ was so widely supported, it was decided that its behavior should be standardized for ECMAScript 6. However, due to its problematic nature, it was added as a deprecated feature. These features reside in Annex B in the ECMAScript specification, which is described as follows:

The ECMAScript language syntax and semantics defined in this annex are required when the ECMAScript host is a web browser. The content of this annex is normative but optional if the ECMAScript host is not a web browser.

JavaScript has several undesirable features that are required by a significant amount of code on the web. Therefore, web browsers must implement them, but other JavaScript engines don’t have to.

In order to explain the magic behind __proto__, two mechanisms were introduced in ES6:

  • A getter and a setter implemented via Object.prototype.__proto__.
  • In an object literal, you can consider the property key '__proto__' a special operator for specifying the prototype of the created objects.

Object.prototype.__proto__

ECMAScript 6 enables getting and setting the property __proto__ via a getter and a setter stored in Object.prototype. If you were to implement them manually, this is roughly what it would look like:

    Object.defineProperty(Object.prototype, '__proto__', {
        get() {
            let _thisObj = Object(this);
            return Object.getPrototypeOf(_thisObj);
        },
        set(proto) {
            if (this === undefined || this === null) {
                throw new TypeError();
            }
            if (!isObject(this)) {
                return undefined;
            }
            if (!isObject(proto)) {
                return undefined;
            }
            let status = Reflect.setPrototypeOf(this, proto);
            if (! status) {
                throw new TypeError();
            }
        },
    });
    function isObject(value) {
        return Object(value) === value;
    }

The getter and the setter for __proto__ in the ES6 spec:

The property key __proto__ as an operator in an object literal

If __proto__ appears as an unquoted or quoted property key in an object literal, the prototype of the object created by that literal is set to the property value:

    > Object.getPrototypeOf({ __proto__: null })
    null
    > Object.getPrototypeOf({ '__proto__': null })
    null

Using the string value '__proto__' as a computed property key does not change the prototype, it creates an own property:

    > let obj = { ['__proto__']: null };
    > Object.getPrototypeOf(obj) === Object.prototype
    true
    > Object.keys(obj)
    [ '__proto__' ]

The special property key '__proto__' in the ES6 spec:

Avoiding the magic of __proto__

Define, don’t assign

Remember that there are two ways to create own properties.

First, assigning. Use the assignment operator for a property that is not yet an own property:

    obj.newProperty = 123;

In three cases, no own property newProperty is created, even if it doesn’t exist, yet:

  1. A read-only property newProperty exists in the property chain. Then the assignment causes a TypeError in strict mode.
  2. A setter exists in the prototype chain. Then that setter is called.
  3. A getter without a setter exists in the prototype chain. Then a TypeError is thrown in strict mode. This case is similar to the first one.

Second, defining. Use Object.defineProperty() and Object.defineProperties() to always create a new own property if it doesn’t exist yet. None of the three scenarios listed for assignment prevent that.

For more information, consult section “Properties: Definition Versus Assignment” in “Speaking JavaScript”.

Defining __proto__

In ECMAScript 6, if you define (not assign) the own property __proto__, no special functionality is triggered and the getter/setter Object.prototype.__proto__ is overridden:

    let obj = {};
    Object.defineProperty(obj, '__proto__', { value: 123 })
    
    Object.keys(obj); // [ '__proto__' ]
    console.log(obj.__proto__); // 123

Objects that don’t have Object.prototype as a prototype

The __proto__ getter/setter is provided via Object.prototype. Therefore, an object without Object.prototype in its prototype chain doesn’t have the getter/setter, either. In the following code, dict is an example of such an object – it does not have a prototype. As a result, __proto__ now works like any other property:

    > let dict = Object.create(null);
    > '__proto__' in dict
    false
    > dict.__proto__ = 'abc';
    > dict.__proto__
    'abc'

__proto__ and dict objects

If you want to use an object as a dictionary then it is best if it doesn’t have a prototype. That’s why prototype-less objects are also called dict objects. In ES6, you don’t even have to escape the property key '__proto__' for dict objects, because it doesn’t trigger any special functionality.

__proto__ as an operator in an object literal lets you create dict objects more concisely:

    let dictObj = {
        __proto__: null,
        yes: true,
        no: false,
    };

Note that in ES6, you should normally prefer the built-in data structure Map to dict objects, especially if keys are not fixed.

__proto__ and JSON

Prior to ES6, the following could happen in a JavaScript engine:

    > JSON.parse('{"__proto__": []}') instanceof Array
    true

With __proto__ being a getter/setter in ES6, JSON.parse() works fine, because it defines properties, it doesn’t assign them (if implemented properly, an older version of V8 did assign).

JSON.stringify() isn’t affected by __proto__, either, because it only considers own properties. Objects that have an own property whose name is __proto__ work fine:

    > JSON.stringify({['__proto__']: true})
    '{"__proto__":true}'

Detecting support for ES6-style __proto__

Support for ES6-style __proto__ varies from engine to engine. Consult kangax’ ECMAScript 6 compatibility table for information on the status quo:

The following two sections describe how you can programmatically detect whether an engine supports either of the two kinds of __proto__.

Feature: __proto__ as getter/setter

A simple check for the getter/setter:

    var supported = {}.hasOwnProperty.call(Object.prototype, '__proto__');

A more sophisticated check:

    var desc = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
    var supported = (
        typeof desc.get === 'function' && typeof desc.set === 'function'
    );

Feature: __proto__ as an operator in an object literal

You can use the following check:

    var supported = Object.getPrototypeOf({__proto__: null}) === null;

Recommendations for __proto__

It is nice how well ES6 turns __proto__ from something obscure into something that is easy to understand.

However, I still recommend not to use it. It is effectively a deprecated feature and not part of the core standard. You can’t rely on it being there for code that should run on all engines.

More recommendations:

  • Use Object.getPrototypeOf() to get the prototype of an object.
  • Use Object.create() to create a new object with a given prototype. Avoid Object.setPrototypeOf(). If you change the prototype of an existing object, it can become slower.
  • I actually like __proto__ as an operator in an object literal. It is useful for demonstrating prototypal inheritance and for creating dict objects. However, the previously mentioned caveats do apply.

Source:: 2ality

ECMAScript 6: holes in Arrays

By Axel Rauschmayer

This blog post describes how ECMAScript 6 handles holes in Arrays.

Holes in Arrays

Holes are indices “inside” an Array that have no associated element. In other words: An Array arr is said to have a hole at index i if:

  • 0 ≤ i < arr.length
  • !(i in arr)

For example: The following Array has a hole at index 1.

    > let arr = ['a',,'b']
    'use strict'
    > 0 in arr
    true
    > 1 in arr
    false
    > 2 in arr
    true
    > arr[1]
    undefined

For more information, consult Sect. “Holes in Arrays” in “Speaking JavaScript”.

ECMAScript 6: holes are treated like undefined elements

The general rule for Array methods that are new in ES6 is: each hole is treated as if it were the element undefined. Examples:

    > Array.from(['a',,'b'])
    [ 'a', undefined, 'b' ]
    > [,'a'].findIndex(x => true)
    0
    > [...[,'a'].entries()]
    [ [ 0, undefined ], [ 1, 'a' ] ]

The idea is to steer people away from holes and to simplify long-term. Unfortunately that means that things are even more inconsistent now.

Array methods and holes

Array.from()

Array.from() converts holes to undefined:

    > Array.from(['a',,'b'])
    [ 'a', undefined, 'b' ]

With a second argument, it works mostly like map(), but does not ignore holes:

    > Array.from(new Array(3), (x,i) => i)
    [ 0, 1, 2 ]

Spread operator (...)

Inside Arrays, the spread operator (...) works much like Array.from() (but its operand must be iterable, whereas Array.from() can handle anything that’s Array-like).

    > [...['a',,'b']]
    [ 'a', undefined, 'b' ]

Array.prototype methods

In ECMAScript 5, behavior already varied greatly:

  • fill() doesn’t care whether there are elements at indices or not.
  • filter() and forEach() ignore holes.
  • join() and toString() treat holes as if they were undefined elements, but interprets both null and undefined as empty strings.
  • map() skips but preserves holes.

ECMAScript 6 adds new kinds of behaviors:

  • copyWithin() creates holes when copying holes (i.e., it deletes elements if necessary).
  • entries(), keys(), values() treat each hole as if it was the element undefined.
  • find() and findIndex() do the same.

The following table describes how Array.prototype methods handle holes.

Method Holes are
concat Preserved ['a',,'b'].concat(['c',,'d']) → ['a',,'b','c',,'d']
copyWithin Preserved [,'a','b',,].copyWithin(2,0) → [,'a',,'a']
entries Elements [...[,'a'].entries()] → [[0,undefined], [1,'a']]
every Ignored [,'a'].every(x => x==='a') → true
fill Filled new Array(3).fill('a') → ['a','a','a']
filter Removed ['a',,'b'].filter(x => true) → ['a','b']
find Elements [,'a'].find(x => true) → undefined
findIndex Elements [,'a'].findIndex(x => true) → 0
forEach Ignored [,'a'].forEach((x,i) => log(i)); → 1
indexOf Ignored [,'a'].indexOf(undefined) → -1
join Elements [,'a',undefined,null].join('#') → '#a##'
keys Elements [...[,'a'].keys()] → [0,1]
lastIndexOf Ignored [,'a'].lastIndexOf(undefined) → -1
map Preserved [,'a'].map(x => 1) → [,1]
pop Elements ['a',,].pop() → undefined
push Preserved new Array(1).push('a') → 2
reduce Ignored ['#',,undefined].reduce((x,y)=>x+y) → '#undefined'
reduceRight Ignored ['#',,undefined].reduceRight((x,y)=>x+y) → 'undefined#'
reverse Preserved ['a',,'b'].reverse() → ['b',,'a']
shift Elements [,'a'].shift() → undefined
slice Preserved [,'a'].slice(0,1) → [,]
some Ignored [,'a'].some(x => x !== 'a') → false
sort Preserved [,undefined,'a'].sort() → ['a',undefined,,]
splice Preserved ['a',,].splice(1,1) → [,]
toString Elements [,'a',undefined,null].toString() → ',a,,'
unshift Preserved [,'a'].unshift('b') → 3
values Elements [...[,'a'].values()] → [undefined,'a']

Notes:

  • ES6 methods have checkmarks (✓).
  • JavaScript ignores trailing commas: ['a',,].length → 2
  • Helper function used in the table: const log = console.log.bind(console);

Recommendations

With regard to holes in Arrays, the only rule is now that there are no rules. Therefore, you should avoid holes if you can (they affect performance negatively, too). If you can’t then the table in the previous section may help.

Further reading

  • ECMAScript 5: Chapter “Arrays” in “Speaking JavaScript”
  • ECMAScript 6: Chapter “New Array features” in “Exploring ES6”

Source:: 2ality

Freebie: 3 Stylish and Customizable JavaScript Dialogs

By Danny Markov

3-stylish-customizable-javascript-dialogs

It’s time for freebies again! In this edition we’re bringing you 3 stylish dialogs! They don’t use any frameworks – it’s all vanilla HTML, CSS and JavaScript (with a sprinkle of jQuery). They are responsive and should work in all modern desktop and mobile browsers.

The Dialogs

Dialogs are a good way to present a message or require an action for your users. The dialogs built into web browsers can’t be styled to match your design, so you often need to roll on your own. That’s why we’ve created the three designs included here, which can be easily customized to fit your style and used as replacements for the default alert() and prompt() dialogs.

To include one of the dialogs in your project simply copy the HTML from the example and place it anywhere on your page. Each dialog has a separate CSS stylesheet, containing all the needed styles for it to look nice. The CSS is self contained and won’t interfere with the rest of your styles.

We’ve also included a few useful jQuery snippets for showing the modal and dismissing it by clicking/touching the dark overlay, clicking the button or hitting the escape key.

Confirmation Dialog

Free for Commercial Use

All of the dialogs can be downloaded from the button above. You have all rights to customize them and use them in personal and commercial projects (our license page). We hope you enjoy them!

Source:: Tutorialzine.com

function-names-es6

By Axel Rauschmayer

The name property of a function contains its name:

    > function foo() {}
    > foo.name
    'foo'

This property is useful for debugging (its value shows up in stack traces) and some metaprogramming tasks (picking a function by name etc.).

Prior to ECMAScript 6 (ES6), this property was already supported by most engines. With ES6, it becomes part of the language standard and is frequently filled in automatically.

The following sections describe how name is set up automatically for various programming constructs.

Assignments

Functions pick up names if they are created via variable declarations:

    let func1 = function () {};
    console.log(func1.name); // func1
    
    const func2 = function () {};
    console.log(func2.name); // func2
    
    var func3 = function () {};
    console.log(func3.name); // func3

But even with a normal assignment, name is set up properly:

    let func4;
    func4 = function () {};
    console.log(func4.name); // func4
    
    var func5;
    func5 = function () {};
    console.log(func5.name); // func5

With regard to names, arrow functions are like anonymous function expressions:

    const func = () => {};
    console.log(func.name); // func

From now on, whenever you see an anonymous function expression, you can assume that an arrow function works the same way.

Default values

If a function is a default value, it gets its name from its variable or parameter:

    let [func1 = function () {}] = [];
    console.log(func1.name); // func1
    
    let { f2: func2 = function () {} } = {};
    console.log(func2.name); // func2
    
    function g(func3 = function () {}) {
        return func3.name;
    }
    console.log(g()); // func3

Methods in object literals

If a function is the value of a property, it gets its name from that property. It doesn’t matter if that happens via a method definition (line A), a traditional property definition (line B), a property definition with a computed property key (line C) or a property value shorthand (line D).

    function func() {}
    let obj = {
        m1() {}, // (A)
        m2: function () {}, // (B)
        ['m' + '3']: function () {}, // (C)
        func, // (D)
    };
    console.log(obj.m1.name); // m1
    console.log(obj.m2.name); // m2
    console.log(obj.m3.name); // m3
    console.log(obj.func.name); // func

The names of getters are prefixed with 'get', the names of setters are prefixed with 'set':

    let obj = {
        get foo() {},
        set bar(value) {},
    };
    let getter = Object.getOwnPropertyDescriptor(obj, 'foo').get;
    console.log(getter.name); // 'get foo'
    
    let setter = Object.getOwnPropertyDescriptor(obj, 'bar').set;
    console.log(setter.name); // 'set bar'

Methods in class definitions

The naming of methods in class definitions is similar to object literals:

    class C {
        m1() {}
        ['m' + '2']() {} // computed property key
    
        static classMethod() {}
    }
    console.log(C.prototype.m1.name); // m1
    console.log(new C().m1.name); // m1
    
    console.log(C.prototype.m2.name); // m2
    
    console.log(C.classMethod.name); // classMethod

Getters and setters again have the name prefixes 'get' and 'set', respectively:

    class C {
        get foo() {}
        set bar(value) {}
    }
    let getter = Object.getOwnPropertyDescriptor(C.prototype, 'foo').get;
    console.log(getter.name); // 'get foo'
    
    let setter = Object.getOwnPropertyDescriptor(C.prototype, 'bar').set;
    console.log(setter.name); // 'set bar'

Named function definitions

This scenario has always been well supported: a function definition with a name passes it on to the name property.

For example, a function declaration:

    function foo() {}
    console.log(foo.name); // foo

The name of a named function expression also sets up the name property.

    const bar = function baz() {};
    console.log(bar.name); // baz

Because it comes first, the function expression’s name baz takes precedence over other names (e.g. the name bar provided via the variable declaration):

However, as has in ES5, the name of a function expression is only a variable inside the function expression:

    const bar = function baz() {
        console.log(baz.name); // baz
    };
    bar();
    console.log(baz); // ReferenceError

Class definitions

Remember that class definitions create functions. Those functions also have their property name set up correctly:

    class Foo {}
    console.log(Foo.name); // Foo
    
    const Bar = class {};
    console.log(Bar.name); // Bar

Default exports

All of the following statements set name to 'default':

    export default function () {}
    export default (function () {});
    
    export default class {}
    export default (class {});
    
    export default () => {};

Other programming constructs

  • Generator functions and generator methods get their names the same way that normal functions and methods do.

  • new Function() produces functions whose name is 'anonymous'. A webkit bug describes why that is necessary on the web.

  • Function.prototype.bind() produces functions whose name is 'bound'.

Methods whose keys are symbols

In ES6, the key of a method can be a symbol. The name property of such a method is still a string:

  • If the symbol has a description, the method’s name is the description in square brackets.
  • Otherwise, the method’s name is the empty string ('').
    const key1 = Symbol('description');
    const key2 = Symbol();
    
    let obj = {
        [key1]() {},
        [key2]() {},
    };
    console.log(obj[key1].name); // '[description]'
    console.log(obj[key2].name); // ''

Property name is only created automatically, never updated

Assignment etc. only set the name if that property doesn’t exist, yet. Accordingly, anonymous function expressions and arrow functions don’t initially have it:

    > 'name' in (function () {})
    false
    > 'name' in (() => {})
    false

The function property name in the spec

  • The spec operation SetFunctionName() sets up the property name. Search for its name in the spec to find out where that happens.
  • Anonymous function expressions not having a property name can be seen by looking at their runtime semantics:
    • The names of named function expressions are set up via SetFunctionName(). That operation is not invoked for anonymous function expressions.
    • The names of function declarations are set up when entering a scope (they are hoisted!).
  • When an arrow function is created, no name is set up, either (SetFunctionName() is not invoked).

Suport for the name property in engines

In Kangax’ ES6 table, you can see that no engine currently fully supports name, not even Babel. Thus, the code in this blog post shows how things should be, not how they are in any single engine.

Source:: 2ality

Typed Arrays in ECMAScript 6

By Axel Rauschmayer

Typed Arrays are an ECMAScript 6 API for handling binary data. This blog post explains how they work.

Overview

Code example:

    let typedArray = new Uint8Array([0,1,2]);
    console.log(typedArray.length); // 3
    typedArray[0] = 5;
    let normalArray = [...typedArray]; // [5,1,2]
    
    // The elements are stored in typedArray.buffer.
    // Get a different view on the same data:
    let dataView = new DataView(typedArray.buffer);
    console.log(dataView.getUint8(0)); // 5

Instances of ArrayBuffer store the binary data to be processed. Two kinds of views are used to access the data:

  • Typed Arrays (Uint8Array, Int16Array, Float32Array, etc.) interpret the ArrayBuffer as an indexed sequence of elements of a single type.
  • Instances of DataView let you access data as elements of several types (Uint8, Int16, Float32, etc.), at any byte offset inside an ArrayBuffer.

The following browser APIs support Typed Arrays (details are mentioned later):

  • File API
  • XMLHttpRequest
  • Fetch API
  • Canvas
  • WebSockets
  • And more

Introduction

For a long time, JavaScript was not very good at handling binary data. This changed with the introduction of the Typed Array API, whose main use cases are:

  • Processing binary data: manipulating image data in HTML Canvas elements, parsing binary files, handling binary network protocols, etc.
  • Interacting with native APIs: Native APIs often receive and return data in a binary format, which you could neither store nor manipulate well in traditional JavaScript. That meant that whenever you were communicating with such an API, data had to be converted from JavaScript to binary and back, for every call. Typed Arrays eliminate this bottleneck. One example of communicating with native APIs is WebGL, for which Typed Arrays were initially created. Section “History of Typed Arrays” of the article “Typed Arrays: Binary Data in the Browser” (by Ilmari Heikkinen for HTML5 Rocks) has more information.

Two kinds of objects work together in the Typed Array API:

  • Buffers: Instances of ArrayBuffer hold the binary data.
  • Views: provide the methods for accessing the binary data. There are two kinds of views:
    • An instance of a Typed Array constructor (Uint8Array, Float64Array, etc.) works much like a normal Array, but only allows a single type for its elements and doesn’t have holes.
    • An instance of DataView lets you access data at any byte offset in the buffer, and interprets that data as one of several types (Uint8, Float64, etc.).

This is a diagram of the structure of the Typed Array API (notable: all Typed Arrays have a common superclass):

Typed Arrays were a separate specification before they became part of the ECMAScript 6 standard.

Element types

The following element types are supported by the API:

Element type Bytes Description C type
Int8 1 8-bit signed integer signed char
Uint8 1 8-bit unsigned integer unsigned char
Uint8C 1 8-bit unsigned integer (clamped conversion) unsigned char
Int16 2 16-bit signed integer short
Uint16 2 16-bit unsigned integer unsigned short
Int32 4 32-bit signed integer int
Uint32 4 32-bit unsigned integer unsigned int
Float32 4 32-bit floating point float
Float64 8 64-bit floating point double

The element type Uint8C is special: it is not supported by DataView and only exists to enable Uint8ClampedArray. This Typed Array is used by the canvas element (where it replaces CanvasPixelArray). The only difference between Uint8C and Uint8 is how overflow and underflow are handled (as explained in the next section). It is recommended to avoid the former – quoting Brendan Eich:

Just to be super-clear (and I was around when it was born), Uint8ClampedArray is totally a historical artifact (of the HTML5 canvas element). Avoid unless you really are doing canvas-y things.

Handling overflow and underflow

Normally, when a value is out of the range of the element type, modulo arithmetic is used to convert it to a value within range. For signed and unsigned integers that means that:

  • One plus the highest value is converted to the lowest value (0 for unsigned integers).
  • One minus the lowest value is converted to the highest value.

Modulo conversion for unsigned 8-bit integers:

    > let uint8 = new Uint8Array(1);
    > uint8[0] = 255; uint8[0] // highest value within range
    255
    > uint8[0] = 256; uint8[0] // overflow
    0
    > uint8[0] = 0; uint8[0] // lowest value within range
    0
    > uint8[0] = -1; uint8[0] // underflow
    255

Modulo conversion for signed 8-bit integers:

    > let int8 = new Int8Array(1);
    > int8[0] = 127; int8[0] // highest value within range
    127
    > int8[0] = 128; int8[0] // overflow
    -128
    > int8[0] = -128; int8[0] // lowest value within range
    -128
    > int8[0] = -129; int8[0] // underflow
    127

Clamped conversion is different:

  • All underflowing values are converted to the lowest value.
  • All overflowing values are converted to the highest value.
    > let uint8c = new Uint8ClampedArray(1);
    > uint8c[0] = 255; uint8c[0] // highest value within range
    255
    > uint8c[0] = 256; uint8c[0] // overflow
    255
    > uint8c[0] = 0; uint8c[0] // lowest value within range
    0
    > uint8c[0] = -1; uint8c[0] // underflow
    0

Endianness

Whenever a type (such as Uint16) is stored as multiple bytes, endianness matters:

  • Big endian: the most significant byte comes first. For example, the Uint16 value 0xABCD is stored as two bytes – first 0xAB, then 0xCD.
  • Little endian: the least significant byte comes first. For example, the Uint16 value 0xABCD is stored as two bytes – first 0xCD, then 0xAB.

Endianness tends to be fixed per CPU architecture and consistent across native APIs. Typed Arrays are used to communicate with those APIs, which is why their endianness follows the endianness of the platform and can’t be changed.

On the other hand, the endianness of protocols and binary files varies and is fixed across platforms. Therefore, we must be able to access data with either endianness. DataViews serve this use case and let you specify endianness when you get or set a value.

Quoting Wikipedia on Endianness:

  • Big-endian representation is the most common convention in data networking; fields in the protocols of the Internet protocol suite, such as IPv4, IPv6, TCP, and UDP, are transmitted in big-endian order. For this reason, big-endian byte order is also referred to as network byte order.
  • Little-endian storage is popular for microprocessors in part due to significant historical influence on microprocessor designs by Intel Corporation.

You can use the following function to determine the endianness of a platform.

    const BIG_ENDIAN = Symbol('BIG_ENDIAN');
    const LITTLE_ENDIAN = Symbol('LITTLE_ENDIAN');
    function getPlatformEndianness() {
        let arr32 = Uint32Array.of(0x12345678);
        let arr8 = new Uint8Array(arr32.buffer);
        switch ((arr8[0]*0x1000000) + (arr8[1]*0x10000) + (arr8[2]*0x100) + (arr8[3])) {
            case 0x12345678:
                return BIG_ENDIAN;
            case 0x78563412:
                return LITTLE_ENDIAN;
            default:
                throw new Error('Unknown endianness');
        }
    }

There are also platforms that arrange words (pairs of bytes) with a different endianness than bytes inside words. That is called mixed endianness. Should you want to support such a platform then it is easy to extend the previous code.

Negative indices

With the bracket operator [ ], you can only use non-negative indices (starting at 0). The methods of ArrayBuffers, Typed Arrays and DataViews work differently: every index can be negative. If it is, it counts backwards from the length. In other words, it is added to the length to produce a normal index. Therefore -1 refers to the last element, -2 to the second-last, etc. Methods of normal Arrays work the same way.

    > let ui8 = Uint8Array.of(0, 1, 2);
    > ui8.slice(-1)
    Uint8Array [ 2 ]

Offsets, on the other hand, must be non-negative. If, for example, you pass -1 to:

    DataView.prototype.getInt8(byteOffset)

then you get a RangeError.

ArrayBuffers

ArrayBuffers store the data, views (Typed Arrays and DataViews) let you read and change it. In order to create a DataView, you need to provide its constructor with an ArrayBuffer. Typed Array constructors can optionally create an ArrayBuffer for you.

ArrayBuffer constructor

The signature of the constructor is:

    ArrayBuffer(length : number)

Invoking this constructor via new creates an instance whose capacity is length bytes. Each of those bytes is initially 0.

Static ArrayBuffer methods

  • ArrayBuffer.isView(arg)
    Returns true if arg is an object and a view for an ArrayBuffer. Only Typed Arrays and DataViews have the required internal property [[ViewedArrayBuffer]]. That means that this check is roughly equivalent to checking whether arg is an instance of a Typed Array or of DataView.

ArrayBuffer.prototype properties

  • get ArrayBuffer.prototype.byteLength
    Returns the capacity of this ArrayBuffer in bytes.

  • ArrayBuffer.prototype.slice(start, end)
    Creates a new ArrayBuffer that contains the bytes of this ArrayBuffer whose indices are greater than or equal to start and less than end. start and end can be negative (see Sect. “Negative indices”).

Typed Arrays

The various kinds of Typed Array are only different w.r.t. to the type of their elements:

  • Typed Arrays whose elements are integers: Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array
  • Typed Arrays whose elements are floats: Float32Array, Float64Array

Typed Arrays versus normal Arrays

Typed Arrays are much like normal Arrays: they have a length, elements can be accessed via the bracket operator [ ] and they have all of the standard Array methods. They differ from Arrays in the following ways:

  • All of their elements have the same type, setting elements converts values to that type.
  • They are contiguous. Normal Arrays can have holes (indices in the range [0, arr.length) that have no associated element), Typed Arrays can’t.
  • Initialized with zeros. This is a consequence of the previous item:
    • new Array(10) creates a normal Array without any elements (it only has holes).
    • new Uint8Array(10) creates a Typed Array whose 10 elements are all 0.
  • An associated buffer. The elements of a Typed Array ta are not stored in ta, they are stored in an associated ArrayBuffer that can be accessed via ta.buffer.

Typed Arrays are iterable

Typed Arrays implement a method whose key is Symbol.iterator and are therefore iterable (consult chapter “Iterables and iterators” in “Exploring ES6” for more information). That means that you can use the for-of loop and similar mechanisms in ES6:

    let ui8 = Uint8Array.of(0,1,2);
    for (let byte of ui8) {
        console.log(byte);
    }
    // Output:
    // 0
    // 1
    // 2

ArrayBuffers and DataViews are not iterable.

Converting Typed Arrays to and from normal Arrays

To convert a normal Array to a Typed Array, you make it the parameter of a Typed Array constructor. For example:

    > let tarr = new Uint8Array([0,1,2]);

The classic way to convert a Typed Array to an Array is to invoke Array.prototype.slice on it. This trick works for all Array-like objects (such as arguments) and Typed Arrays are Array-like.

    > Array.prototype.slice.call(tarr)
    [ 0, 1, 2 ]

In ES6, you can use the spread operator (...), because Typed Arrays are iterable:

    > [...tarr]
    [ 0, 1, 2 ]

Another ES6 alternative is Array.from(), which works with either iterables or Array-like objects:

    > Array.from(tarr)
    [ 0, 1, 2 ]

The Species pattern

Some methods create new instances that are similar to this. The species pattern lets you configure what constructor should be used to do so. For example, if you create a subclass MyArray of Array then the default is that map() creates instances of MyArray. If you want it to create instances of Array, you can use the species pattern to make that happen. Details are explained in Sect “The species pattern” in “Exploring ES6”.

ArrayBuffers use the species pattern in the following locations:

  • ArrayBuffer.prototype.slice()
  • Whenever an ArrayBuffer is cloned inside a Typed Array or DataView.

Typed Arrays use the species pattern in the following locations:

  • TypedArray.prototype.filter()
  • TypedArray.prototype.map()
  • TypedArray.prototype.slice()
  • TypedArray.prototype.subarray()

DataViews don’t use the species pattern.

The inheritance hierarchy of Typed Arrays

As you could see in the diagram at the beginning of this post, all Typed Array classes (Uint8Array etc.) have a common superclass. I’m calling that superclass TypedArray, but it is not directly accessible from JavaScript (the ES6 specification calls it the intrinsic object %TypedArray%). TypedArray.prototype houses all methods of Typed Arrays.

Static TypedArray methods

Both static TypedArray methods are inherited by its subclasses (Uint8Array etc.).

TypedArray.of()

This method has the signature:

    TypedArray.of(...items)

It creates a new Typed Array that is an instance of this (the class on which of() was invoked). The elements of that instance are the parameters of of().

You can think of of() as a custom literal for Typed Arrays:

    > Float32Array.of(0.151, -8, 3.7)
    Float32Array [ 0.151, -8, 3.7 ]
TypedArray.from()

This method has the signature:

    TypedArray<U>.from(source : Iterable<T>, mapfn? : T => U, thisArg?)

It converts the iterable source into an instance of this (a Typed Array).

For example, normal Arrays are iterable and can be converted with this method:

    > Uint16Array.from([0, 1, 2])
    Uint16Array [ 0, 1, 2 ]

Typed Arrays are iterable, too:

    > let ui16 = Uint16Array.from(Uint8Array.of(0, 1, 2));
    > ui16 instanceof Uint16Array
    true

The optional mapfn lets you transform the elements of source before they become elements of the result. Why perform the two steps mapping and conversion in one go? Compared to performing the first step separately, via source.map(), there are two advantages:

  1. No intermediate Array or Typed Array is needed.
  2. When converting a Typed Array to a Typed Array whose elements have a higher precision, the mapping step can make use of that higher precision.

To illustrate the second advantage, let’s use map() to double the elements of a Typed Array:

    > Int8Array.of(127, 126, 125).map(x => 2 * x)
    Int8Array [ -2, -4, -6 ]

As you can see, the values overflow and are coerced into the Int8 range of values. If map via from(), you can choose the type of the result so that values don’t overflow:

    > Int16Array.from(Int8Array.of(127, 126, 125), x => 2 * x)
    Int16Array [ 254, 252, 250 ]

According to Allen Wirfs-Brock, mapping between Typed Arrays was what motivated the mapfn parameter of from().

TypedArray.prototype properties

Indices accepted by Typed Array methods can be negative (they work like traditional Array methods that way). Offsets must be non-negative. For details, see Sect. “Negative indices”.

Methods specific to Typed Arrays

The following properties are specific to Typed Arrays, normal Arrays don’t have them:

  • get TypedArray.prototype.buffer : ArrayBuffer
    Returns the buffer backing this Typed Array.
  • get TypedArray.prototype.byteLength : number
    Returns the size in bytes of this Typed Array’s buffer.
  • get TypedArray.prototype.byteOffset : number
    Returns the offset where this Typed Array “starts” inside its ArrayBuffer.
  • TypedArray.prototype.set(arrayOrTypedArray, offset=0)
    Copies all elements of arrayOrTypedArray to this Typed Array. The element at index 0 of arrayOrTypedArray is written to index offset of this Typed Array (etc.).
    • If arrayOrTypedArray is a normal Array, its elements are converted to numbers who are then converted to the element type T of this Typed Array.
    • If arrayOrTypedArray is a Typed Array then each of its elements is converted directly to the appropriate type for this Typed Array. If both Typed Arrays have the same element type then faster, byte-wise copying is used.
  • TypedArray.prototype.subarray(begin=0, end=this.length) : TypedArray
    Returns a new Typed Array that has the same buffer as this Typed Array, but a (generally) smaller range. If begin is non-negative then the first element of the resulting Typed Array is this[begin], the second this[begin+1] (etc.). If begin in negative, it is converted appropriately.
Array methods

The following methods are basically the same as the methods of normal Arrays:

  • TypedArray.prototype.copyWithin(target : number, start : number, end = this.length) : This
    Copies the elements whose indices are between start (including) and end (excluding) to indices starting at target. If the ranges overlap and the former range comes first then elements are copied in reverse order to avoid overwriting source elements before they are copied.
  • TypedArray.prototype.entries() : Iterable
    Returns an iterable over [index,element] pairs for this Typed Array.
  • TypedArray.prototype.every(callbackfn, thisArg?)
    Returns true if callbackfn returns true for every element of this Typed Array. Otherwise, it returns false. every() stops processing the first time callbackfn returns false.
  • TypedArray.prototype.fill(value, start=0, end=this.length) : void
    Set the elements whose indices range from start to end to value.
  • TypedArray.prototype.filter(callbackfn, thisArg?) : TypedArray
    Returns a Typed Array that contains every element of this Typed Array for which callbackfn returns true. In general, the result is shorter than this Typed Array.
  • TypedArray.prototype.find(predicate : T => boolean, thisArg?) : T
    Returns the first element for which the function predicate returns true.
  • TypedArray.prototype.findIndex(predicate : T => boolean, thisArg?) : number
    Returns the index of the first element for which predicate returns true.
  • TypedArray.prototype.forEach(callbackfn, thisArg?) : void
    Iterates over this Typed Array and invokes callbackfn for each element.
  • TypedArray.prototype.indexOf(searchElement, fromIndex=0) : number
    Returns the index of the first element that strictly equals searchElement. The search starts at fromIndex.
  • TypedArray.prototype.join(separator : string = ',') : string
    Converts all elements to strings and concatenates them, separated by separator.
  • TypedArray.prototype.keys() : Iterable
    Returns an iterable over the indices of this Typed Array.
  • TypedArray.prototype.lastIndexOf(searchElement, fromIndex?) : number
    Returns the index of the last element that strictly equals searchElement. The search starts at fromIndex, backwards.
  • get TypedArray.prototype.length : number
    Returns the length of this Typed Array.
  • TypedArray.prototype.map(callbackfn, thisArg?) : TypedArray
    Returns a new Typed Array in which every element is the result of applying callbackfn to the corresponding element of this Typed Array.
  • TypedArray.prototype.reduce(callbackfn : (previousValue : any, currentElement : T, currentIndex : number, array : TypedArray) => any, initialValue?) : any
    callbackfn is fed one element at a time, together with the result that was computed so far and computes a new result. Elements are visited from left to right.
  • TypedArray.prototype.reduceRight(callbackfn : (previousValue : any, currentElement : T, currentIndex : number, array : TypedArray) => any, initialValue?) : any
    callbackfn is fed one element at a time, together with the result that was computed so far and computes a new result. Elements are visited from right to left.
  • TypedArray.prototype.reverse() : This
    Reverses the order of the elements of this Typed Array and returns this.
  • TypedArray.prototype.slice(start=0, end=this.length) : TypedArray
    Create a new Typed Array that only has the elements of this Typed Array whose indices are between start (including) and end (excluding).
  • TypedArray.prototype.some(callbackfn, thisArg?)
    Returns true if callbackfn returns true for at least one element of this Typed Array. Otherwise, it returns false. some() stops processing the first time callbackfn returns true.
  • TypedArray.prototype.sort(comparefn? : (number, number) => number)
    Sorts this Typed Array, as specified via comparefn. If comparefn is missing, sorting is done ascendingly, by comparing via the less-than operator (<).
  • TypedArray.prototype.toLocaleString(reserved1?, reserved2?)
  • TypedArray.prototype.toString()
  • TypedArray.prototype.values() : Iterable
    Returns an iterable over the values of this Typed Array.

Due to all of these methods being available for Arrays, you can consult the following two sources to find out more about how they work:

  • The following methods are new in ES6 and explained in chapter “New Array features” of “Exploring ES6”: copyWithin, entries, fill, find, findIndex, keys, values.
  • All other methods are explained in chapter “Arrays” of “Speaking JavaScript”.

"ElementType»Array constructor

Each Typed Array constructor has a name that follows the pattern "ElementType»Array, where "ElementType» is one of the element types in the table at the beginning. That means that there are 9 constructors for Typed Arrays: Int8Array, Uint8Array, Uint8ClampedArray (element type Uint8C), Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array.

Each constructor has five overloaded versions – it behaves differently depending on how many arguments it receives and what their types are:

  • "ElementType»Array(buffer, byteOffset=0, length?)
    Creates a new Typed Array whose buffer is buffer. It starts accessing the buffer at the given byteOffset and will have the given length. Note that length counts elements of the Typed Array (with 1–4 bytes each), not bytes.

  • "ElementType»Array(length)
    Creates a Typed Array with the given length and the appropriate buffer (whose size in bytes is length * "ElementType»Array.BYTES_PER_ELEMENT).

  • "ElementType»Array()
    Creates a Typed Array whose length is 0. It also creates an associated empty ArrayBuffer.

  • "ElementType»Array(typedArray)
    Creates a new Typed Array that has the same length and elements as typedArray. Values that are too large or small are converted appropriately.

  • "ElementType»Array(arrayLikeObject)
    Treats arrayLikeObject like an Array and creates a new TypedArray that has the same length and elements. Values that are too large or small are converted appropriately.

The following code shows three different ways of creating the same Typed Array:

    let tarr = new Uint8Array([1,2,3]);
    
    let tarr = Uint8Array.of(1,2,3);
    
    let tarr = new Uint8Array(3);
    tarr[0] = 0;
    tarr[1] = 1;
    tarr[2] = 2;

Static "ElementType»Array properties

  • "ElementType»Array.BYTES_PER_ELEMENT
    Counts how many bytes are needed to store a single element:

        > Uint8Array.BYTES_PER_ELEMENT
        1
        > Int16Array.BYTES_PER_ELEMENT
        2
        > Float64Array.BYTES_PER_ELEMENT
        8
    

"ElementType»Array.prototype properties

  • "ElementType»Array.prototype.BYTES_PER_ELEMENT
    The same as "ElementType»Array.BYTES_PER_ELEMENT.

DataViews

DataView constructor

  • DataView(buffer, byteOffset=0, byteLength=buffer.byteLength-byteOffset)
    Creates a new DataView whose data is stored in the ArrayBuffer buffer. By default, the new DataView can access all of buffer, the last two parameters allow you to change that.

DataView.prototype properties

  • get DataView.prototype.buffer
    Returns the ArrayBuffer of this DataView.

  • get DataView.prototype.byteLength
    Returns how many bytes can be accessed by this DataView.

  • get DataView.prototype.byteOffset
    Returns at which offset this DataView starts accessing the bytes in its buffer.

  • DataView.prototype.get"ElementType»(byteOffset, littleEndian=false)
    Reads a value from the buffer of this DataView.

    • "ElementType» can be: Float32, Float64, Int8, Int16, Int32, Uint8, Uint16, Uint32
  • DataView.prototype.set"ElementType»(byteOffset, value, littleEndian=false)
    Writes value to the buffer of this DataView.

    • "ElementType» can be: Float32, Float64, Int8, Int16, Int32, Uint8, Uint16, Uint32

Browser APIs that support Typed Arrays

Typed Arrays have been around for a while, so there are quite a few browser APIs that support them.

File API

The file API lets you access local files. The following code demonstrates how to get the bytes of a submitted local file in an ArrayBuffer.

    let fileInput = document.getElementById('fileInput');
    let file = fileInput.files[0];
    let reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = function () {
        let arrayBuffer = reader.result;
        ···
    };

XMLHttpRequest

In newer versions of the XMLHttpRequest API, you can have the results delivered in an ArrayBuffer:

    let xhr = new XMLHttpRequest();
    xhr.open('GET', someUrl);
    xhr.responseType = 'arraybuffer';
    
    xhr.onload = function () {
        let arrayBuffer = xhr.response;
        ···
    };
    
    xhr.send();

Fetch API

Similarly to XMLHttpRequest, the Fetch API lets you request resources. But it is based on Promises, which makes it more convenient to use. The following code demonstrates how to download the content pointed to by url as an ArrayBuffer:

    fetch(url)
    .then(request => request.arrayBuffer())
    .then(arrayBuffer => ···);

Canvas

Quoting the HTML5 specification:

The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, art, or other visual images on the fly.

The 2D Context of canvas lets you retrieve the bitmap data as an instance of Uint8ClampedArray:

    let canvas = document.getElementById('my_canvas');
    let context = canvas.getContext('2d');
    let imageData = context.getImageData(0, 0, canvas.width, canvas.height);
    let uint8ClampedArray = imageData.data;

WebSockets

WebSockets let you send and receive binary data via ArrayBuffers:

    let socket = new WebSocket('ws://127.0.0.1:8081');
    socket.binaryType = 'arraybuffer';
    
    // Wait until socket is open
    socket.addEventListener('open', function (event) {
        // Send binary data
        let typedArray = new Uint8Array(4);
        socket.send(typedArray.buffer);
    });
    
    // Receive binary data
    socket.addEventListener('message', function (event) {
        let arrayBuffer = event.data;
        ···
    });

Other APIs

  • WebGL uses the Typed Array API for: accessing buffer data, specifying pixels for texture mapping, reading pixel data, and more.

  • The Web Audio API lets you decode audio data submitted via an ArrayBuffer.

  • Media Source Extensions: The HTML media elements are currently and . The Media Source Extensions API enables you to create streams to be played via those elements. You can add binary data to such streams via ArrayBuffers, Typed Arrays or DataViews.

  • Communication with Web Workers: If you send data to a Worker via postMessage(), either the message (which will be cloned) or the transferable objects can contain ArrayBuffers.

  • Cross-document communication: works similarly to communication with Web Workers and also uses the method postMessage().

Extended example: JPEG SOF0 decoder

The code of the following example is on GitHub. And you can run it online.

The example is a web pages that lets you upload a JPEG file and parses its structure to determine the height and the width of the image and more.

The JPEG file format

A JPEG file is a sequence of segments (typed data). Each segment starts with the following four bytes:

  • Marker (two bytes): declares what kind of data is stored in the segment. The first of the two bytes is always 0xFF. Each of the standard markers has a human readable name. For example, the marker 0xFFC0 has the name “Start Of Frame (Baseline DCT)”, short: “SOF0”.
  • Length of segment (two bytes): how long is this segment (in bytes, including the length itself)?

JPEG files are big-endian on all platforms. Therefore, this example demonstrates how important it is that we can specify endianness when using DataViews.

The JavaScript code

The following function processArrayBuffer() is an abridged version of the actual code; I’ve removed a few error checks to reduce clutter. processArrayBuffer() receives an ArrayBuffer with the contents of the submitted JPEG file and iterates over its segments.

    // JPEG is big endian
    var IS_LITTLE_ENDIAN = false;
    
    function processArrayBuffer(arrayBuffer) {
        try {
            var dv = new DataView(arrayBuffer);
            ···
            var ptr = 2;
            while (true) {
                ···
                var lastPtr = ptr;
                enforceValue(0xFF, dv.getUint8(ptr),
                    'Not a marker');
                ptr++;
                var marker = dv.getUint8(ptr);
                ptr++;
                var len = dv.getUint16(ptr, IS_LITTLE_ENDIAN);
                ptr += len;
                logInfo('Marker: '+hex(marker)+' ('+len+' byte(s))');
                ···
    
                // Did we find what we were looking for?
                if (marker === 0xC0) { // SOF0
                    logInfo(decodeSOF0(dv, lastPtr));
                    break;
                }
            }
        } catch (e) {
            logError(e.message);
        }
    }

This code uses the following helper functions (that are not shown here):

  • enforceValue() throws an error if the expected value (first parameter) doesn’t match the actual value (second parameter).
  • logInfo() and logError() display messages on the page.
  • hex() turns a number into a string with two hexadecimal digits.

decodeSOF0() parses the segment SOF0:

    function decodeSOF0(dv, start) {
        // Example (16x16):
        // FF C0 00 11 08 00 10 00 10 03 01 22 00 02 11 01 03 11 01
        var data = {};
        start += 4; // skip marker 0xFFC0 and segment length 0x0011
        var data = {
            bitsPerColorComponent: dv.getUint8(start), // usually 0x08
            imageHeight: dv.getUint16(start+1, IS_LITTLE_ENDIAN),
            imageWidth: dv.getUint16(start+3, IS_LITTLE_ENDIAN),
            numberOfColorComponents: dv.getUint8(start+5),
        };
        return JSON.stringify(data, null, 4);
    }

More information on the structure of JPEG files:

Availability

Much of the Typed Array API is implemented by all modern JavaScript engines, but several features are new to ECMAScript 6:

  • Static methods borrowed from Arrays: TypedArray.from(), TypedArray.of()
  • Prototype methods borrowed from Arrays: TypedArray.prototype.map() etc.
  • Iterable Typed Arrays
  • Support for the species pattern
  • An inheritance hierarchy where TypedArray is the superclass of all Typed Array classes

It may take a while until these are available everywhere. As usual, kangax’ “ES6 compatibility table” describes the status quo.

Source:: 2ality

Quick Tip: The Simplest Way To Center Elements Vertically And Horizontally

By Danny Markov

the-simple-way-to-center

Flexbox is a relatively new addition to the CSS world and we keep finding more and more excellent applications for it. We can even solve the age-old problem with centering an element both vertically and horizontally with CSS. It is easier than you can imagine – it is only three lines of code, doesn’t require you to specify the size of the centered element and is responsive-friendly!

(Play with our code editor on Tutorialzine.com)

The HTML

The idea, of course, revolves around flexbox (see the browser support). First, we create a container in which we want everything to be centered:

<div class="container">
    <!--// Any content in here will be centered.-->
    <img src="fireworks.jpg" alt="fireworks">
</div>

You can place this container div anywhere you want. In the live example above we’ve made it take up the whole width and height of the page.

The CSS

As we said earlier, we will be using only three lines of code. Here they are:

.container{
    display: flex;
    justify-content: center;
    align-items: center;
}

Every flex container has two axis for positioning elements. The main axis is declared with the flex-direction property (can be row or column, see docs). By omitting this rule, we’ve left the flex direction to its default row value.

Now all that we need to do is center both axis. It couldn’t get any simpler:

  1. Make the display type flex, so that we activate flexbox mode.
  2. justify-content defines where flex items will align according to the main axis (horizontally in our case).
  3. align-items does the same with the axis perpendicular to the main one (vertically in our case).

Now that we have set the rules for the vertical and the horizontal alignment to center, any element we add inside the container will be positioned perfectly in the middle. We don’t need to know its dimensions beforehand, the browser will do all the hard work!

Conclusion

There are lots of other techniques for centering content with CSS, but flexbox makes this a whole lot simpler and more elegant. If you wish to learn more about it, check out these resources:

  • A complete guide to flexbox – here.
  • MDN: Using CSS flexible boxes (a long read) – here.
  • Flexbox in 5 minutes – here.

Source:: Tutorialzine.com