Технопарк, осень, 2025 г.
let/const, шаблонные строки, Promise, стрелочные функцииSharedArrayBuffer и Atomicsconsole.log(typeof foo);console.log(typeof bar);var foo = 'bar';if (false) {var bar = 42;}
console.log(typeof foo); // undefinedconsole.log(typeof bar); // undefinedvar foo = 'bar';if (false) {var bar = 42;}
let / constif (true) {let bar = 42;}console.log(typeof foo); // ReferenceErrorconsole.log(typeof bar); // ReferenceErrorconst foo = 'bar';foo = 'baz'; // TypeError
const name = 'Jon Snow';const answer = 40;const res = `Hello, ${name}! Answer is ${answer + 2}`console.log(res); // Hello, Jon Snow! Answer is 42const multiline = `First line`Second line`Third line`;multiline.split('\n').length === 3; // true
// unicode supportconsole.log('😀'.length); // 2console.log('\u{1F600}'); // 😀console.log('\uD83D\uDE00'); // 😀String.prototype.charAt(index); '😀'.charAt(0) === �String.prototype.charCodeAt(index); '😀'.charCodeAt(0) === 55357String.prototype.codePointAt(index); '😀'.codePointAt(0) === 128512
const переменная = 42;const джонни = {имя: 'Jon',фамилия: 'Snow',возраст: 20};function распечатать (пользователь) {console.log(`${пользователь.имя} ${пользователь.фамилия}`);console.log(`Возраст ${пользователь.возраст} лет`);}распечатать(джонни);
// ECMAScript 2015 featuresString.prototype.includes(searchString, position = 0)String.prototype.endsWith(searchString, position = length)String.prototype.startsWith(searchString, position = 0)String.prototype.repeat(times)// ECMAScript 2017 featuresString.prototype.padStart(maxLength, fillString=' ')String.prototype.padEnd(maxLength, fillString=' ')
function getJSON(url) {return new Promise(function (resolve, reject) {const xhr = new XMLHttpRequest();xhr.open('GET', url, true);xhr.onreadystatechange = function () {if (xhr.readyState === 4) {resolve(JSON.parse(xhr.responseText));}}}}
getJSON('/data/books.json').then(function (books) {books.forEach(function (book) {console.log(book.title);});}).catch(function (error) {console.error(error);});.finally(function () {console.log('Promise ends');});
// Вернёт промис в состоянии fulfilled («выполнено успешно»)Promise.resolve( ... );// Вернёт промис в состоянии rejected («выполнено с ошибкой»)Promise.reject( ... );// Выполнит все промисы "параллельно"Promise.all( [ ... ] );// Вернёт промис, выполнившийся раньше всехPromise.race( [ ... ] );
const hello = () => console.log('Hello, World!');const sqr = num => num * 2;[1, 2, 3, 4].map(sqr); // [1, 4, 9, 16]const compare = (left, right) => {if (left.length === right.length) {return left.localeCompare(right);}return left.length - right.length;}
this и своего
			arguments: берут их их
			LexicalEnvironment
		newclass User {constructor(login, password) {this._login = login;this._password = password;}hello() {console.log('Hello, ' + this._login);}}
class MathUtils {static sqr(number) {return number * number;}static abs(number) {return number < 0 ? -number : number;}}
const user1 = new User('Alex', 'qwerty123');const user2 = new User('Jon', 'passw0rd');user1.hello(); // Hello, Alexuser2.hello(); // Hello, JonMathUtils.sqr(6); // 36MathUtils.abs(-42); // 42
class Shape {constructor(width, height) {this._width = width;this._height = height;}get Square() { return this._width * this._height; }set SideLength(value) {this._width = this._height = value;}}
const shape = new Shape(6, 12);console.log(shape.Square); // 72shape.SideLength = 7;console.log(shape.Square); // 49
class View {constructor(el) {this._el = el;}hide() {this._el.hidden = true;}}
class LoginView extends View {constructor() {super(document.getElementById('login'));this._form = this._el.querySelector('.login__form');}hide() {super.hide();this._form.clear();}}
// экспортируем значенияexport const PI = 4;export function square(number) { return number * number; }export default class User {constructor() { ... }}const name = 'Jon Snow', years = 42;export { name, years as age };
// импортируем значенияimport { PI, square } from '../module.js';import { name as login } from '../module.js';import UserClass from '../module.js';import * as Utils from '../module.js';import '../module.js';// ре-экспортexport { PI, login as username } from '../module.js';export * from '../module.js';
// es6 featuresconst login = 'Jon Snow', age = 42;const User = {login, age}; // {login: 'Jon Snow', age: 42}const Obj = {func: function () { ... }, // old wayfunc() { ... }, // inline methodsget Arr() { return this.array; }, // object getters & setters['foo' + 'bar']: value, // computed property namesarray: [1, 2, 3, 4, 5,], // trailing commasprop: value, // trailing commas}
// es8 featuresfunction UseFull (param1 ,param2 ,param3 , // trailing commas) { return param1 + param2 + param3; }UseFull (42 ,100500 ,-200600 , // trailing commas); // -100058
// проверка двух выражений на совпадениеObject.is(value1, value2);Object.is(1, 1); // trueObject.is(1, '1'); // falseObject.is(false, false); // trueObject.is({a: 42}, {a: 42}); // falseObject.is(NaN, NaN); // true (NaN === NaN) === falseObject.is(0, -0); // false (-0 === 0) === true
// копирование свойствObject.assign(target, source, source, source, ...);const s1 = {a: 'Jon'}, s2 = {b: 42};const result = Object.assign({}, s1, s2);// result: {// a: 'Jon',// b: 42// }
// Запаковывание объектовObject.seal(target); // можно изменить значение имеющихся свойств,// но нельзя добавить или удалить их// Заморозка объектовObject.freeze(target); // нельзя изменять значения имеющихся свойств,// удалять их, добавлять новыеObject.isFrozen(target); Object.isSealed(target);
// Перебор ключей, значений и свойствconst user = {login: 'Jon Snow', age: 42};Object.keys(user); // ['login', 'age']Object.values(user); // ['Jon Snow', 42]Object.entries(user); // [['login', 'Jon Snow'], ['age', 42]]
Map — хэш-таблицаconst map = new Map();map.set(key, value); // добавить значениеmap.get(key); // получить значениеmap.has(key); // проверить наличие ключаmap.delete(key); map.clear();map.size; // размер Mapmap.forEach(callback); // перебор ключей, свойств, значенийmap.values(); map.keys(); map.entries();
Set — набор значенийconst set = new Set();set.add(value); // добавить значениеset.has(value); // проверить наличие значенияset.delete(value); set.clear();set.size; // размер Setset.forEach(callback); // перебор ключей, свойств, значенийset.values(); set.keys(); set.entries();
ReflectВстроенный JavaScript объект, предоставляющий методы для перехвата взаимодействий с объектами и работы с рефлексией в JavaScript
Reflect.apply(target, thisArgument, argumentsList)Reflect.construct(target, argumentsList)Reflect.get(target, propertyKey)Reflect.has()Reflect.getPrototypeOf(target)Reflect.setPrototypeOf(target, prototype)
// Reflect.defineProperty(target, propertyKey, attributes)const object = {};Reflect.defineProperty(object, 'foo', {enumerable: false, // разрешает перечислениеwritable: false, // разрешает перезаписьconfigurable: false, // разрешает изменение дескриптораvalue: undefined // значение свойстваget: undefined // геттерset: undefined // сеттер}
// hello python from es7console.log(3 ** 4); // 81console.log(49 ** 0.5); // 7
Приехало в ECMAScript 2018
// новый флаг s (dotAll)/foo.bar/.test('foo\nbar'); // false/foo.bar/s.test('foo\nbar'); // true// именованные группы в RegExplet re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;let result = re.exec('2018-04-06');// result.groups.year === '2018';// result.groups.month === '04';// result.groups.day === '06';
SharedArrayBuffer и Atomics
	// mainconst worker = new Worker(scriptUrl); // создали воркер// const sharedWorker = new SharedWorker(scriptUrl);worker.postMessage({hello: 'world'}); // отправили данныеworker.onmessage = function(e) { e.data ... }; // обработчик onmessage
// workerself.onmessage = function(e) { e.data... }; // обработчик onmessageself.postMessage({hello: 'world'}); // отправили данные
SharedArrayBuffer и Atomicsconst buffer = new ArrayBuffer(15 * 1024 * 1024); // 15 MB RAMworker.postMessage(buffer); // клонирует данныеconst shared = new SharedArrayBuffer(length); // разделяемая памятьworker.postMessage(shared); // клонирует данныеAtomics.add(typedArray, pos, val); // потокобезопасное сложениеAtomics.sub(typedArray, pos, val); // потокобезопасное вычитаниеAtomics.store(typedArray, pos, val); // потокобезопасная записьAtomics.load(typedArray, pos); // потокобезопасное чтениеAtomics.wait(typedArray, pos, val[, timeout]); // like as Linux futexes...
// деструктуризацияconst [name, family] = 'Jon Snow'.split(' ');console.log(name); // Jonconsole.log(family); // Snow// пропуск элементовconst [, , var3, var4] = [1, 2, 3, 4];const [num1, , num3] = [1, 2, 3, 4];
// значения по умолчаниюconst [name, family = 'Black'] = ['Jon'];console.log(name); // Jonconsole.log(family); // Black// swap переменныхlet title1 = 'Book 1', title2 = 'Book 2';([title1, title2] = [title2, title1]); // title1 === 'Book 2'// title2 === 'Book 1'
const person = {login: 'Jon Snow', age: 42, alive: true};// деструктуризацияconst {login, age} = person;// значения по умолчаниюconst {login, age, password = 'qwerty123'} = person;// переименование свойствconst {login: username, age} = person; // username === 'Jon Snow'// комбинацияconst {login: username = 'Anonimous', age} = person;
// вложенная деструктуризацияconst element = {tagName: 'DIV', size: {width: 300, height: 200}};const {tagName: tag,size: {width: w = 250, height: h = 250} = {},color = 'red',childs: [first, second, , last] = []} = element;console.log({tag, w, h, color, first, second, last});
function sruare({width: w, height: h = 100}) {return w * h;}square({width: 20, height: 50, color: 'red'}); // 1000square({width: 42}); // 4200
const [posts, messages, user] = Promise.all([fetch('/posts'),fetch('/messages'),fetch('/me')]);const [xlarge, large, medium, small, xsmall] = Promise.all(['xl', 'l', 'm', 's', 'xs'].map(size => fetch(`/profile/${size}-logo.png`)););
function figure({width: w = 10, height: h = 10, length: l = 20}) {return w * h * l;}const width = 15, height = 25, length = 50;const args = {width: width,height: height,length: length,};volume(args); // 18750
function figure({width: w = 10, height: h = 10, length: l = 20}) {return w * h * l;}const width = 15, height = 25, length = 50;const args = {width,height,length,};volume(args); // 18750
function figure({width: w = 10, height: h = 10, length: l = 20}) {return w * h * l;}const width = 15, height = 25, length = 50;const args = { width, height, length };volume(args); // 18750
function figure({width: w = 10, height: h = 10, length: l = 20}) {return w * h * l;}const width = 15, height = 25, length = 50;volume({ width, height, length }); // 18750
function figure({width: w = 10, height: h = 10, length: l = 20}) {return w * h * l;}const width = 15, height = 25, length = 50;volume({ width, height, length }); // 18750volume({ height, width, length }); // 18750volume({ height, width }); // 7500volume({ }); // 2000
// расширение массивовconst arr = ['a', 'b', 'c', 'd'];const arr2 = [1, 2, ...arr, 3];console.dir(arr2); // [1, 2, 'a', 'b', 'c', 'd', 3];
// используется при деструктуризацииconst scoreboard = ['Jane', 'Jon', 'Alex', 'Max'];const [first, second, ...loosers] = scoreboard;// first === 'Jane'// second === 'Jon'// loosers === ['Alex', 'Max']
// может проитерироваться по элементам коллекции// и вернуть массив, состоящий из её элементовconst letters = [...'abcde'];console.dir(letters); // ['a', 'b', 'c', 'd', 'e'];// panes будет настоящим массивомconst panes = [...document.querySelectorAll('.pane')];
// передача параметров в функциюconst numbers = [1, 2, 42, 532, -3.14, -Infinity];const maximum = ... ?const minimum = ... ?const maximum = Math.max.apply(null, numbers); // 532const minimum = Math.min.apply(null, numbers); // -Infinity
// передача параметров в функциюconst numbers = [1, 2, 42, 532, -3.14, -Infinity];const maximum = Math.max(...numbers); // 532const minimum = Math.min(...numbers); // -Infinity
// сбор праметров функцииfunction summ(...nums) {// можно работать не с arguments, а с настоящим массивом numsreturn nums.reduce((sum, current) => sum + current, 0);}console.log(summ(1, 2, 3, 4, 5)); // 15
// сбор праметров функцииfunction split(coeff, ...nums) {return nums.filter(num => num < coeff);}console.log(split(3.14, 1, 2, 3, 4, 5)); // [1, 2, 3]
const name = { first: 'Jon', last: 'Snow' };const address = {city: 'Norilsk',country: 'Russian Federation',street: 'Leninskiy Prospect',};const profile = {age: 20,...name,...address,}
const {login, password, ...profile} = {login: 'Jon',password: 'qwerty123',age: 42,city: 'Norilsk',birthdate: '30.03.2000'};console.log(profile);// { age: 42, city: 'Norilsk', birthdate: '30.03.2000' }
		Number
Boolean
String
Object
null
		undefined
Symbol
Reference
List
Completion
		Property Descriptor
Lexical Environment
Environment Record
Data Block
...
	
// без newconst symbol1 = Symbol();const symbol2 = Symbol('label');const symbol3 = Symbol('label');console.log(typeof symbol1); // symbolconsole.log(symbol2 == symbol3); // falseconsole.log(symbol2 === symbol3); // falseconsole.log(symbol1); // 'Symbol()'console.log(symbol2); // 'Symbol(label)'
// берутся из реестра глобальных символов// если символа нет в реестре - создаётся новый символconst symbol1 = Symbol.for('label');const symbol2 = Symbol.for('label');console.dir(symbol1 == symbol2); // trueconst symbol3 = Symbol('label');console.dir(Symbol.keyFor(symbol1)); // 'label'console.dir(Symbol.keyFor(symbol3)); // undefined
const User = {name: 'Jon Snow',[Symbol.for('hello')]() {console.log(`Hello, ${this.name}!`);}}User[Symbol.for('hello')](); // 'Hello, Jon Snow!'const helloSymbol = Symbol.for('hello');User[helloSymbol](); // 'Hello, Jon Snow!'
Symbol.hasInstanceSymbol.iteratorSymbol.replaceSymbol.searchSymbol.toPrimitiveSymbol.toStringTag...
Итераторы — расширяющая понятие «массив» концепция, которая пронизывает современный стандарт JavaScript сверху донизу. Итерируемые или, иными словами, «перебираемые» объекты — это те, содержимое которых можно перебрать в цикле
В общем смысле,
		итератор — это объект, предоставляющий метод next(), который возвращает
		следующий элемент определённой последовательности. Для перебора итераторов существует специальный цикл for
			... of
const numbers = [2, 3, 5, 7, 11, 13];for (const prime of numbers) {console.log(`Prime number ${prime}!`);}
// оператор расширения итерируется по итератору// и возвращает массив из элементов итератораfunction arrayUniq()const source = [...arguments];// Set.prototype.values() возвращает итератор по элементам коллекцииreturn [...new Set(source).values()];}
Symbol.iteratorconst iterable = [1, 2, 3, 4];const iterator = iterable[Symbol.iterator]();console.log(iterator.next()); { value: 1, done: false }console.log(iterator.next()); { value: 2, done: false }console.log(iterator.next()); { value: 3, done: false }console.log(iterator.next()); { value: 4, done: false }console.log(iterator.next()); { value: undefined, done: true }console.log(iterator.next()); { value: undefined, done: true }
const iterable = {current: 0,[Symbol.iterator]() { return this; },next() {if (this.current) {return { value: this.current--, done: false };}return { value: undefined, done: true }}}
iterable.current = 7;const elements = [...iterable]; // [ 7, 6, 5, 4, 3, 2, 1 ]iterable.current = 5;let summ = 0;for (const n of iterable) {summ += n;}console.log(summ); // 15
function * generator() {yield 1;yield 2;return 3;}const generator = function * () {yield 1; yield 2; return 3;};
const gen = generator();console.log(gen.next()); // { value: 1, done: false }console.log(gen.next()); // { value: 2, done: false }console.log(gen.next()); // { value: 3, done: true }console.log(gen.next()); // { value: undefined, done: true }console.log(gen.next()); // { value: undefined, done: true }const gen2 = generator(); // console.log([...gen2])
function * fibonacci() {let prev = 1, curr = 0;while (true) {let now = prev + curr;prev = curr; curr = now;yield now;}}
function * rand(length) {while (length--) {yield Math.random();}}console.log([...rand(3)]); // [ 0.216, 0.39, 0.555 ]console.log([...rand(5)]); // [ 0.782, 0.806, 0.294, 0.228, 0.755 ]
function * simple() {let num = yield 'line 2';return num;}const gen = simple();console.log(gen.next()); // { value: 'line 2', done: false }console.log(gen.next(42)); // { value: 42, done: true }console.log(gen.next()); // { value: undefined, done: true }
function * wow() {let num = 0, sum = 0;while (num = yield sum) {sum += num;}return sum;}
const gen = wow();gen.next(); // { value: 0, done: false }gen.next(1); // { value: 1, done: false }gen.next(2); // { value: 3, done: false }gen.next(3); // { value: 6, done: false }gen.next(4); // { value: 10, done: false }gen.next(5); // { value: 15, done: false }gen.next(0); // { value: 15, done: true }
const gen = wow();gen.next(); // { value: 0, done: false }gen.next(1); // { value: 1, done: false }gen.throw(new Error('kek')); // Error: kekgen.next(0); // до этого места выполнение не дойдёт
function * twicer(element) {yield element; yield element;}function * test() {yield * twicer(42);yield * twicer('test');}console.log([...test()]); // [ 42, 42, 'test', 'test' ]
async/await)
	async/awaitКлючевое слово
