Skip to content

About

Extensions proposal for ECMAScript

Resources

Code of conduct

Contributing

Security policy

Stars

176 stars

Watchers

35 watching

Forks

Latest commit

 

History

36 Commits

Folders and files

Repository files navigation

Extensions and :: operator

Proposal status

This is an ECMAScript (JavaScript) proposal in stage 1.

Note: The proposal could be seen as the reshape of the "virtual method" part of old bind operator proposal, see tc39/proposal-bind-operator#56.

Simple examples

Example of ad-hoc extension methods and accessors

// define two extension methods
const ::toArray = function () { return [...this] }
const ::toSet = function () { return new Set(this) }

// define a extension accessor
const ::allDivs = {
	get() { return this.querySelectorAll('div') }
}

// reuse built-in prototype methods and accessors
const ::flatMap = Array.prototype.flatMap
const ::size = Object.getOwnPropertyDescriptor(Set.prototype, 'size')

// Use extension methods and accesors to calculate
// the count of all classes of div element.
let classCount = document::allDivs
	::flatMap(e => e.classList::toArray())
	::toSet()::size

roughly equals to:

// define two extension methods
const $toArray = function () { return [...this] }
const $toSet = function () { return new Set(this) }

// define a extension accessor
const $allDivs = {
	get() { return this.querySelectorAll('div') }
}

// reuse built-in prototype method and accessor
const $flatMap = Array.prototype.flatMap
const $size = Object.getOwnPropertyDescriptor(Set.prototype, 'size')

// Use extension methods and accesors to calculate
// the count of all classes of div element.
let $
$ = $allDivs.get.call(document)
$ = $flatMap.call($, e => $toArray.call(e.classList))
$ = $toSet.call($)
$ = $size.get.call($)
let classCount = $

Example of using constructors or namespace object as extensions

// util.js
export const toArray = iterable => [...iterable]
export const toSet = iterable => new Set(iterable)
import * as util from './util.js'

const ::allDivs = {
	get() { return this.querySelectorAll('div') }
}

let classCount = document::allDivs
	::Array:flatMap(
		e => e.classList::util:toArray())
	::util:toSet()
	::Set:size

roughly equals to:

import * as util from './util.js'

const $allDivs = {
	get() { return this.querySelectorAll('div') }
}

let $
$ = $allDivs.get.call(document)
$ = Array.prototype.flatMap.call($,
	e => util.toArray(e.classList))
$ = util.toSet($)
$ = Object.getOwnPropertyDescriptor(Set.prototype, 'size').get.call($)
let classCount = $

Changes of the old bind operator proposal

  • keep obj::foo() syntax for extension methods
  • repurpose obj::foo as extension getters and add obj::foo = as extension setters
  • separate namespace for ad-hoc extension methods and accessors, do not pollute normal binding names
  • add obj::ext:name syntax
  • change operator precedence to same as .
  • remove ::obj.foo (use cases can be solved by custom extension + library, or other proposals)

Other matrials

About

Extensions proposal for ECMAScript

Resources

Code of conduct

Contributing

Security policy

Stars

176 stars

Watchers

35 watching

Forks

Used by

Contributors

Languages