20 и 1 примочка Javascript, которые я никак не могу запомнить

от автора

Статья описывает особенности Javascript ES3, которые имеют свойство забываться. Одни из них — странности языка, а другие просто свойства, которые, по-моему, труднозапоминаемы. Я постарался собрать здесь не те из них, по которым можно дать просто ссылку на описание языка (как по различиям между apply и call), а о которых мало сказано в руководствах.

Прежде чем начать, хочу уточнить 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *