Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   JS.next(стандарты, фичи, движки) (https://javascript.ru/forum/offtopic/50248-js-next-standarty-fichi-dvizhki.html)

trikadin 04.11.2015 20:06

Цитата:

Сообщение от Safort
Кароче, посоны, Object.observe выпиливают https://mail.mozilla.org/pipermail/e...er/044684.html

Ну блин. Это же офигенно полезная штука, какого чёрта?

FINoM 04.11.2015 20:08

trikadin, на самом деле, акцессоры рулят. Могу холиварить об этом долго.

Mаxmaxmаximus 04.11.2015 23:28

FINoM, назови мне аксессор на удаение свойства?
аксессоры медленнеее обсерверов.
аксессоры заставляют тебя изменять обьект если ты хочешь его прослушивать хотя возможно это изменение слмоает обьект.

сделай мне обсервинг массива на аксессорах, устанавливай и удаляй их каждый раз при изменении длины. А потом пробегись циклом по десяти тысячному массиву, вызывая 10 тысяч аксессоров и.т.п.

в общем ты не обижайся но ты слабо разбираешься в теме раз сравниваешь аксессоры и обсервинг. они для разных целей, и аксессоры совершенно не предназначены для отслеживания изменений, они предназначены для контролирования заливки значения и возможного реагирования на его изменение ИЗНУТРИ обьекта, снаружи для этой цели служат обсерверы.

Mаxmaxmаximus 04.11.2015 23:31

Пасоны я не понял че та, они решили выпилить из стандарта фитчу которую придумали? Окей а как они предлагают тогда обсервить обьекты и массивы? А как же фреймворки которые построенные на Object.observe?

trikadin 05.11.2015 00:58

Цитата:

Сообщение от FINoM
trikadin, на самом деле, акцессоры рулят. Могу холиварить об этом долго.

У тебя есть объект, в котором нужно отслеживать добавление/удаление произвольных свойств. Расскажи, как это сделать на аксессорах? Ещё аксессоры синхронные (как и прокси), а О.о -- нет.

Короче, нет смысла спорить об этом, у проксей, аксессоров и О.о -- разные сферы применения, это как спорить, что лучше -- гвоздь или шуруп.

devote 05.11.2015 10:52

Цитата:

Сообщение от trikadin
что лучше -- гвоздь или шуруп.

шуруп конечно, он по структуре сложнее :D

trikadin 05.11.2015 12:30

devote, ага, и забить его молотком можно, а вот гвоздь вкрутить не получится :D

Вот мы и будем, похоже, шурупы молотком забивать, изобретая свои 100500 велосипедов на проксях вместо "гвоздя" O.o

FINoM 05.11.2015 13:43

Цитата:

Сообщение от Mаxmaxmаximus
назови мне аксессор на удаение свойства?

Это минус акцессоров, да.
Цитата:

Сообщение от trikadin
в котором нужно отслеживать добавление/удаление произвольных свойств.

O.o - это костыль, причем достаточно медленный, если сравнивать с акцессорами. Не буду тут развивать тему в этом топике, я уже написал здесь, что я думаю об обсерверах и акцессорах.

FINoM 05.11.2015 13:57

Лично меня в defineProperty привлекает скорость и последовательность (читай, синхронность).

На самом деле, было бы круто иметь симбиоз O.o, Proxy и defineProperty. Сейчас все три технологии имеют свои минусы.

1. O.o не умеет слушать отдельные свойства, не умеет быть синхронным без вызова deliverChangeRecords.
2. Proxy не поддерживает асинхронность, не умеет слушать отдельные свойства, не позволяет работать с объектом напрямую.
3. defineProperty не умеет слушать delete и не может быть асинхронным.

В идеале, хотелось бы видеть один API, который:
- Позволяет опционально включить асинхронность.
- Позволяет, по выбору программиста, слушать все изменения или изменения отдельных свойств (например, длины массива) для увелиения производительности.
- Из изменений слушает delete, get, set.
- Слушает set, не заставляя перезаписывать акцессор.
- Позволяет работать с объектом напрямую.
- Позволяет, как и прокси, переопределить стандартное поведение JavaScript (например, при delete, не удалять свойство, а запускать произвольный код).

Мне не очень нравится идея удаления О.о из спецификации, но если этот ход ведет к созданию единого API, который сочетает в себе плюсы всех трех технологий, я только за. Но пока, если я правильно понимаю, ничего такого не предвидится.

trikadin 05.11.2015 16:59

Цитата:

Сообщение от FINoM
O.o - это костыль, причем достаточно медленный, если сравнивать с акцессорами.

Можно пруфов? Странновато звучит -- асинхронные события (которые ещё и накапливаются, к тому же) медленнее, чем синхронные вызовы функций?

trikadin 05.11.2015 17:12

Цитата:

Сообщение от FINoM
Не буду тут развивать тему в этом топике, я уже написал здесь, что я думаю об обсерверах и акцессорах.

Дочитал до раздела "Производительность", охренел, пардон, от того, что там написано.

Object.observe -- асинхронный, блин, он вызывается в следующем лупе! Во время цикла вотчер не был вызван ни разу. В то время как геттер, конечно же, честно вызывался на каждой итерации (ибо синхронный) и увеличивал себе счётчик на единичку, т. е. на две за каждую итерацию. Хм, почему же он победил?..

FINoM 05.11.2015 17:24

trikadin, что-то я тебя не понимаю. Тест показывает насколько быстро О.о собирает изменения. j++ - это просто плейсхолдер, который ничего не делает.

trikadin 05.11.2015 17:39

FINoM, а, да, я неправ, приношу свои извинения.

Интересно тогда, конечно, почему так. Положили хер на оптимизацию?..

FINoM 05.11.2015 19:31

trikadin, тест еще не учитывает доставки изменений, которая тоже будет "стоить" несколько микро/миллисекунд.

trikadin 05.11.2015 21:18

FINoM, не знаю, мне кажется, что это просто типа "вот мы разработали модуль, если им кто-нибудь будет нормально пользоваться -- заоптимизируем". А поскольку аксессоры юзают много и часто -- их и задрочили.

FINoM 05.11.2015 21:23

Цитата:

Сообщение от trikadin
А поскольку аксессоры юзают много и часто -- их и задрочили.

Эм. Разве они так часто используются?

trikadin 05.11.2015 22:11

FINoM, O_o

Ну лично я их юзаю везде. А DOM целиком из них состоит вообще.

FINoM 06.11.2015 15:35

Цитата:

Сообщение от trikadin
Ну лично я их юзаю везде.

Ну таких упоротых как мы, насколько известно - немного.
Цитата:

Сообщение от trikadin
А DOM целиком из них состоит вообще.

Вот бы можно было бы навешать акцессор на стандартные свойства (value, innerHTML...), не убивая встроенный, мир бы стал добрее.

trikadin 06.11.2015 15:49

Цитата:

Сообщение от FINoM
Вот бы можно было бы навешать акцессор на стандартные свойства (value, innerHTML...)

А MutationObserver тебе чем не угодил?

Кстати да, несомненное преимущество обсервера перед аксессорами и проксями -- в том, что один объект может наблюдать сразу много разных наблюдателей, и им не придётся думать друг о друге, и они не будут друг другу никак мешать.

FINoM 06.11.2015 15:53

Цитата:

Сообщение от trikadin
А MutationObserver тебе чем не угодил?

Судя по доке он слушает все изменения ноды, а это медленно.

trikadin 06.11.2015 16:06

FINoM, плохо доку прочитал) Там есть фильтры, можно слушать только те атрибуты, которые тебе нужны (смотри "attributeFilter").

И да, раньше были MutationEvents, они были синхронными, и вот это было действительно медленно.

trikadin 06.11.2015 16:07

И ещё: по поводу value -- меня полностью удовлетворяет oninput event (который, кстати, срабатывает и для элементов с contenteditable="true").

FINoM 06.11.2015 16:09

trikadin, дык, понятно, я могу слушать oninput, но я хочу слушать изменение свойства, а не DOM событие или изменение атрибута.

loljs 06.11.2015 16:48

Цитата:

Сообщение от FINoM (Сообщение 394803)
Судя по доке он слушает все изменения ноды, а это медленно.

Да вроде нет, там конкретно указывается, что слушать, а что нет. И непонятно, зачем тебе тут скорость нужна вообще. Он отрабатывает только на событие. Что у тебя, миллион событий в секунду чтоли происходит?

FINoM 06.11.2015 16:59

Цитата:

Сообщение от loljs
Что у тебя, миллион событий в секунду чтоли происходит?

Я хочу реализовать двусторонний байндинг, а там да, может быть очень много элементов.

trikadin 06.11.2015 19:39

FINoM, так чем MutationObserver не устраивает, в итоге? Если ты начнёшь наблюдать за одним атрибутом value, то ты получишь оповещение о его изменении, что тебе и нужно, и при этом это будет асинхронно, что хорошо, ибо не тормозит отрисовку DOM'а.

