С последната спецификация ECMAScript 6 или ES 6, в езика JavaScript са добавени много нови и полезни възможности, най-интересните от които можете да прочетете в тази статия. Пълният код на примерите можете да свалите от профила ми в Github
Декларация на променливи с let
let е ключовата дума, която заменя позната ни var за деклариране на променливи. За тези от вас, които не знаят, при var има проблеми свързани с видимостта на променливите (scope) и повторната им декларация като те са специфични за JavaScript и не се срещат в другите езици за програмиране, така че за програмисти, които са започнали да програмират на други езици и след това са преминали към JavaScript (повечето попадат в тази категория), проблемите могат лесно да останат незабелязани. Ето един пример:
var msg = 'Hello JS';
function show(){
var a=1;
if( true){
var b=2;
console.log('b=', b); // b=2
}
console.log('msg=',msg); // msg=Hello JS (msg has global scope - Ok)
console.log('a=',a); // a=1 ( a has function scope - Ok)
console.log('b=',b); // b=2 ( b has function scope too - ???)
}
show();
Ако се замени var с let това ще ограничи областта на видимост на b до блока на if т.е. последното извеждане на b ще предизвика ReferenceError:b is not defined. По същият начин, при повторна декларация на променлива с var, това не се отчита като грешка, но ако се замени var с let, резултатът ще бъде SyntaxError: Identifier ‘msg’ has already been declared.
var msg = 'Hello JS';
var msg = 'Hi, John';
console.log(msg); //Hi, John
Декларация на константи
В JavaScript константите са най-обикновени променливи с подходящ префикс или суфикс в името (т.е. програмистите са се договорили, че това е константа – var const_path = ‘…’ или var path_const = ‘…’ ) и съответно пред промяната на стойнстта няма никакви пречки. С новата спецификация може да използвате ключовата дума const, която предпазва от промени на стойността както е в другие езици.
const path = '/images/';
console.log('path:',path); // path:/images/
path = '/css/'; // TypeError: Assignment to constant variable
Ако с const се декларира обектна променлива, то действието на const е малко по-различно. Стойностите на ключовете и самите ключове ще могат да се променят, добавят и изтриват, но на самата обектна променлива няма да могат да се присвояват нови стойности както е показано в следващият фрагмент:
const app = {
title: 'My Blog',
logo: '/images/logo.png'
};
console.log(app.title);
console.log(app.logo);
delete app.title; //Ok
delete app.logo; //Ok
console.log(app); // empty object {}
app.scripts = '/js/'; // adds a new key - Ok
app = { mail: 'me@site.com'} //TypeError: Assignment to constant variable.
console.log(app);
Низ съдържащ променливи и изрази
Ако програмирате на PHP, то със сигурност вече знаете как изглежда това! Единственото условие е да оградите низa с апострофи.
let user = 'John Doe';
let msg = `Welcome ${user} !`;
let price=2;
let vat= 1.2;
let crn = 'EUR';
console.log(msg);//Welcome John Doe
console.log( `Price ${ price * vat} ${crn}` ); //Price 2.4 EUR
Функции с подразбиращи се параметри
В JavaScript няма ясна индикация (освен в документацията) за това кои параметри на функциите са задължителни и кои могат да бъдат пропуснати при извикването й и съответно, ако не се подаде стойност каква ще бъде стойността по подразбиране- нещо, което в редица други езици (C++, Python, PHP) съществува отдавна.
function createUser(user,plan){
if( typeof user == 'undefined' || user.trim().length == 0)
throw 'Undefined or empty user name!';
plan = (typeof plan == 'undefined')? 'developer': plan;
console.log('New user ' + user +', ' + plan);
}
createUser('John'); //New user John, developer
createUser('Smith', 'basic'); //New user Smith, basic
createUser(); //Raise Error:Undefined or empty user name
На параметрите, за които няма стойност при извикване на функцията, по подразбиране им се присвоява специалната стойнст undefined, която в тялото на фукцията може да се замени със стойност по подразбиране. С въвеждането на параметри с подразбиращи се стойности в ES6, същият код изглежда доста по-ясен и е достатъчно да се погледне прототипа на функцията за да се видят възможните варианти за нейното извикване.
function createUser(user, plan = 'developer'){
if( typeof user == 'undefined' || user.trim().length == 0)
throw Undefined or empty user name!;
console.log(`Create new user ${user}, plan ${plan}`);
}
createUser('John');
createUser('Smith', 'basic');
createUser(); //Raise Error:Undefined or empty user name
Функции генератори
Функциите генератори са една идея заимствана от Python. Идеята на тези функции е да връщат при всяко извикване следваща стойност изчислена във функцията или взета от масив, низ и др. При декларирането им трябва да се постави след function, а връщането на самата стойност става с yield.
function* getNextValue(){
let i = 1;
while(true){
yield i++;
}
}
var generator = getNextValue();
console.log(generator.next()); // { value: 1, done:false}
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3
generator.return(); //stop the generation of next values
console.log(generator.next()); // {value: undefined, done:true}
Действието на yield е доста по-различно от оператора return, с който изпълнението на функцията приключва и съответно стойностите на i не биха се запазвали. Освен това, в примера е използван безкраен цикъл, но благодарение на yield това не е проблем за изпылнението на кода.
Ламбда изрази (arrow functions)
С ламбда изразите (името съм заимствал от езика Java) можете да превърнете декларацията на кратки функции в компактни и лесни за четене изрази. Например, ако декларираме функция, която премахва интервалите от краищата и разбива текста по определен разделител като връша стойностите в масив, в най-простия си вид това може да изглежда така:
function split(text,delim){
return text.trim().split(delim);
}
console.log( split('John|Mary|Peter|Sam','|')); //['John','Mary','Peter','Sam']
В ES6 съшата функция може да се замести с по-опростен и компактен синтаксис:
let split1 = (text, delim) => {
return text.trim().split(delim);
}
console.log(split1('John|Mary|Peter|Sam','|'));//['John','Mary','Peter','Sam']
и дори с още по-опростен, ако в тялото има само return без други изрази:
let split2 = (text,delim) => text.trim().split(delim);
console.log( split2('John|Mary|Peter|Sam','|')); //['John','Mary','Peter','Sam']
Оператор … за масиви (spread operator)
При определени действия с масиви, операторът … може да ви помогне да избегнете цикли и други неудобни начини за достъп до елементите. Например, преди ES6:
var data = [1,2,3];
function suma(a, b, c){
return a + b + c;
}
console.log( suma(data[0], data[1], data[2]) );
Мисля, че този фрагмент дори няма нужда от коментар :). ES6 превръща това в нещо далеч по-елегантно:
let data = [1,2,3];
function suma(a, b, c){
return a + b + c;
}
console.log( suma(...data ) );
Доста елегатно изглежда и копирането на данните от един масив в друг масив:
let data = [1,2,3];
let values = [ 4, 5, ...data, 7, 8];
console.log(values); //[4,5,1,2,3,7,8]
Ако искате да видите в детайли кой от браузерите в каква степен поддържа новия стандарт, можете да направите това тук.