asyncпозволяет объявлять асинхронные функции, которые возвращают промис. Внутри таких функций возможна "синхронная" работа с промисами с помощью ключевого словаawait
Код, использующий async/await-функции очень похож на код, написанный на генераторах с
		использованием библиотеки co
async function good() {return 42;}good().then(res => console.log('Good: ', res);
async function bad() {throw new Error('kek');}good().then(res => console.log('Good: ', res));.catch(err => console.error(err));
async function luck(num) {if (Math.random() < 0.5) {return num * 2;}throw new Error('kek');}luck(21).then(res => console.log('Good: ', res)); // may be 42.catch(err => console.error(err)); // or may be an Error
async function loadJSON(url) {const response = await fetch(url, {method: 'GET'});if (response.statusCode !== 200) {throw new Error(`Can not load json ${url}`);}const json = await response.json();return json;}
async function load(query) {const list = await fetchList(query);const result = await Promise.all(list.map(item => loadItem(item)));return result;}
async function load(query) {const list = await fetchList(query);return Promise.all(list.map(item => loadItem(item)));}
function readFiles(names) {return names.map(filename => promiseRead(filename))}for (const pRead of readFiles([...])) {const source = await pRead;// logic ...}
for-await-offor await (const source of readFiles([...])) {console.log(source)// logic ...}
Незаменимо, когда заранее не известно количество итерируемых элементов
async function* readLines(path) {let file = await fileOpen(path);try {while (!file.EOF) {yield await file.readLine();}} finally {await file.close();}}
for await (const line of readLines(filePath)) {console.log(line)// logic ...}
ProxyОбъест Proxy (Прокси) — особый объект, смысл которого — перехватывать обращения к другому объекту и, при необходимости, модифицировать их
// создание Proxyconst proxy = new Proxy(target, handler);// target - объект, обращения к которому надо перехватывать// handler - объект с функциями-перехватчиками для операций к target
Proxyconst user = {};const proxy = new Proxy(user, {get (target, property, receiver) {console.log(`Чтение ${property}`);return target[property];},set (target, property, value, receiver) {console.log(`Запись ${property} = ${value}`);target[property] = value;return true;},});
Proxyproxy.name = 'Jon Snow'; // Запись name = Jon Snowproxy.age = 22; // Запись age = 22proxy['long property'] = 'qux'; // Запись long property = quxconst name = proxy.name; // Чтение nameconst age = proxy.age; // Чтение ageconst long = proxy['long property']; // Чтение long property
Proxyconst handler = {get (target, name, receiver); // получение свойствset (target, name, val, receiver); // установка свойстваapply (target, thisValue, args); // вызовы функцииconstruct (target, args); // вызовы конструктора с newhas (target, name); // оператор indefineProperty (target, property, descriptor);// метод Object.defineProperty()deleteProperty (target, property); // оператор delete...};
Proxyconst original = {};const magic = wrapWithProxy(original);magic.data.elements[0].attributes.color = 'black';magic.country.map.shops = [ ... ];
Proxy: jewellimport { jewellPrototype } from 'jewell';jewellPrototype(Array);const diamonds = [...];// Get price: [2k, 100k, 300k]diamonds.map(diamond => diamond.price); // Traditionaldiamonds.map.price; // 💎// Buy all pink diamondsdiamonds.filter(diamond => diamond.pink).forEach(diamond => diamond.buy()); // Traditionaldiamonds.filter.pink.forEach.buy(); // 💎
 
	 
	Полифилл — это библиотека, которая добавляет в старые браузеры поддержку возможностей, которые в современных браузерах являются встроенными
if (!Object.is) {Object.is = function(x, y) {if (x === y) { return x !== 0 || 1 / x === 1 / y; }else { return x !== x && y !== y; }}}
Транспайлинг — это конвертация кода программы, написанной на одном языке программирования в другой язык программирования
// beforeconst f = num => `${num} в квадрате это ${num ** 2}`;// aftervar f = function (num) {return num + ' в квадрате это ' + Math.pow(num, 2);};
Babel — многофункциональный транспайлер, позволяет транспиллировать ES5, ES6, ES2016, ES2017, ES2018, ES.Next, JSX и Flow
Babel REPL — бабель-онлайн
# устанавливаем модуль$ npm install -D @babel/core @babel/cli @babel/preset-env# файл с конфигурацией$ nano .babelrc{"presets": [["@babel/env",{ targets: {edge: "15"}}]]}# запускаем$ babel modern.js --watch --out-file compatible.js
ES.Next — так временно называют совокупность новых возможностей языка, которые могут войти в следующую версию спецификации. Фичи из ES.Next правильнее называть “предложения” (proposals) , потому что они всё ещё находятся на стадии обсуждения
TC39 (технический комитет 39) — занимается развитием JavaScript. Его членами являются компании (помимо прочих, все основные производители браузеров). TC39 регулярно собирается, на встречах присутствуют участники, представляющие интересы компаний, и приглашенные эксперты
Процесс TC39 — алгоритм внесения изменений в спецификацию ECMAScript. Каждое предложение по добавлению новой возможности в ECMAScript в процессе созревания проходит ряд этапов
import { flying } from 'abilities';class Creature {constructor({ name, ...rest}) {console.log(`Привет, ${name}, твои свойства:`, rest);}}@flyingclass Dragon extends Creature {static haveTail = true;legs = 4;async *eat(...staff) {// Eat something...}}
import 'dart:async';import 'dart:math' show Random;Stream<double> computePi({int batch: 1000000}) async* { ... }main() async {print('Compute π using the Monte Carlo method.');await for (var estimate in computePi()) {print('π ≅ $estimate');}}
class Humanconstructor : (@name) ->class Baby extends Humansay : (msg) -> alert "#{@name} говорит '#{msg}'"saymsg = (msg) -> alert msg@echo = (msg) -> console.log msgmatt = new Baby("Матвей")matt.sayHi()
if happy and knowsItlyrics = while num -= 1"#{num} little monkeys, jumping on the bed"elsedate = if friday then sue else jillfor filename in listdo (filename) ->fs.readFile filename, (err, contents) ->compile filename, contents.toString()
(ns hello-world.core(:require [cljs.nodejs :as nodejs]))(nodejs/enable-util-print!)(defn -main [& args](println "Hello world!"))(set! *main-cli-fn* -main)
import Html exposing (text)main =text (toString (zip ["Tom", "Sue", "Bob"] [45, 31, 26]))zip : List a -> List b -> List (a,b)zip xs ys =case (xs, ys) of( x :: xBack, y :: yBack ) ->(x,y) :: zip xBack yBack(_, _) ->[]
interface Person {name: string;age: number;}function meet(person: Person) {return `Привет, я ${person.name}, мне ${parson.age}`;}const user = { name: "Jane", age: 21 };console.log(meet(user));
TypeScript — язык программирования, представленный Microsoft в 2012 году. TypeScript является обратно совместимым с JavaScript и компилируется в последний. TypeScript отличается от JavaScript возможностью явного статического назначения типов, а также поддержкой подключения модулей
Разработчиком языка TypeScript является Андерс Хейлсберг (англ. Anders Hejlsberg), создавший ранее Turbo Pascal, Delphi и C#.
TypeScript Deep Dive — крутая книга по TypeScript
*.js в *.ts# установка компилятора$ npm install -g typescript# компиляция файла$ tsc helloworld.ts# утилита позволяет компилировать и сразу запускать .ts файлы$ npm install -g ts-node$ ts-node script.ts
tsconfig.json{"compilerOptions": {"outDir": "cache/","target": "es2016","declaration": false,"module": "commonjs","strictNullChecks": true,"sourceMap": true...}}
const valid: boolean = true;const count: number = 42;const man: string = 'Jon Snow';console.log(man * 2);// Error: The left-hand side of an arithmetic// operation must be of type 'any', 'number' or an enum type
Вывод типов (англ. type inference) — в программировании возможность компилятора самому логически вывести тип значения у выражения.
const valid = true;const count = 42;const man = 'Jon Snow';console.log(man * 2);// Error: The left-hand side of an arithmetic// operation must be of type 'any', 'number' or an enum type
const valid = true;const count = 42;const man: any = 'Jon Snow';console.log(man * 2); //NaN// Зато нет TS ошибок!// Profit!
const valid = true;const count = 42;const name = 'Jon Snow';const values: number[] = [1, 2, 3, 4, 5];const tuple: [string, number] = ['Mean of life', 42];enum Color {Red, Green, Blue};const c: Color = Color.Green;
let some: any = true; some = 42;some = 'maybe a string instead'; // типы не проверяются// приведение типов (“trust me, I know what I’m doing”)let length: number = (<string>some).length;length = (some as string).length;let unusable: void = undefined;let u: undefined = undefined;let n: null = null;
function sum(x: number, y: number): number {return x + y;}const many: number = sum(40, 2);const gcd = (a: number, b: number): number =>(b === 0) ? a : gcd(b, a % b);console.log(gcd(48, 30)); // 6
function sum(x: number, y?: number): number {if (y) {return x + y;} else {return x;}}console.log(sum(34, 8)); // 42console.log(sum(42)); // OK! - 42
function sum(x: number, y: number = 42): number {return x + y;}console.log(sum(34, 8)); // 42console.log(sum(42)); // OK! - 84
function sum(...numbers: number[]): number {return numbers.reduce((sum: number, current: number): number => {sum += current; return sum;}, 0);}console.log(sum(1, 2, 3, 4, 5)); // 15console.log(sum(42, 0, -10, 5, 5)); // 42
function square(num: number): number;function square(num: string): number;function square(num: any): number {if (typeof num === 'string') {return parseInt(num, 10) * parseInt(num, 10);} else {return num * num;}}
function square(num: string | number): number {if (typeof num === 'string') {return parseInt(num, 10) * parseInt(num, 10);} else {return num * num;}}
interface Figure {width: number;readonly height: number;}const square: Figure = {width: 42, height: 42};square.width = 15; // OKsquare.height = 15; // Cannot assign to read-only property
interface Figure {width: number;height: number;}interface Square extends Figure {square: () => number;}const sq = {width: 15, height: 20,square() { return this.width * this.height; } };sq.square(); // 300
abstract class Class1 {abstract func1(): void; // необходимо определить в наследниках}class Class2 extends Class1 {static readonly field3: string = 'hello';protected name: string;private field1: number;constructor() { super(); }public func1(): void { ... }}
interface Squarable {calcSomething(): number;}class Square implements Squarable {width: number;height: number;// Error: Class 'Square' incorrectly implements interface 'Squarable'.// Property 'calcSomething' is missing in type 'Square'.}
class Queue<T> {private data = [];push = (item: T) => this.data.push(item);pop = (): T => this.data.shift();}const queue = new Queue<number>();queue.push(0); // OKqueue.push('1'); // Error: cannot push a string
function makeKeyValue<K, V>(key: K, value: V): { key: K; value: V } {return {key, value};}const pair = makeKeyValue('days', ['ПН', 'ВТ']);pair.value.push('СР', 'ЧТ', 'ПТ', 'СБ', 'ВС'); // OKpair.value.push(42); // Error: cannot push a number
class Utils {@memoizestatic fibonacci (n: number): number {return n < 2 ? 1 : Utils.fibonacci(n - 1) + Utils.fibonacci(n - 2)}}console.time('count');console.log(Utils.fibonacci(50));console.timeEnd('count'); // оооочень долго
function memoize (target, key, descriptor) {const originalMethod = descriptor.value;const cash = {};descriptor.value = function (n: number): number {return cash[n] ? cash[n] : cash[n] = originalMethod(n);}}console.log(Utils.fibonacci(1000)); // 7.0330367711422765e+208console.timeEnd('count'); // count: 5.668ms
TypeScript Declaration Files (
.d.ts) — служат для описания интерфейсов, экспортируемых классов и методов для модулей, написанных на обычном JavaScript
.d.ts файлыinterface JQueryStatic {ajax(settings: JQueryAjaxSettings): JQueryXHR;(element: Element): JQuery;(html: string, ownerDocument?: Document): JQuery;(): JQuery;}declare var $: JQueryStatic;declare module 'jquery' {export = $;}
JSDoc// Пример типизирования функции с помощью JSDoc + TypeScript/*** @param p0 {string} - Строковый аргумент объявленный на манер TS* @param {string} p1 - Строковый аргумент* @param {string=} p2 - Опциональный аргумент* @param {string} [p3] - Другой опциональный аргумент* @param {string} [p4="test"] - Аргумент со значением по-умолчанию* @return {string} Возвращает строку*/function fn3(p0, p1, p2, p3, p4){// TODO}
        // @flow
        function concat(a /*: string */, b /*: string */) {
            return a + b;
        }
         
        concat('A', 'B'); // Works!
        concat(1, 2); // Error!
         
	
Во время создания WebAssembly решалась следующая задача: быстро исполнять код в браузере
WebAssembly (wasm) — эффективный низкоуровневый байт-код, предназначенный для исполнения в браузере. WebAssemblу представляет собой переносимое абстрактное синтаксическое дерево, обеспечивающее как более быстрый парсинг, так и более быстрое выполнение кода, чем JavaScript — developers.google.com
WebAssembly — это не полная замена JS, а лишь технология, позволяющая писать критичные к ресурсам модули и компилировать их в переносимый байт-код с линейной моделью памяти и статической типизацией
Применения: редактирование изображений/видео/музыки, криптография, математические вычисления, игры...
// исходник на Cint fib(int n) {if (n == 0) { return 0; } else {if ((n == -1) || (n == 1)) { return 1; } else {if (n > 0) { return fib(n - 1) + fib(n - 2); }else { return fib(n + 2) - fib(n + 1); }}}}
// текстовое представление WAST(module(table 0 anyfunc)(memory $0 1)(data (i32.const 12) "\01\00\00\00\00\00\00\00\01\00\00\00")(export "memory" (memory $0))(export "fib" (func $fib))(func $fib (param $0 i32) (result i32)(local $1 i32)(block $label$0(br_if $label$0(i32.ge_u// ...
// скомпилированный байт-код wasmconst wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,134,128,128,128,0,1,96,1,127,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,144,128,128,128,0,2,6,109,101,109,111,114,121,2,0,3,102,105,98,0,0,10,203,128,128,128,0,1,197,128,128,128,0,1,1,127,2,64,32,0,65,1,106,34,1,65,3,79,13,0,32,1,65,2,116,65,12,106,40,2,0,15,11,2,64,32,0,65,1,72,13,0,32,0,65,127,106,16,0,32,0,65,126,106,16,0,106,15,11,32,0,65,2,106,16,0,32,1,16,0,107,11,11,146,128,128,128,0,1,0,65,12,11,12,1,0,0,0,0,0,0,0,1,0,0,0]);
// запускаем wasm-модуль// создаем типизированный массивconst wasmCode = new Uint8Array([...]);// компилируем WASMconst wasmModule = new WebAssembly.Module(wasmCode);// получаем инстанс готовый к работеconst wasmInstance = new WebAssembly.Instance(wasmModule, []);console.log(wasmInstance.exports.fib(10));
AssemblyScript — компилятор TypesScript в WebAssembly. Т.к. TypesScript статически типезированный, то мы можем его скомпилить в WebAssembly. Можно использовать специальные типы