FINoM 06.11.2015 19:57

trikadin, я имею в виду не атрибут а свойство. Его разве можно слушать?

trikadin 06.11.2015 20:12

FINoM, ну, ты узнаёшь об обновлении атрибута, и, соответственно, свойства, которое с ним синхронизировано. Не понимаю, видимо, в чём твоя проблема.

FINoM 06.11.2015 20:14

trikadin, эм, я никогда не работаю с атрибутами, если есть возможность изменить свойство.

trikadin 06.11.2015 20:37

Цитата:

Сообщение от FINoM
trikadin, эм, я никогда не работаю с атрибутами, если есть возможность изменить свойство.

И? Проблема-то в чём? Вряд ли ты добавляешь DOM-объекту нестандартные свойства (у которых нет сопоставленных им атрибутов), а даже если, то вот как раз их ты можешь объявить аксессорами, а те свойства, у которых есть сопоставленные атрибуты, ты можешь слушать через MutationObserver.

<a id="search-link" href="http://google.com/" data-search="google" title="Гугл">Google</a>
<script>
'use strict';
const 
  link = document.querySelector('#search-link'),
  observer = new MutationObserver((mutationsList) => {
    console.log(mutationsList);
  });

observer.observe(link, {
  childList: true,
  attributes: true
});

link.href = 'http://yandex.ru/';
link.title = 'Яндекс';
link.dataset.search = 'yandex';
link.textContent = 'Yandex';
</script>


Смотреть в консоль.

FINoM 06.11.2015 20:41

trikadin, а, сорри. Не проверил сам. Думал, что свойства не работают.

trikadin 06.11.2015 20:57

Цитата:

Сообщение от FINoM
trikadin, а, сорри. Не проверил сам. Думал, что свойства не работают.

Так что темак весьма полезный, плюс отлично поддерживается ;)

Проблема в том, что для дата-биндинга куда актуальнее отслеживать не изменения в DOM (потому что, как правило, нужно отслеживать только ввод в текстовые поля), а объекты в JS.

Кстати, я тут подумал -- в твой бенчмарк по измерению скорости, по-честному, нужно добавить ситуацию, когда отслеживаемых свойств больше одного -- скажем, несколько десятков. Интересно, какая будет ситуация тогда.

FINoM 06.11.2015 21:00

Цитата:

Сообщение от trikadin
Кстати, я тут подумал -- в твой бенчмарк по измерению скорости, по-честному, нужно добавить ситуацию, когда отслеживаемых свойств больше одного -- скажем, несколько десятков. Интересно, какая будет ситуация тогда.

Сорри, нет возможности этим заниматься. Если хочешь, велкам. Лицензия - WTFPL :)

trikadin 06.11.2015 21:19

FINoM, если будет время и желание. Хотя смысла теперь в этом немного: фича только в хроме, все остальные браузеры, даже если и собирались имплементить, то теперь радостно забьют на нее (депрекейтед же).

Octane 29.01.2016 19:50

await yield

nerv_ 21.03.2016 15:21

Далеко не все разработчики успели понять что-же такое ECMAScript2015,
а тут уже грядет ECMAScript2016, который, если ориентироваться на прошлый год, будет принять через пару-тройку месяцев. Например, на сайте Мозиллы заявлены typed-objects. Иными словами, в js потихоньку приходит типизация :)

UPD: https://github.com/hemanth/es7-features

kobezzza 21.03.2016 16:21

Я давно юзаю ES7 фичи, такие как асинки или декораторы :)

trikadin 21.03.2016 23:44

Цитата:

Сообщение от kobezzza
декораторы

Которые никогда уже не стандартизируют, по ходу.

И вообще набор фичей, достигших Stage 3, что-то не впечатляет.
https://github.com/tc39/ecma262/blob/master/README.md

nerv_ 22.03.2016 01:05

Цитата:

Сообщение от trikadin
И вообще набор фичей, достигших Stage 3, что-то не впечатляет.

есть такое дело

