Прежде чем начать, хочу уточнить 3 момента, которые я не стараюсь доказать этой статьёй:
1. Я не говорю, что эти особенности забываются всеми или что они такие по сути. Я их нахожу трудными лично для меня (например, забываются детали, если их не освежать в памяти). Они могут быть лёгкими для вас. Тем не менее, думаю, что этот сборник может быть полезен не только мне.
2. Я не говорю, что нужно использовать эти части языка, а лишь утверждаю, что если вы знаете их, то сможете легко читать код других разработчиков. Большинство их могут быть полезны, но не всегда наличие их в коде — лучшее решение.
3. Я не затрагиваю особенностей ES5 — ни Strict, ни вообще, ни ES6 в целом. Я расскажу о них позже. Я признаю, что некоторые из обсуждаемых особенностей изменяются или развиваются в последующих версиях ECMAScript.
C учётом сказанного, начнём.
1. −0 = +0 = 0 (или строгий нуль равен положительному и отрицательному нулям)
В JavaScript есть значение числа -0 и +0, показывающее, с какой стороны вы подошли к нулю. Но оно преобразуется к строгому нулю при сравнении.
jsfiddle.net/codylindley/6phD9/light/
console.log(-0); //logs 0 console.log(+0); //logs 0 console.log(-0 === +0); //logs true console.log(0 === -0); //logs true console.log(0 === +0); //logs true
2. Можно вызвать конструктор без ключевого слова new
Забыли или надоело писать new — нет проблемы, конструктор вызывается и так (но не так). Надоело писать скобки после конструктора — то же самое.
jsfiddle.net/codylindley/nHCvx/light/
var Human = function(){ this.type = 'human'; console.log('I was called'); }; new Human; //вызов без скобок выполняет конструктор и выводит "I was called" console.log((new Human).type); //выводит human
3. instanceof не работает с примитивами
Оператор instanceof возвращает false для строк, чисел и логических переменных. Если же они расположены в объектах (т.е. в обёртках примитивов), то нормально работает. Не забывайте, что null и undefined не имеют объектной обёртки.
jsfiddle.net/codylindley/bpJjZ/light/
//instanceof не работает на примитивах console.log("" instanceof String); //выводит false console.log(3 instanceof Number); //выводит false console.log(false instanceof Boolean); //выводит false //instanceof работает на сложных значениях (объектах) console.log(new String() instanceof String); //выводит true console.log(new Number() instanceof Number); //выводит true console.log(new Boolean() instanceof Boolean); //выводит true console.log([] instanceof Array); //выводит true console.log({} instanceof Object); //выводит true console.log(/foo/ instanceof RegExp); //выводит true //к сведению, console.log([] instanceof Object); //выводит true
4. Оператор typeof — неуниверсальный и с ошибками
Применимость typeof ограничивается примитивами, но и там имеет ошибку: (typeof null === «object») == true, из-за чего самописно-костыльные способы проверок оказываются наилучшими./
jsfiddle.net/codylindley/U64aZ/light/
//удобно для значений примитивов string, number, и boolean console.log(typeof ""); //выводит "string" console.log(typeof 4); //выводит number console.log(typeof true); //выводит boolean console.log(typeof undefined); //выводит undefined
//но ошибочно, когда переходим к null
console.log(typeof null); //ЧТО?? Неправильно! выводит Object
5. Булевый объект от ложных значений всегда true
console.log(!!(new Boolean(false)) ) //true
new Boolean(new Boolean(false)) — не false, потому что возвращает объект-обёртку. А объект (следите за руками) всегда преобразуется к true. Поэтому названный софизм относится вообще к любому значению конструктора. А настоящий false создают лишь примитивы (NaN, false, 0, null, undefined, и ») и значения выражений.
6. Аргументы или параметры функции?
Аргументы используются в момент вызова функции. Мы передаём функции аргументы. Параметры устанавливаются в момент определения функции. Таким образом, говорят, что параметры используются для определения функции. Эти слова взаимозаменяемы, но знание их разницы может пригодиться.
jsfiddle.net/codylindley/8Zkdd/light/
var myFunction = function(x,y,z){ //x,y,z - параметры return x+y+z }; myFunction(1,2,3); //1,2,3 - аргументы
7. Изменение значения параметра не изменяет значение аргумента
Например, если вы передадите массив в функцию, то изменение значения параметра не изменит исходного значения параметра.
jsfiddle.net/codylindley/c2xb4/light/
var myFunction = function(parameter){ parameter = undefined; //изменяем значение параметра на undefiend console.log(parameter); }; var myArray = [1,2,3]; myFunction(myArray); //вызываем myFunction, передаём массив //myArray - не undefined , несмотря на то, что он как параметр изменён в функции console.log(myArray); //logs [1,2,3]
8. Вызов Boolean() как функции преобразует любое значение в boolean
Вызов конструктора как функции (без new) с аргументом преобразует его в логическое.
jsfiddle.net/codylindley/4wQLd/light/
//всё, что ниже, возвращает false console.log(Boolean(undefined)); console.log(Boolean(null)); console.log(Boolean(0)); console.log(Boolean('')); console.log(Boolean(NaN)); //всё, что ниже, возвращает true console.log(Boolean(1)); console.log(Boolean('false')); console.log(Boolean([])); console.log(Boolean({})); console.log(Boolean(function(){})); console.log(Boolean(/foo/));
Конечно, двойная инверсия !!() даст тот же эффект. Но это недостаточно выразительно, чтобы мне нравилось.
jsfiddle.net/codylindley/jNPvH/light/
//всё, что ниже, возвращает false console.log(!!undefined); console.log(!!null); console.log(!!0); console.log(!!''); console.log(!!NaN); //всё, что ниже, возвращает true console.log(!!1); console.log(!!'false'); console.log(!![]); console.log(!!{}); console.log(!!function(){}); console.log(!!/foo/);
9. Вызов конструктора примитивных объектов без new возвращает примитивы
jsfiddle.net/codylindley/ymGmG/light/
//выводит true console.log(String('foo') === 'foo'); console.log(Number(5) === 5); console.log(Boolean('true') === true); //выводит false, потому что создаётся оболочка объекта console.log(new String('foo') === 'foo'); console.log(new Number(5) === 5); console.log(new Boolean('true') === true);
10. Object() создаёт объектные оболочки примитивов
В отличие от других конструкторов, Object() оборачивает примитивы в оболочки.
jsfiddle.net/codylindley/tGChw/light/
//примитив number в оболочке объекта console.log(Object(1) instanceof Number); //logs true //примитив string в оболочке объекта console.log(Object('foo') instanceof String); //примитив boolean в оболочке объекта console.log(Object(true) instanceof Boolean);
11. Доступ к свойствам примитивов таит ошибку
Всё отлично пишется в примитивы, кто бы что там ни говорил. Проблем нет и при чтении. Если не считать, что читается всегда undefined. Причина в том, что объектная оболочка для примитива не создаётся.
jsfiddle.net/codylindley/E7GGK/light/
//создаём примитивы var N = 5; var S = 'foo'; var B = true; //добавим к примитивам свойства, которые исчезнут, если у примитивов нет обёрток объектов N.test = 'test'; S.test = 'test'; B.test = 'test'; //проверим, что свойств не осталось console.log(N.test); //выводит undefined console.log(S.test); //выводит undefined console.log(B.test); //выводит undefined
12. delete не удаляет унаследованные свойства
jsfiddle.net/codylindley/xYsuS/light/
var Person = function(){}; //создаёт конструктор Person Person.prototype.type = 'person'; //наследуемое свойство var cody = new Person(); //потомок Person delete cody.type //удаляем (?) type console.log(cody.type) //выводит person, потому что сын за отца не отвечает
13. Объектные оболочки строк массивоподобны
Из-за того, что оболочка строкового объекта создаёт массивоподобный объект, (т.е. console.log(new String(‘foo’)); //выводит foo {0=«f», 1=«o», 2=«o»} ), можно использовать индексирование символов (кроме IE7-).
jsfiddle.net/codylindley/7p2ed/light/
//примитив строки var foo = 'foo'; //доступ к символам как к массиву console.log(foo[0]) //выводит "f", потому что создаётся оболочка объекта {0="f", 1="o", 2="o"} //есть доступ к свойствам через угловые скобки console.log(foo['length']); //выводит 3
14. Доступ к свойствам из примитивов чисел
Первая точка после примитива числа распознаётся как десятичная точка и конфликтует с точкой в смысле доступа к свойству. Но вторая…
jsfiddle.net/codylindley/Pn6YT/light/
//скобочная нотация console.log(2['toString']()); //logs 2 //точечная нотация доступа к свойствам после десятичной точки. console.log(2..toString()); //logs 2 //скобки для точечной нотации console.log((2).toString()); //logs 2
15. Array.length можно переписывать, что имеет побочные эффекты
Явным присваиванием свойства length можно добавить ряд undefined-значений в конец массива или укоротить массив.
jsfiddle.net/codylindley/9Pp9h/light/
var myArray1 = []; myArray1.length = 3; console.log(myArray1); //выводит [undefined, undefined, undefined] //удалить часть значений myArray2 = [1,2,3,4,5,6,7,8,9] myArray2.length = 1; console.log(myArray2); //выводит [1]
16. Логический оператор "||" работает до первого истинного значения
Если значение левого аргумента в этом операторе приведётся к true, правое значение вычисляться не будет, что образно именуется термином «short-circuiting» (закорачивание, короткое замыкание, или для данного случая — «идти коротким путём»). Фактически, обнаружение true в первом значении приводит к незатрагиванию функций и выражений правой части, неизменению значений в их скрытых сеттерах.
jsfiddle.net/codylindley/NUKKZ/light/
//возвращает первое значение, преобразуемое к true, затем выражения не вычисляются var foo = false || 0 || '' || 4 || 'foo' || true; console.log(foo); //выводит 4, потому что число приводится // к первому истинному логическому значению в цепочке
17. Логический оператор "&&" работает до первого ложного значения
Аналогично, но с обратным логическим значением, выполняется до первого фола включительно.
jsfiddle.net/codylindley/DEbk5/light/
//возвращает первое значение, преобразуемое к false, затем выражения не вычисляются var foo = true && 'foo' && '' && 4 && 'foo' && true; console.log(foo); //выводит '', потому что строка приводится к false
18. Когда использовать null, а когда — undefined?
Проще говоря, null — это значение (примитив) для описания отсутствия значения, а undefined — это настоящее отсутствие какого-либо примитива, объекта, свойства: пустая ссылка. В обычной практике разработчикам рекомендуется использовать null для индикации явно проставленного отсутствия значений, а undefined — оставлять для Javascript для указания отсутствия того, чего «никогда не было». При использовании null в программе вы отличите сообщения скрипта от следов сознательных установок null.
19. undefined по умолчанию
undefined описывает отсутствие значения. Следующие примеры не создают значений (возвращают undefined).
jsfiddle.net/codylindley/3buPG/light/
jsfiddle.net/codylindley/3buPG/light/
//переменные без присвоенных значений - не имеют значений var foo; console.log(foo); //undefined //попытка доступа к отсутствующему свойству возвращает undefined console.log(this.foo); //undefined //передача отсутствующих аргументов функции, ожидающей их, приводит к undefined-параметрам var myFunction = function f(x){return x} console.log(myFunction()); //undefined //функция возвратит undefined, если не выполнила явный return вообще var myFunc = function f(){}; console.log(myFunc()); //undefined
20. Выражение может работать там, где не сможет оператор
Выражения возвращают значения, в то время как операторы выполняют действия, что ярко иллюстрируется на примере различий между if и тернарным логическим оператором для условного выражения. «if» не может работать при задании параметров функций, условное выражение — может.
jsfiddle.net/codylindley/SSh68/light/
var verify = true; //оператор if работает с любыми операторами if(verify){console.log('verify is true');} //Выражение может работать там, где не могут быть применены операторы //запись в переменную (странный пример --прим.пер.) var check = verify ? console.log('verify is true') : console.log('verify is false'); //передача значений в функцию console.log(verify ? 'verify is true' : ' verify is false');
21. Расположение операторов ++ и —
Если операторы префиксные (перед переменной), то сначала изменяется значение, затем оно возвращается в выражение. Если постфиксные — в выражение возвращается начальное значение, но перед возвратом переменная изменяется.
jsfiddle.net/codylindley/QzG9w/light/
http://jsfiddle.net/codylindley/QzG9w/light/ var boo = 1; var foo = 1; console.log(boo++); //даёт 1, но следующий console.log(boo) дал бы 2 console.log(++foo); //даёт 2, возвращает новое значение foo
ссылка на оригинал статьи http://habrahabr.ru/post/202686/
Добавить комментарий