голосуем за опциональную типизацию

Malleys 31.12.2018 05:17

Я бы хотел предложить вариант, как могла бы выглядеть типизация в JavaScript.

Мне кажется, что предложенные варианты неявной типизации 1) синтаксически усложнены и 2) не учитывают некоторые особенности JavaScript

Тип объекта — ссылка на функцию, при помощи которой сконструирован объект (явно или неявно). null и undefined, а также объекты вида { __proto__: null } не имеют конструктора. Тип может быть простым и составным.

Простой тип объекта o может быть выведен при помощи o.constructor

Например, в следующем примере
const PI = 3.14159265;
const re = /a/gi;
const IS_PROXY = Symbol("is proxy");
const now = new Date();

простой тип констант PI, re, IS_PROXY и now выводится неявно как Number, RegExp, Symbol и Date соответственно.

Далее в рассуждениях я буду обозначать вид простого типа при помощи звёздочки *. Т. е. в примере выше объекты имели вид *.

Рассмотрим вычисленное выражение Promise.resolve(5). С одной стороны можно сказать, что оно имеет простой тип Promise. Однако начав работать с этим объектом, можно заметить, что оно не полностью описывает всё, что достижимо в этом объекте. Например, можно извлечь значение, которое хранится в Promise. На самом деле это тип Promise, который содержит тип Number. Это составной тип.
Рассмотрим вычисленное выражение ["id", 60]. Оно похоже на простой тип Array. Однако при помощи перебора элементов этого массива можно установить, что оно содержит достижимые объекты, которые тоже имеют свой тип. Это составной тип.
Рассмотрим вычисленное выражение (a, p) => `€ ${a * (1 - p / 100)}`. Оно похоже на простой тип Function. Однако исследуя аргументы и возвращаемый результат функций, т. е. то, что достижимо в любой функции, мы видим, что они имеют свой тип. Функция — составной тип.

Такие виды типов можно обозначить так:
Вид *<*> для типа, который зависит от другого типа, например тип Promise<Number>
Вид *<*, *> для типа, который зависит от двух других типов, например тип Array<String, Number>
Вид *<*, *, *> для типа, который зависит от трёх других типов, например тип Function<Number, Number, String>
Составной тип может зависеть от любого кол-ва типов. Зависящие типы — аргументы вида.
Также для составного типа можно определить тип хвоста. Например,
вид *<...*> показывает, что тип зависит от любого кол-ва одного и того же другого типа, например тип Set<...Number> для множества содержащего любое кол-во чисел.
вид *<*, ...*> показывает, что тип зависит от другого типа и любого кол-ва одного и того же третьего типа, например тип Array<RegExp, ...String> для массива, содержащего рег. выр. и любое кол-во строк.

Функция без аргумента имеет вид Function<*>, т. е. у её зависящего типа указывается только возвращаемый тип
Функция с одним аргументом имеет вид Function<*, *>, т. е. у её зависящих типов указывается тип аргумента и возвращаемый тип
Функция с двумя аргументами имеет вид Function<*, *, *>, т. е. у её зависящих типов указываются типы аргументов и возвращаемый тип и т. д.

Поскольку у видов Function последний аргумент указывает на тип возвращаемого значения, то тип хвоста списка аргументов указывается в списке типов вида предпоследним.
Вид Function<...*, *>, например тип Function<...Number, Boolean> для функции, которая принимает в качестве аргументов любое кол-во чисел и возвращает true или false.
Вид Function<*, ...*, *>, например тип Function<Array<String>, ...String, String> для функции, которая принимает массив строк и любое кол-во строк и возвращает строку и т. д.

В JavaScript может быть реализован достаточно мощный механизм вывода типов, который позволит не указывать типы функций. Можно будет указать тип функции явно для того, чтобы ограничить её использование только для конкретных типов данных, либо для структурированного оформления исходного кода.

Синтаксис типов (определение BindingIdentifier взято из 9-ого издания ECMAScript)

Код:

Type :
        BindingIdentifier
        BindingIdentifier < TypeParameters >

TypeParameters :
        TypeRestParameter
        TypeRestParameter , Type
        TypeParameterList
        TypeParameterList , TypeRestParameter
        TypeParameterList , TypeRestParameter , Type

TypeRestParameter :
        ... Type

TypeParameterList :
        Type
        TypeParameterList , Type

В 9-ом издании ECMAScript определённые синтаксические правила дополняются:

Код:

FormalParameter[Yield, Await] :
        BindingElement[?Yield, ?Await]
        Type WhiteSpace BindingElement[?Yield, ?Await]

MethodDefinition[Yield, Await] :
        PropertyName[?Yield, ?Await] ( UniqueFormalParameters[~Yield, ~Await] ) { FunctionBody[~Yield, ~Await] }
        Type WhiteSpace PropertyName[?Yield, ?Await] ( UniqueFormalParameters[~Yield, ~Await] ) { FunctionBody[~Yield, ~Await] }
        GeneratorMethod[?Yield, ?Await]
        AsyncMethod[?Yield, ?Await]
        AsyncGeneratorMethod[?Yield, ?Await]
        get PropertyName[?Yield, ?Await] ( ) { FunctionBody[~Yield, ~Await] }
        get Type WhiteSpace PropertyName[?Yield, ?Await] ( ) { FunctionBody[~Yield, ~Await] }
        set PropertyName[?Yield, ?Await] ( PropertySetParameterList ) { FunctionBody[~Yield, ~Await] }

Expression[In, Yield, Await] :
        AssignmentExpression[?In, ?Yield, ?Await]
        AssignmentExpression[?In, ?Yield, ?Await] :: Type
        Expression[?In, ?Yield, ?Await] , AssignmentExpression[?In, ?Yield, ?Await]
        Expression[?In, ?Yield, ?Await] , AssignmentExpression[?In, ?Yield, ?Await] :: Type

Хотя можно ещё более подробно указать в правилах синтаксиса, как можно использовать неявные типы, но я думаю, что для начала хватит такого определения. В этих правилах говорится, что у метода/сеттера может быть указан тип каждого аргумента. Также может быть указан возвращаемый тип метода/геттера.
Также любое выражение может быть снабжено типом. (так называемое типизированное выражение)

Возможно ключевое void стоит указывать там, где ожидается null или undefined? Например, функция alert может иметь тип Function<Object, void>

Посмотрите на примеры:

1. Деструктуризация по типу.
class Vector {
	constructor(Number x, Number y, Number z) {
		this.x = x
		this.y = y
		this.z = z
	}

	Vector add(Vector { x, y, z }) {
		return new Vector(
			this.x + x,
			this.y + y,
			this.z + z
		)
	}
}


Код выше работает так(это не значит, что он должен работать именно так, возможны оптимизации на уровне движка)
class Vector {
	constructor() {
		if(
			Object(arguments[0]) instanceof Number &&
			Object(arguments[1]) instanceof Number &&
			Object(arguments[2]) instanceof Number
		) {
			const [x, y, z] = arguments;
			this.x = x
			this.y = y
			this.z = z
		}

		else
			throw new TypeError("No method arises from provided arguments");
	}

	add() {
		if(
			Object(arguments[0]) instanceof Vector
		) {
			const [{x, y, z}] = arguments;
			return new Vector(
				this.x + x,
				this.y + y,
				this.z + z
			)
		}

		else
			throw new TypeError("No method arises from provided arguments");
	}
}




2. Перегрузка
class SomeClass {
	Number add(Number num1, Number num2) {
		return num1 + num2;
	}

	String add(String str1, String str2) {
		return str1 + str2;
	}
}


Это выполняется так
class SomeClass {
	add() {
		if(
			Object(arguments[0]) instanceof Number &&
			Object(arguments[1]) instanceof Number
		) {
			const [num1, num2] = arguments;
			return num1 + num2;
		} else

		if(
			Object(arguments[0]) instanceof String && 
			Object(arguments[1]) instanceof String
		) {
			const [str1, str2] = arguments;
			return str1 + str2;
		}

		else
			throw new TypeError("No method arises from provided arguments");
	}
}



Поскольку типы имеют свой собственный контекст, где они могут быть использованы, то я думаю, что можно ввести также литералы для типов.

Array или []
Array<Number> или [Number]
Array<...RegExp> или [...RegExp]
Array<String, Number> или [String, Number]
Array<String, ...String> или [String, ...String]

Function<Response, Array<Number>> или Response => [Number]
Function<Number> или () => Number
Function<...Number, Number> или (...Number) => Number
Function<Function<...Object, Array<Object>>, String> или ((...{}) => [{}]) => String


Часовой пояс GMT +3, время: 10:48.