Скрытые возможности JavaScript?

Какие «скрытые возможности» JavaScript, по вашему мнению, должен знать каждый программист?

Убедившись в превосходном качестве ответов на следующие вопросы, я подумал, что пришло время спросить о JavaScript.

Несмотря на то, что JavaScript, возможно, является сейчас самым важным языком на стороне клиента (просто спросите Google), удивительно, насколько мало большинство веб-разработчиков понимают, насколько он действительно мощный.

Разве вы не имели в виду: «Увидев репутацию и взгляды на этот другой вопрос, я подумал, что задам почти тот же вопрос, чтобы повысить свой собственный»? ;-)

Bobby Jack 14.09.2008 22:22

Конечно, пессимист. :) Я бы подумал, что это вопрос сообщества. Кроме того, после того, как вы наберете определенное количество очков, все будет уменьшаться.

Allain Lalonde 14.09.2008 22:37

Достаточно справедливо - это не похоже, что вам «нужна» репутация! Думаю, у меня просто большая проблема с C# - мне не совсем подходит тип вопроса, для которого предназначен этот сайт.

Bobby Jack 14.09.2008 22:41

Да, может быть, и нет, но я нашел, что знания в ответах отличные. Я думаю, вам было бы сложно представить среднему программисту на C# все это в одном месте, если бы не SO. Понадобились годы, чтобы составить такой же список с трудом завоеванным.

Allain Lalonde 14.09.2008 22:54

Мне нравится эта серия вопросов; Я думаю, что система «digg» для ответов лучше, чем «+1», которую вы видите на форумах. Намного легче понять, что сообщество считает самым важным. Я уверен, что это хорошая приманка для ссылок и для Google!

Martin Clarke 14.09.2008 23:08

Я профессионально пишу JavaScript уже 10 лет и кое-чему научился из этой ветки. Спасибо, Алан!

Andrew Hedges 20.09.2008 11:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
312
6
150 256
99

Ответы 99

Функции в JavaScript являются первоклассными гражданами:

var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };

var sum = function(x,y,z) {
  return x+y+z;
};

alert( passFunAndApply(sum,3,4,5) ); // 12

Для написания элегантного javascript можно использовать методы функционального программирования..

В частности, функции могут передаваться как параметры, например Array.filter () принимает обратный вызов:

[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]

Вы также можете объявить «частную» функцию, которая существует только в рамках определенной функции:

function PrintName() {
    var privateFunction = function() { return "Steve"; };
    return privateFunction();
}

Есть три способа создавать функции в javascript: function sum (x, y, z) {return (x + y + z); } и var sum = new Function ("x", "y", "z", "return (x + y + z);"); другие способы.

Marius 14.09.2008 23:35

Концепция функций как данных в моей книге определенно заслуживает особого внимания.

Jason Bunting 15.09.2008 01:52

Я только что обновил образец, чтобы показать, как использовать «частную» функцию, которая существует только в рамках определенной функции.

Chris Pietschmann 10.10.2008 18:25

new Function() такой же злой, как eval. Не использовать.

Nicolás 04.01.2010 08:56

Я не думаю, что функция-как-данные === функция-как-первоклассный гражданин ... Да, вы можете делать некоторые манипуляции со строками + магию eval / new Function (). Но это сильно отличается от того, как это есть в Scala / Lisp.

chakrit 23.03.2010 16:07

не уверен, что это скрытая функция ... больше похоже на основную функцию.

Claudiu 24.06.2010 18:33

@ Marius, Nicolas Очень мало случаев, в которых вы хотели бы использовать новую функцию. Хотя это лучше, чем eval (вы можете повторно использовать функцию вместо анализа кода каждый раз, и код не может получить доступ к локальным переменным), это все же не рекомендуется (например, это усложняет отладку)

Asaf 13.01.2012 14:04

Частные методы

У объекта могут быть частные методы.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    // A private method only visible from within this constructor
    function calcFullName() {
       return firstName + " " + lastName;    
    }

    // A public method available to everyone
    this.sayHello = function () {
        alert(calcFullName());
    }
}

//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();

// This fails since the method is not visible from this scope
alert(person1.calcFullName());

Педантизм: в JavaScript нет классов. Возможны функции, которые доступны членам объекта, но в остальном недоступны.

Shog9 14.09.2008 07:29

На самом деле это не частная функция - это скорее функциональная переменная в локальной области видимости.

Keith 15.09.2008 20:28

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

Allain Lalonde 18.09.2008 02:44

Тот, который существует в определении класса, а не в экземпляре. В приведенном выше примере переменную функции calcFullName можно переназначить на что-то другое, и логика каждый раз прорабатывается заново.

Keith 19.09.2008 16:49

Я согласен с Кейтом ... Зная, что технические характеристики квалифицируются как скрытая функция (или больше похожа на «малоизвестную функцию») JavaScript, ее использование для «частных методов» - это скорее взлом, чем что-либо еще.

paercebal 19.09.2008 23:14

Я не думаю, что вы можете назвать это методом, поскольку в каждом экземпляре объекта создается новая функция. Метод находится в прототипе и может быть изменен один раз, чтобы изменить все объекты. Добавьте к этому тот факт, что с этой техникой ваши объекты занимают гораздо больше памяти.

Vincent Robert 20.09.2008 00:57

@Vince, это метод экземпляра. @Kieth, детали реализации различны для каждого языка. Следует учитывать, обеспечивает ли он необходимый уровень сокрытия информации, чтобы его можно было назвать конфиденциальным.

Zach 21.09.2008 00:38

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

Shog9 21.09.2008 02:23

Зачем, черт возьми, вам нужны частные методы? В реальных объектно-ориентированных языках их нет (см. Smalltalk).

user9903 22.09.2008 19:45

Просто интересно, есть ли у person1 юридический блог? ;-)

travis 23.09.2008 20:11

Нет, просто звучит как бла-бла-бла. Я все время использую это имя, когда преподаю.

Allain Lalonde 04.10.2008 17:47

Если вы настаиваете на том, чтобы называть его частными методами, ожидайте путаницы, когда настоящие и правильные классы будут реализованы в следующем стандарте. Хотя, думаю, мы привыкли объяснять подобные вещи в JAVA-Script. :П

Kit Sunde 14.12.2008 23:53

+1 за задержанную ссылку на разработку

Domenic 28.02.2010 05:19

@travis - Я не смотрел шоу, но я задал тот же вопрос, когда наткнулся на имя этого персонажа. И я проверил; там является и блог!

Kenny Evitt 21.06.2010 17:48

любой язык с замыканиями и первоклассными функциями может это сделать. Я думаю, что не хватает смысла называть это «частным методом». более точным было бы «вы можете имитировать частные методы, объявив функцию внутри конструктора». где абстракция не работает: если вы объявите функцию в прототипе Person, она не сможет получить доступ к «закрытому методу» calcFullName. Называя его «частным методом», люди просто сбивают с толку и создают впечатление, будто в JavaScript есть ООП на основе классов.

Claudiu 24.06.2010 18:38

-1, это не частный метод, люди по-прежнему могут вызывать calcFullName, если хотят.

Russel Yang 06.04.2011 20:09

with.

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

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

var user = 
{
   fname: 'Rocket', 
   mname: 'Aloysus',
   lname: 'Squirrel', 
   city: 'Fresno', 
   state: 'California'
};

// ...

with (user)
{
   mname = 'J';
   city = 'Frostbite Falls';
   state = 'Minnesota';
}

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

var user = 
{
   fname: "John",
// mname definition skipped - no middle name
   lname: "Doe"
};

with (user)
{
   mname = "Q"; // creates / modifies global variable "mname"
}

Поэтому, вероятно, будет хорошей идеей избегать использования оператора with для такого назначения.

См. Также: Есть ли законное использование оператора «with» в JavaScript?

Следует избегать расхожего мнения со статусом. Если пользовательский объект не имеет одного из упомянутых вами свойств, переменная за пределами псевдообласти блока with будет изменена. В этом кроется ошибка. Больше информации на yuiblog.com/blog/2006/04/11/with-statement-considered-harmfu‌ l

Alan Storm 14.09.2008 11:54

Если вы неправильно написали имя переменной, вы ввели ошибку. Период. Лично я никогда не использую with для подобных вещей, но это своего рода «скрытая функция», так что ...

Shog9 14.09.2008 20:44

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

Alan Storm 14.09.2008 20:56

Хорошая точка зрения. Я исправлю свой ответ, чтобы отметить это.

Shog9 14.09.2008 21:11

Аминь - если бы я увидел выражение «with» в любом найденном мной JS, я бы исключил его и задал вопрос разработчику, написавшему его, чтобы убедиться, что он знает, почему его использовать нехорошо ... «скрытая функция?» Больше похоже на «отвратительную черту».

Jason Bunting 15.09.2008 01:55

рассмотрим более сложную цепочку abcd с (abc) {d.foo = bar;} - это мощный инструмент, который по своей сути не подвержен ошибкам. Ключ в том, чтобы сократить корень на один уровень выше. И неправильное написание имени переменной? Вы вводите ошибку если вы сделаете это где бы, вы сделаете это, независимо от «с».

annakata 20.01.2009 14:33

если нужно поменять половину? функция augment (a, b) {for (i in b) {a [i] = b [i]} return a}

Breton 29.01.2009 04:10

Дуглас Крокфорд недавно сказал, что with - одна из худших частей JavaScript в .NET Rocks! подкаст.

core 14.03.2009 07:09

@Chris: Крокфорд утверждал это в течение некоторого времени, и у него есть веские причины так говорить. Однако он предоставляет то, что не предусмотрено никакими другими языковыми конструкциями: способ прямого увеличения области разрешения имен (функции обеспечивают это косвенно). Используйте с осторожностью.

Shog9 14.03.2009 22:50

В большинстве случаев вы можете использовать циклы и что-то вроде jQuery.extend, чтобы получить тот же эффект.

chakrit 23.03.2010 16:16

Я согласен, что с () - зло. Еще одна вещь, которая может вас убедить, заключается в том, что вы не можете использовать с ним jslint или минификатор (например, компрессор YUI или Google Closure Compiler). Любая область, в которой появляется with (), не будет оптимизирована и не может быть проверена на предмет области видимости переменной (потому что вы не знаете область действия переменной до времени выполнения).

thomasrutter 10.04.2010 07:27

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

Claudiu 24.06.2010 18:41

Это скрыто по какой-то причине. Никто не должен знать об этом, и никто никогда не должен никому рассказывать об этом, если они это сделали.

Justin Johnson 19.12.2010 12:10

кроме того, блок кода, написанный с помощью "with", всегда медленнее, чем старый добрый способ

gion_13 19.01.2011 22:54

@gion: это в значительной степени деталь реализации - например, это не обязательно верно в (более старых версиях) IE. Для оптимизации with прилагается мало усилий (по очевидным причинам).

Shog9 20.01.2011 00:02

@ Shog9: Не деталь реализации: способ определения with делает его неоптимизируемым. Эта презентация содержит информацию о том, почему with работает медленно. В более старых версиях IE все операторы были медленными, поэтому with не был медленнее других.

dolmen 29.03.2011 11:49

Вы можете получить доступ к свойствам объекта с помощью [] вместо .

Это позволяет вам искать свойство, соответствующее переменной.

obj = {a:"test"};
var propname = "a";
var b = obj[propname];  // "test"

Вы также можете использовать это для получения / установки свойств объекта, имя которого не является допустимым идентификатором.

obj["class"] = "test";  // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.

Некоторые люди этого не знают и в конечном итоге используют eval () вот так, то есть действительно плохая идея:

var propname = "a";
var a = eval("obj." + propname);

Это сложнее читать, труднее найти ошибки (нельзя использовать jslint), медленнее выполняется и может привести к эксплойтам XSS.

eval - зло, хотя и редко необходимо

Doug Domeny 25.06.2009 18:27

Я никогда не использую eval и помню, когда обнаружил это. Это меня очень обрадовало.

user55776 13.07.2009 01:55

Таким образом, к свойствам объекта можно получить доступ как через точечную, так и через подстрочную нотацию.

Russ Cam 05.04.2010 23:53

Интересно отметить, что ссылки на точки на самом деле являются синтаксическим сахаром для скобок. foo.bar, в любом случае, согласно спецификации, ведет себя так же, как foo["bar"]. также обратите внимание, что все является строковым свойством. даже когда вы выполняете доступ к массиву, array[4], 4 преобразуется в строку (опять же, по крайней мере, в соответствии со спецификацией ECMAScript v3)

Claudiu 24.06.2010 18:40

Думаю, это должен знать каждый JS-программист.

Cem Kalyoncu 10.06.2011 01:03

«Методы расширения в JavaScript» через свойство прототипа.

Array.prototype.contains = function(value) {  
    for (var i = 0; i < this.length; i++) {  
        if (this[i] == value) return true;  
    }  
    return false;  
}

Это добавит метод contains ко всем объектам Array. Вы можете вызвать этот метод, используя этот синтаксис

var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");

Обычно это считается плохой идеей, потому что другой код (не ваш) может делать предположения об объекте Array.

Chris Noe 22.09.2008 23:45

Также обычно считается плохой идеей делать предположения об объекте Array. :(

eyelidlessness 08.10.2008 03:47

Мммм .. javascript 1.6 дополнительные массивы? индекс? звонить в колокола?

Breton 29.01.2009 04:07

@Breton: Это не что-то конкретное для класса Array, это просто пример. Я использую это для расширения функции new Date (). ToString (); метод, позволяющий использовать строку маски. Объект Любой может быть расширен, и все его экземпляры получат новый метод.

Esteban Küber 30.06.2009 20:42

Плохая идея: perfectionkills.com/whats-wrong-with-exnding-the-dom

Mathias Bynens 30.12.2010 23:52

@Mathias: дело не в DOM.

dolmen 29.03.2011 01:59

Назначение значений по умолчанию для переменных

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

var a = b || c;

Переменная a получит значение c, только если b будет фальшивка (если это null, false, undefined, 0, empty string или NaN), в противном случае a получит значение b.

Это часто бывает полезно в функциях, когда вы хотите присвоить аргументу значение по умолчанию, если оно не указано:

function example(arg1) {
  arg1 || (arg1 = 'default value');
}

Пример отката IE в обработчиках событий:

function onClick(e) {
    e || (e = window.event);
}

Следующие языковые функции были с нами в течение долгого времени, все реализации JavaScript поддерживают их, но они не были частью спецификации до ECMAScript 5-е издание:

Заявление debugger

Описано на: § 12.15 Оператор отладчика

Этот оператор позволяет вам вставить точки останова программно в ваш код, просто:

// ...
debugger;
// ...

Если отладчик присутствует или активен, он немедленно остановится прямо в этой строке.

В противном случае, если отладчик отсутствует или активен, этот оператор не имеет наблюдаемого эффекта.

Многострочные строковые литералы

Описано на: § 7.8.4 Строковые литералы

var str = "This is a \
really, really \
long line!";

Вы должны быть осторожны, потому что символ рядом с \должен является ограничителем строки, например, если у вас есть пробел после \, код будет Смотреть точно так же, но вызовет SyntaxError.

Нет, если он нулевой, если он считается ложным. а = 0 || 42; даст вам 42. Это сравнимо с Python или, а не с C# ?? оператор. Если вам нужно поведение C#, сделайте a = (b === null)? c: b;

Armin Ronacher 22.09.2008 02:18

Он также работает в Visual Studio, если вы разрабатываете на ASP.NET :)

chakrit 23.03.2010 16:13

Я бы хотел, чтобы это было правильно || только для неопределенных. Меня это сегодня укусило за 0, так как я хотел создать эмуляцию перегруженного метода, чтобы последний аргумент был необязательным, а вместо него использовалось значение по умолчанию.

egaga 15.04.2010 07:47

+1 этот трюк используется сниппетом Google Analytics по умолчанию. `var _gaq = _gaq || []; `; он не позволяет чрезмерно усердным пользователям перезаписывать свою работу.

Yahel 11.11.2010 03:29

Я не знал о технике многострочного строкового литерала. Это здорово, спасибо.

Charlie Flowers 26.11.2010 05:33

Удивительно, как много людей не понимают, что это тоже объектно-ориентированный подход.

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

Wedge 14.09.2008 11:42

Странный. Как еще они интерпретировали бы document.writeln или document.getElementsbyTagName?

Allain Lalonde 14.09.2008 22:39

Потому что я считаю, что большинство разработчиков используют Javascript в браузерах и не заботятся о том, насколько это объектно-ориентированный подход. они используют базовые функции, чтобы что-то делать в браузерах, если они активно используют серверные коды.

Tarik 19.12.2009 06:58

JavaScript не имеет области действия блока (но у него есть закрытие, так что назовем его даже?).

var x = 1;
{
   var x = 2;
}
alert(x); // outputs 2

Это хорошо. Это действительно важное отличие от большинства C-подобных языков.

Martin Clarke 14.09.2008 23:02

Вы всегда можете сделать "var tmp = function () {/ * block scope * /} ();". Синтаксис уродливый, но работает.

Joeri Sebrechts 30.09.2008 15:03

Или вы можете использовать let, если это только Firefox: stackoverflow.com/questions/61088/…

Eugene Yokota 01.10.2008 04:42

или просто: (function () {var x = 2;}) (); предупреждение (тип x); //неопределенный

Pim Jager 28.01.2009 02:17

@Pim: JSLint говорит: «Переместите вызов в скобки, содержащие функцию». Наряду с "Ожидается ровно один пробел между 'function' и '('.".

Hello71 10.01.2011 06:11

@ Hello71, что именно хочет JSLint?

Pim Jager 13.01.2011 19:28

@Pim: (function () { var x = 2; }());

Hello71 14.01.2011 00:41

Фактически, это так: var v = "переменная в области функций"; попробуйте {бросить "брошенную переменную"; } catch (v) {v = "локальная переменная"; console.info (v); } console.info (v);

yorick 19.01.2011 20:49

Как насчет закрытие в JavaScript (аналогично анонимным методам в C# v2.0 +). Вы можете создать функцию, которая создает функцию или «выражение».

Пример закрытие:

//Takes a function that filters numbers and calls the function on 
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
  var filteredNumbers = [];

  for (var index = 0; index < numbers.length; index++)
  {
    if (filterFunction(numbers[index]) == true)
    {
      filteredNumbers.push(numbers[index]);
    }
  }
  return filteredNumbers;
}

//Creates a function (closure) that will remember the value "lowerBound" 
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
  return function (numberToCheck) {
    return (numberToCheck > lowerBound) ? true : false;
  };
}

var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];

var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);

numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);

numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);

Я не уверен, но могу ли вернуть (numberToCheck> lowerBound)? истина: ложь; просто стать return (numberToCheck> lowerBound); просто пытаюсь расширить свое понимание ...

davidsleeps 10.06.2009 08:15

Я бы сказал, что анонимные функции в C# эквивалентны закрытию, а не наоборот :)

vava 23.08.2009 13:23

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

slebetman 11.01.2010 16:52

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

Tyler 29.01.2010 21:01

Я не думаю, что это лучший или самый простой для понимания пример того, что такое закрытие. Просто говорю. Смысл закрытия в том, что даже когда кажется, что группа переменных «выходит за пределы области видимости», они все еще могут оставаться доступными для функции, которая изначально была определена в этой области. В приведенном выше примере это означает, что переменная lowerBound все еще доступна этой внутренней анонимной функции, даже когда внешняя функция buildGreaterThanFunction завершается.

thomasrutter 18.03.2010 19:08

@thomasrutter +1 - я использую замыкания для «захвата» области видимости для последующего использования (скажем, в setTimeout или обработчике событий), например function testFunc(){ var str='this will be out of scope when timeout event occurs'; setTimeout(function(){ return function(input){ alert(input); }(str); }, 5000); return; }

acatalept 09.09.2011 22:31

Вы также можете расширять (наследовать) классы и переопределять свойства / методы, используя упомянутую цепочку прототипов ложка16.

В следующем примере мы создаем класс Pet и определяем некоторые свойства. Мы также переопределяем метод .toString (), унаследованный от Object.

После этого мы создаем класс Dog, метод расширяет Pet и переопределяет .toString () которого снова меняет его поведение (полиморфизм). Кроме того, мы добавляем в дочерний класс некоторые другие свойства.

После этого мы проверяем цепочку наследования, чтобы показать, что Dog все еще имеет тип Dog, тип Pet и тип Object.

// Defines a Pet class constructor 
function Pet(name) 
{
    this.getName = function() { return name; };
    this.setName = function(newName) { name = newName; };
}

// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function() 
{
    return 'This pets name is: ' + this.getName();
};
// end of class Pet

// Define Dog class constructor (Dog : Pet) 
function Dog(name, breed) 
{
    // think Dog : base(name) 
    Pet.call(this, name);
    this.getBreed = function() { return breed; };
}

// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();

// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;

// Now we override Pet.prototype.toString
Dog.prototype.toString = function() 
{
    return 'This dogs name is: ' + this.getName() + 
        ', and its breed is: ' + this.getBreed();
};
// end of class Dog

var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);

// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true

Оба ответа на этот вопрос были кодами, измененными из отличная статья Рэя Джаджадинаты в MSDN.

Функции являются объектами и поэтому могут иметь свойства.

fn = function(x) {
   // ...
}

fn.foo = 1;

fn.next = function(y) {
  //
}

Это очень полезный совет. Например, вы можете установить значения по умолчанию как свойство функции. Например: myfunc.delay = 100; Затем пользователи могут изменить значение по умолчанию, и все вызовы функций будут использовать новое значение по умолчанию. Например: myfunc.delay = 200; myfunc ();

BarelyFitz 01.06.2009 04:23

Полезно ... и опасно!

palswim 13.08.2010 02:41

Выглядит небрежно, зачем использовать это вместо переменной?

instantsetsuna 08.12.2010 13:20

@instantsetsuna: Зачем нужна еще одна переменная отдельный? Как обычно, это сводится к «использовать его, когда это уместно / полезно» ;-)

VolkerK 10.12.2010 12:04

Я мог бы процитировать большую часть прекрасной книги Дугласа Крокфорда. JavaScript: хорошие стороны.

Но я возьму для вас только один, всегда используйте === и !== вместо == и !=.

alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true

== не является транзитивным. Если вы используете ===, он даст false для все эти заявления, как и ожидалось.

Большинство людей считают это одной из худших частей языка, когда впервые видят ее (3 равно !?). Я думаю, что знание об этом важно, потому что это заставляет вас фиксировать в памяти, что JavaScript динамически типизируется.

Allain Lalonde 14.09.2008 23:01

Да, я согласен - Крокфорд говорит о «худшей части» приложения. Жаль, что они не смогли просто заставить "==" вести себя так, как ожидалось.

Martin Clarke 14.09.2008 23:03

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

Jason Bunting 15.09.2008 01:58

Я мог неправильно понять; но есть ли у них что-то особенное, что, по вашему мнению, он не соответствует действительности?

Martin Clarke 15.09.2008 03:33

Я повторяю предупреждение Джейсона. Книга сама по себе очень интересна и дает много хороших советов, но DC слишком убежден, что его образ действий - единственно правильный, а все остальное «несовершенно». Если вам нужны примеры, посмотрите его ответы в JSLint Yahoo Group.

Zilk 29.10.2008 00:21

по всем вышеперечисленным причинам, и особенно из-за его комментария к "этому"

annakata 20.01.2009 14:29

Может ли кто-нибудь объяснить мне, почему 0 == '' верно в javascript? Что именно означает нетранзитивное сравнение на равенство?

Davy8 02.03.2009 20:57

Нетранзитивно: '' == 0 и 0 == '0', но ''! = '0'. Если бы он был транзитивным, «» равнялось бы «0». 0 == '', потому что преобразование типов происходит автоматически, и некоторые архитекторы JS считали, что '' следует преобразовать в 0.

PotatoEngineer 20.03.2009 18:30

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

thomasrutter 01.04.2009 09:15

Ну, == и === не о динамической типизации. == вводит принуждение, а это совсем другое дело. Если вы знаете, что хотите преобразовать в строку / число / и т. д., Вам следует сделать это явно.

Rene Saarsoo 05.06.2009 22:39

Лучше всего использовать == при тестировании на undefined, потому что undefined == null, но undefined! == null. Я редко видел что-либо, где я хотел бы различать undefined и null.

PotatoEngineer 09.06.2009 00:10

@zlik: Полностью согласен. В некотором смысле он гениален, но не бойтесь переписывать свой код. В частности, его код создания PHP JSON ограничен в том, сколько он может собирать.

staticsan 22.06.2009 04:42

Я думаю, что самая страшная часть == - это '\n\t\r ' == 0 => true ...: D

Shrikant Sharat 18.10.2009 13:19

Я вижу, что многие люди до сих пор неправильно понимают JavaScript :)

chakrit 23.03.2010 15:57

Крокфорд не идеален, но он произвел революцию в JS и сделал его удобным языком для всех нас. Он почти всегда подкрепляет свои мнения вескими основаниями. Если я не согласен с ним в 2% случаев, я не думаю, что это имеет большое значение. Когда вы не согласны, легко настроить набор правил JSLint с комментариями.

Neil 05.10.2010 21:17

В Javascript есть статические переменные внутри функций:

function someFunction(){
  var Static = arguments.callee;
  Static.someStaticVariable = (Static.someStaticVariable || 0) + 1;
  alert(Static.someStaticVariable);
}
someFunction() //Alerts 1
someFunction() //Alerts 2
someFunction() //Alerts 3

Он также имеет статические переменные внутри объектов:

function Obj(){
  this.Static = arguments.callee;
}
a = new Obj();
a.Static.name = "a";
b = new Obj();
alert(b.Static.name); //Alerts b

Отлично! Мне пришлось сделать тройной взгляд на это, пока я не понял, что вы определяете свойство самой функции. Мне пришлось запустить alert (someFunction.someStaticVariable); чтобы он утонул.

Allain Lalonde 15.09.2008 03:27

Я думаю, вы искажаете способность функций иметь свойства в целом. То, что вы говорите, технически верно, но как побочный эффект для функций, являющихся объектами первого порядка в языке.

levik 16.09.2008 19:08

Согласен, это немного вводит в заблуждение. "arguments.callee" - это просто ссылка на вызванную функцию. Во втором примере a.Static === b.Static === Obj

Josh 22.09.2008 15:36

В теле функции вы можете просто написать someFunction.someStaticVariable вместо arguments.callee.someStaticVariable. Читает чище.

Srikumar 04.12.2011 14:55

undefined не определен. Итак, вы можете сделать это:

if (obj.field === undefined) /* ... */

«undefined» не является зарезервированным словом, так что это потенциально может потерпеть неудачу, если у вас есть переменная с таким именем.

levik 16.09.2008 19:11

если у вас есть переменная с таким именем, вы уже потерпели неудачу

jsight 01.10.2008 21:01

jsight, я хочу проголосовать за комментарии: P

Andrea Ambu 16.01.2009 19:54

Вы даже можете изменить значение глобального undefined.

Ates Goral 20.04.2010 09:25

Вы можете заменить «undefined» выражением «void ()». Преимущество в том, что void нельзя переопределить.

JacquesB 14.06.2011 11:59

Действительно? Когда я пытаюсь это сделать, я получаю синтаксическую ошибку в FF и Chrome.

JW. 14.06.2011 18:49

@JW void не является функцией. void 0 или void(0) можно безопасно использовать в качестве замены undefined.

Rob W 02.02.2012 15:52

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

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

Вот пример моего старого «одноэлементного» подхода:

var singleton = function(){ 

  if (typeof arguments.callee.__instance__ == 'undefined') { 

    arguments.callee.__instance__ = new function(){

      //this creates a random private variable.
      //this could be a complicated calculation or DOM traversing that takes long
      //or anything that needs to be "cached"
      var rnd = Math.random();

      //just a "public" function showing the private variable value
      this.smth = function(){ alert('it is an object with a rand num=' + rnd); };

   };

  }

  return arguments.callee.__instance__;

};


var a = new singleton;
var b = new singleton;

a.smth(); 
b.smth();

Как видите, в обоих случаях конструктор запускается только один раз.

Например, я использовал этот подход еще в 2004 году, когда мне пришлось создать модальное диалоговое окно с серым фоном, которое покрыл всю страницу (что-то вроде Лайтбокс). Интернет Explorer 5.5 и 6 имеют самый высокий контекст стекирования для элементы <select> или <iframe> из-за их «оконная» природа; поэтому, если страница содержала элементы выбора, единственный способ скрыть их - создать iframe и расположите его «вверху» страницы. Итак, весь сценарий был довольно сложный и немного медленный (использовался фильтр: выражений для установки непрозрачности закрывающего окна iframe). В В скрипте "shim" был только один метод ".show ()", который создавал прокладку только один раз и кешировали в статической переменной :)

Меня просто восхищает то, как JavaScript работает с Date ()!

function isLeapYear(year) {
    return (new Date(year, 1, 29, 0, 0).getMonth() != 2);
}

Это действительно «скрытая особенность».

Обновлено: удалено "?" условие, предложенное в комментариях для политкорректности. Было: ... новая дата (год, 1, 29, 0, 0) .getMonth ()! = 2? правда: ложь ... Подробности смотрите в комментариях.

Это тоже слишком сложно. Я не понимаю, как можно писать cond ? true : false (или наоборот) и не замечать, насколько это идиотично.

Konrad Rudolph 17.09.2008 23:08

Для наглядности строка должна быть return! (New Date (year, 1, 29, 0, 0) .getMonth () == 2); Или, на самом деле, это должно быть return new Date (year, 1, 29, 0, 0) .getMonth ()! = 2;

Jesse Millikan 23.09.2008 01:52

На самом деле это обозначение не так уж идиотично, как может показаться, когда «неопределенные» результаты могут быть включены в дополнительные данные. Я взял этот пример из реально работающей системы, и изменение его формы на «Политически корректную» полностью тормозит систему :)

Thevs 27.09.2008 19:18

@Thevs: Я не понимаю, как изменение формы в этом случае что-нибудь сломает. И старый код, и новый код, похоже, возвращают реальные логические значения (истина / ложь) вместо того, чтобы просто возвращать объекты, которые могут быть или не быть правдивыми.

jsight 01.10.2008 20:53

Ты прав. Виноват. В моем исходном коде было «? 1: 0», а затем возвращаемое значение было добавлено к 28, чтобы определить количество дней в феврале. Изменение его для возврата логического значения vlaue нарушило мой код. В случае «? False: true» оба фрагмента кода эквивалентны.

Thevs 02.10.2008 14:38

Также секретные возвращаемые значения методов "set ...": var d = new Date ((new Date ()). SetHours (0, 0, 0, 0));

palswim 13.08.2010 02:55

Это должно оставаться скрытым. По крайней мере, пример использования, потому что он неэффективен. Используйте его только в тестовом наборе для проверки более быстрая реализация, например !(year % 4 != 0 || (year % 100 == 0 && year % 400 != 0)).

dolmen 29.03.2011 13:33

Все функции на самом деле являются экземплярами встроенного типа Функция, который имеет конструктор, который принимает строку, содержащую определение функции, поэтому вы можете фактически определять функции во время выполнения, например, объединяя строки:

//e.g., createAddFunction("a","b") returns function(a,b) { return a+b; }
function createAddFunction(paramName1, paramName2)
 { return new Function( paramName1, paramName2
                       ,"return "+ paramName1 +" + "+ paramName2 +";");
 }

Кроме того, для пользовательских функций Function.toString () возвращает определение функции в виде буквальной строки.

Однако обычно в этом нет необходимости. В вашем примере вы можете просто сказать: return function (paramName1, paramName2) {return paramName1 + paramName2; }

JW. 15.09.2008 21:43

Это был просто надуманный пример. Это по-прежнему приятная малоизвестная функция. Тем не менее, вы можете создавать макросы, например, раскручивать цикл.

Mark Cidade 15.09.2008 21:55

Вам не нужно определять какие-либо параметры для функции. Вы можете просто использовать объект функции arguments, подобный массиву.

function sum() {
    var retval = 0;
    for (var i = 0, len = arguments.length; i < len; ++i) {
        retval += arguments[i];
    }
    return retval;
}

sum(1, 2, 3) // returns 6

Ого! Действительно?! Честно говоря, я понятия не имел. Этому сайту действительно нужна функция "избранных ответов". Я бы обязательно добавил это.

Joshua Carmody 20.09.2008 00:36

Однако стоит отметить, что, хотя аргументы действуют как массив, это не настоящий массив javascript - это просто объект. Таким образом, вы не можете использовать join (), pop (), push (), slice () и так далее. (Вы можете преобразовать его в настоящий массив, если хотите: "var argArray = Array.prototype.slice.call (arguments);")

Jacob Mattison 27.01.2009 00:37

Также стоит отметить, что доступ к объекту Arguments является относительно дорогостоящим - лучшие примеры - в ночных сборниках Safari, Firefox и Chrome, где простая ссылка на объект arguments делает вызов функции намного медленнее, например. если (ложные) аргументы; повредит перфорацию.

olliej 18.02.2009 06:20

Точно так же у arguments есть свойство callee, которое является самой текущей функцией. Это позволяет делать рекурсию с анонимными функциями, круто!

Vincent Robert 03.04.2009 00:01

По крайней мере, включите в сигнатуру функции аргумент с именем «varargs» или что-то еще, чтобы читатели знали, что ваша функция имеет арность.

a paid nerd 10.05.2009 02:46

Это круто, но есть ли веская причина, по которой вы хотите это сделать? Почему бы просто не передать массив?

Nathan 23.09.2009 00:07

@Nathan «f (x, y, z)» выглядит лучше, чем «f ([x, y, z])».

Mark Cidade 28.09.2009 16:01

@Nathan Этот arguments позволяет вам изменять любые существующие функции по своему усмотрению, даже не зная аргументов. Попробуйте Google для Memoize Javascript, и вы поймете, как это можно использовать.

chakrit 23.03.2010 16:04

@ Винсент Роберт: обратите внимание, что arguments.callee устарел.

ken 30.12.2010 00:50

Следует отметить, что это не уникально для JavaScript и возможно во многих других языках.

Justin Johnson 31.01.2011 19:38

@ken: developer.mozilla.org/en/JavaScript/Reference/… "JavaScript 1.4: устаревшие аргументы, arguments.callee и arguments.length как свойства экземпляров Function; сохранены аргументы как локальная переменная функции и arguments.callee и arguments.length как свойства этой переменной".

tsurahman 28.04.2011 05:25

Все объекты в Javascript реализованы как хэш-таблицы, поэтому к их свойствам можно получить доступ через индексатор и наоборот. Также вы можете перечислить все свойства с помощью оператора для / в:

var x = {a: 0};
x["a"]; //returns 0

x["b"] = 1;
x.b; //returns 1

for (p in x) document.write(p+";"); //writes "a;b;"

Кроме того, имена свойств являются строками, и если в строке есть символ, который не позволяет использовать ее через точечную нотацию, к ней можно получить доступ через индексную нотацию. Например, свойство объекта x ['funky prop'] не может быть доступно как x.funky prop; x ['funky.prop'] недоступен как x.funky.prop;

BarelyFitz 01.06.2009 05:03

Только не забудьте проверить имена свойств с помощью "object.hasOwnProperty (propertyName)" перед их использованием из цикла for-in, иначе вы столкнетесь с некоторыми нежелательными вещами;)

BYK 22.06.2009 01:59

@Beska: Я думаю, что доработка будет такой: for (p in x) if (x.hasOwnProperty (p)) document.write (p + ";"); Это позволяет обойти проблемы, при которых добавление новых свойств к прототипу x приведет к тому, что в также будет перечислять их, что может быть нежелательным поведением.

shuckster 31.07.2009 15:59

Вы можете использовать оператор в, чтобы проверить, существует ли ключ в объекте:

var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true

Если вы находите объектные литералы слишком уродливыми, вы можете объединить их с подсказкой функции без параметров:

function list()
 { var x = {};
   for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
   return x
 }

 5 in list(1,2,3,4,5) //true

Не настолько умно, что проверяет наличие ключа, а не значение. x в списке; работает только потому, что x [1]! = null, а не потому, что там есть значение 1.

Armin Ronacher 22.09.2008 02:16

Я пока не использовал эту технику, поэтому забыл, что раньше я действительно использовал объектные литералы. Спасибо за исправление.

Mark Cidade 22.09.2008 21:03

Также будьте осторожны: оператор in также проверяет цепочку прототипов! Если кто-то поместил свойство с именем «5» в Object.prototype, второй пример вернет true, даже если вы вызвали «5 в списке (1, 2, 3, 4)» ... Лучше использовать hasOwnProperty method: list (1, 2, 3, 4) .hasOwnProperty (5) вернет false, даже если Object.prototype имеет свойство '5'.

Martijn 22.06.2009 12:24

Для самого общего решения, которое может проверить, есть ли у объекта собственное свойство, даже если оно названо «hasOwnProperty», вы должны полностью перейти к: Object.prototype.hasOwnProperty.call (object, name) ;

Kris Kowal 13.09.2009 02:52

Лучшее использование для этого (вместе с hasOwnProperty) - проверка с тремя состояниями ... queue[item] = false; будет делать (item in queue) === true, но все еще сохраняет (queue[item] === false) ... пригодится в некоторых ситуациях (и выглядело странным уборщиком, использующим hasOwnProperty)

chakrit 23.03.2010 16:02

@Kris, если только кто-то не перезапишет Object.prototype.hasOwnProperty;)

Nick 27.07.2010 23:51

JavaScript использует простой литерал объекта:

var x = { intValue: 5, strValue: "foo" };

Таким образом создается полноценный объект.

JavaScript использует объектную ориентацию на основе прототипов и предоставляет возможность расширять типы во время выполнения:

String.prototype.doubleLength = function() {
    return this.length * 2;
}

alert("foo".doubleLength());

Объект делегирует весь доступ к атрибутам, которые сам не содержит, своему «прототипу», другому объекту. Это можно использовать для реализации наследования, но на самом деле он более мощный (даже если более громоздкий):

/* "Constructor" */
function foo() {
    this.intValue = 5;
}

/* Create the prototype that includes everything
 * common to all objects created be the foo function.
 */
foo.prototype = {
    method: function() {
        alert(this.intValue);
    }
}

var f = new foo();
f.method();

Странно, что никто не подумал о JSON !?

Allain Lalonde 16.09.2008 01:12

Может быть, для некоторых это немного очевидно ...

Установите Firebug и используйте console.info («привет»). Намного лучше, чем использовать random alert ();, который, как я помню, делал много лет назад.

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

Chris Noe 22.09.2008 23:49

журнал функций (сообщение) {если (консоль) console.info (сообщение) еще предупреждение (сообщение)}

Josh 27.09.2008 01:33

Еще лучше, ставьте перед операторами журнала ';;;' а затем minify позаботится об этом за вас. (По крайней мере, модуль Perl, который я использую, имеет эту функцию и утверждает, что это обычное дело.)

Kev 10.11.2008 16:46

Джош: Это не сработает, поскольку консоль не определена. Вы можете проверить typeof console! == "undefined" или window.console.

Eli Grey 13.08.2009 07:03

Всегда включайте: if (typeof ('console') == 'undefined') {console = {log: function () {}}; } то вы можете продолжать использовать console.info, и он просто ничего не делает.

gregmac 02.09.2009 08:37

window.LOG = (typeof (console)! = 'undefined')? console.info: function () {; } // Позволяет также использовать параметры.

MiffTheFox 22.09.2009 23:12

Джош: предлагаю перейти на журнал функций (msg) {if (console.info) console.info (msg) else alert (msg)}

Jason S 23.09.2009 03:57

Или еще лучше: function log (msg) {if (console) console.info (msg) else alert (msg + "\ nHey! Установите Firebug, чтобы не получать это раздражающее сообщение!"); }

Jason S 23.09.2009 03:58

чтобы облегчить день отладки, я обычно использую цитаты из моих любимых комедийных шоу, например console.info («4 наан, Джереми - это безумие!»)

wheresrhys 23.11.2009 12:41

Кроме того, это доступно в Chrome / Safari / IE без Firebug. Но семантика может немного отличаться (чего в мире браузеров нет?)

chakrit 23.03.2010 16:10

Это прекрасно работает: // материал console.info var alertAnyways = true; if (typeof console === "undefined" || typeof console.info === "undefined") {var console = {}; если (alertAnyways) {console.info = функция (сообщение) {предупреждение (сообщение); }; } else {console.info = function (msg) {// ничего не делать}; }} var cl = функция (сообщение) {console.info (сообщение); };

jpswain 13.11.2010 08:32

@gregmac: есть опечатка: typeof ('console') is 'string', поэтому никогда не будет 'undefined'.

dolmen 29.03.2011 01:50

Один из моих любимых - проверка типа конструктора:

function getObjectType( obj ) {  
    return obj.constructor.name;  
}  

window.onload = function() {  
    alert( getObjectType( "Hello World!" ) );  
    function Cat() {  
        // some code here...  
    }  
    alert( getObjectType( new Cat() ) );  
}

Так что вместо устаревшего старого [Object object], который вы часто получаете с ключевым словом typeof, вы можете получить реальные типы объектов, основанные на конструкторе.

Другой - использование переменных аргументов как способ «перегрузить» функции. Все, что вы делаете, это используете выражение для определения количества аргументов и возврата перегруженного вывода:

function myFunction( message, iteration ) {  
    if ( arguments.length == 2 ) {  
        for ( i = 0; i < iteration; i++ ) {  
            alert( message );  
        }  
    } else {  
        alert( message );  
    }  
}  

window.onload = function() {  
    myFunction( "Hello World!", 3 );  
}

Наконец, я бы сказал сокращенное обозначение оператора присваивания. Я узнал об этом из источника фреймворка jQuery ... по-старому:

var a, b, c, d;
b = a;
c = b;
d = c;

Новый (сокращенный) способ:

var a, b, c, d;
d = c = b = a;

Хорошо повеселиться :)

Не рекомендуется полагаться на свойство конструктора, поскольку оно изменяемое и ненадежное. Как только вы начнете экспериментировать со свойством prototype, становится очень легко уничтожить значение .constructor.

Breton 29.01.2009 08:31

Этот очень скрыт и полезен только изредка ;-)

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

var o1 = { foo: 1, bar: 'abc' };
function f() {}
f.prototype = o1;
o2 = new f();
assert( o2.foo === 1 );
assert( o2.bar === 'abc' );
o2.foo = 2;
o2.baz = true;
assert( o2.foo === 2 );
// o1 is unchanged by assignment to o2
assert( o1.foo === 1 );
assert( o2.baz );

Это касается только «простых» значений на o1. Если вы изменяете массив или другой объект, прототип больше не «защищает» исходный объект. Будьте осторожны, когда у вас есть {} или [] в определении / прототипе класса.

Метки времени в JavaScript:

// Usual Way
var d = new Date();
timestamp = d.getTime();

// Shorter Way
timestamp = (new Date()).getTime();

// Shortest Way
timestamp = +new Date();

Кратчайший способ: отметка времени = + новая дата;

Sjoerd Visscher 22.09.2008 13:20

Самый короткий способ умный, но трудный для понимания, поскольку можно подумать, что вы хотели написать + =, но по ошибке написали = +

Rene Saarsoo 09.03.2009 13:12

@ Рене: Аргх. Я даже запуталась твоим собственным утверждением, и «зафиксировала» ответ ...

Adriano Varoli Piazza 08.07.2009 18:10

Еще короче / менее загадочно: просто используйте «timestamp = new Date ();». Вы можете вычесть отметки времени, потому что они имеют функцию valueOf (), которая возвращает целочисленную отметку времени. Если вы хотите использовать метку времени как целое число, используйте либо «+ метка времени» (коротко, но загадочно), либо «timestamp.valueOf ()».

Jason S 23.09.2009 03:54

Конечно, при правильном форматировании / интервале такой двусмысленности можно избежать. Почему так сложно использовать правильный интервал? НЕ пишите «timestamp = + new Date ();», конечно, это сбивает с толку. Вместо этого напишите «timestamp = + new Date ();».

ken 14.01.2010 22:13

@ken: Кто определяет «правильное»? Кому-то нравится меньше пробелов, кому-то нравится больше. Может быть подходящий способ для организации или проекта, но не обязательно глобально.

icktoofay 07.06.2010 10:11

@icktoofay: Найдите мне спецификацию стандартов кодирования где угодно, которая диктует, поддерживает или оправдывает код, написанный как «timestamp = + new Date ();». В качестве альтернативы, пропустите эту строку через любое из огромного количества средств форматирования JS (также известных как beautifiers), и я хочу, чтобы ни один из них не оставил его без места. «Правильный» может быть субъективным в теории, но на практике очень очевидно, что является «правильным», а что - нет.

ken 07.06.2010 21:53

@ken: Да, конечно, timestamp=+new Date(); не очень понятен и, вероятно, не будет поддерживаться никакими рекомендациями по кодированию, но something=123; не редкость и, безусловно, может быть «подходящим» для людей, которые привыкли к этому стилю.

icktoofay 08.06.2010 03:35

Источник Date.now(): developer.mozilla.org/en/JavaScript/Reference/Global_Objects‌ /…

bennedich 20.11.2011 00:01

Function.toString () (неявно):

function x() {
    alert("Hello World");
}
eval ("x = " + (x + "").replace(
    'Hello World',
    'STACK OVERFLOW BWAHAHA"); x("'));
x();

Имейте в виду, что toSource() не является стандартом. В вашем примере у вас есть x + "", который обычно должен быть эквивалентен x.toString(). Полагаю, вы хотели вместо этого использовать x.toSource()?

Ates Goral 01.10.2008 08:21

ааа, вы меня поймали. Я вызываю toString, а не ToSource, но согласно developer.mozilla.org/En/… - Function.ToString () декомпилирует функцию.

Jimmy 08.10.2008 00:03

Да, toSource полезен для отладки в Mozilla. Но, как вы заметили, неявный toString может делать классные (если не сумасшедшие) вещи.

palswim 13.08.2010 03:02

Частные переменные с общедоступным интерфейсом

Он использует небольшую хитрость с определением функции автоматического вызова. Все внутри возвращаемого объекта доступно в общедоступном интерфейсе, а все остальное является частным.

var test = function () {
    //private members
    var x = 1;
    var y = function () {
        return x * 2;
    };
    //public interface
    return {
        setx : function (newx) {
            x = newx;
        },
        gety : function () {
            return y();
        }
    }
}();

assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());

это называется модульным шаблоном, как было названо Эриком Мираглией из yuiblog.com/blog/2007/06/12/module-pattern. Я действительно думаю, что это название вводит в заблуждение, его следует называть шаблоном синглтона или чем-то в этом роде. Я мог бы также добавить, что общедоступные методы также могут вызывать другие общедоступные методы с помощью объекта this. Я постоянно использую этот шаблон в своем коде, чтобы все было организовано и чисто.

mikeycgto 24.08.2009 01:53

Методы (или функции) могут вызываться для объекта, который не относится к тому типу, для работы с которым они были разработаны. Это замечательно для вызова собственных (быстрых) методов для пользовательских объектов.

var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });

Этот код дает сбой, потому что listNodes не является Array

Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);

Этот код работает, потому что listNodes определяет достаточно свойств, подобных массиву (длина, оператор []), для использования sort().

Числа - тоже объекты. Итак, вы можете делать такие классные вещи, как:

// convert to base 2
(5).toString(2) // returns "101"

// provide built in iteration
Number.prototype.times = function(funct){
  if (typeof funct === 'function') {
    for(var i = 0;i < Math.floor(this);i++) {
      funct(i);
    }
  }
  return this;
}


(5).times(function(i){
  string += i+" ";
});
// string now equals "0 1 2 3 4 "

var x = 1000;

x.times(function(i){
  document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document

МОЙ БОГ! Я не знал о toString (radix) ...

Ates Goral 08.01.2010 19:56

Эта реализация times неэффективна: Math.floor вызывается каждый раз, а не только один раз.

dolmen 29.03.2011 11:55

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

var z = ( x = "can you do crazy things with parenthesis", ( y = x.split(" "), [ y[1], y[0] ].concat( y.slice(2) ) ).join(" ") )

alert(x + "\n" + y + "\n" + z)

Выход:

can you do crazy things with parenthesis
can,you,do,crazy,things,with,parenthesis
you can do crazy things with parenthesis

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

Allain Lalonde 22.09.2008 17:01

Если вы хотите, чтобы в обфускаторе это было действительно неясно, используйте китайские или другие символы Юникода: function 喂 (我) {alert (我)};

some 19.11.2008 21:47

Понятие правдивых и ложных ценностей. Вам не нужно делать что-то вроде

если (someVar === undefined || someVar === null) ...

Просто сделайте:

если (! someVar).

Каждому значению соответствует логическое представление.

С этим нужно быть осторожнее. Ноль и пустая строка также преобразуются в false.

Sjoerd Visscher 22.09.2008 13:25

как следствие, вы должны использовать if (!! x) для проверки «истинности» вместо if (x)

HS. 18.07.2009 16:45

Вы можете выполнить метод объекта для любого объекта, независимо от того, есть ли у него этот метод или нет. Конечно, это может не всегда работать (если метод предполагает, что у объекта есть что-то, чего нет), но это может быть чрезвычайно полезно. Например:

function(){
    arguments.push('foo') // This errors, arguments is not a proper array and has no push method
    Array.prototype.push.apply(arguments, ['foo']) // Works!
}

Я не уверен, нравится ли мне это использование или мне следует отшатнуться от страха !? :)

Allain Lalonde 22.09.2008 17:00

также вызовите - Array.prototype.push.call (arguments, 'foo' / *, arg2, arg3 и т. д. * /);

Luke Schafer 30.12.2009 06:53

Joose - хорошая объектная система, если вам нужен объектно-ориентированный объект на основе классов, который похож на CLOS.

// Create a class called Point
Class("Point", {
    has: {
        x: {
            is:   "rw",
            init: 0
        },
        y: {
            is:   "rw",
            init: 0
        }
    },
    methods: {
        clear: function () {
            this.setX(0);
            this.setY(0);
        }
    }
})

// Use the class
var point = new Point();
point.setX(10)
point.setY(20);
point.clear();

Все ваши «скрытые» функции находятся прямо здесь, в вики Mozilla: http://developer.mozilla.org/en/JavaScript.

Есть Справочник по основному JavaScript 1.5, что нового в JavaScript 1.6, что такое новое в JavaScript 1.7, а также что новое в JavaScript 1.8. Просмотрите все те примеры, которые действительно работают и ошибочны в нет.

Посещение:

Вставьте этот код JavaScript в адресную строку своего веб-браузера:

Наслаждайтесь дискотекой на JavaScript :-p

Очень хорошо! Я люблю это :-)

webmat 21.10.2008 05:28

Кто-то назвал бы это делом вкуса, но:

aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }

Тройной оператор можно объединить в цепочку, чтобы он действовал как Scheme (cond ...):

(cond (predicate  (action  ...))
      (predicate2 (action2 ...))
      (#t         default ))

можно записать как ...

predicate  ? action( ... ) :
predicate2 ? action2( ... ) :
             default;

Это очень "функционально", поскольку оно разветвляет ваш код без побочных эффектов. Так что вместо:

if (predicate) {
  foo = "one";
} else if (predicate2) {
  foo = "two";
} else {
  foo = "default";
}

Ты можешь написать:

foo = predicate  ? "one" :
      predicate2 ? "two" :
                   "default";

Также хорошо работает с рекурсией :)

Мне нравится указанный вами синтаксис предиката. Я никогда не думал о таком соединении. аккуратный.

Allain Lalonde 24.09.2008 02:08

Эээ ... В JavaScript есть инструкция switch (). :-)

staticsan 22.06.2009 04:54

Я не большой поклонник операторов switch - это артефакт C, а не функционального программирования. В моем примере для оператора switch все равно потребуются три отдельных оператора, все из которых начинаются с «foo =» - очевидное ненужное повторение.

Andrey Fedorov 22.06.2009 11:14

О боже ... Так что же именно за скрытая особенность? Возможность искажать код, чтобы он выглядел как другой язык? (Думаю, то же самое они сделали и с библиотекой Prototype :)

harto 22.07.2009 03:27

@harto: Я думаю, что JavaScript достаточно гибок и не имеет определенного стиля. Не говорите мне, что вы никогда используете в своем коде элементы из других языков. Это тоже дело вкуса.

Lucas Jones 23.09.2009 00:51

@harto: трюк состоит в том, чтобы использовать тернарный оператор для выполнения if-else в выражениях. Это действительно здорово, что та же языковая функция, которая выполняет эквивалент if, также может выполнять if-else без изменений.

Andrey Fedorov 23.09.2009 20:22

Я, например, приветствую тернарный оператор.

thomasrutter 18.03.2010 19:11

При перечитывании я хотел бы отметить, что это не «превращение кода в другой язык», а на самом деле упрощение семантического значения кода: когда вы пытаетесь сказать «установите foo на одно из трех things », это утверждение должно начинаться с« foo = ... », а не« if ».

Andrey Fedorov 22.03.2010 22:59

Это здорово, но как это спрятать? C существует уже давно, и мы делаем это всегда.

Hogan 06.04.2010 19:49

Тернарная цепочка возможна во многих языках, основанных на C, в этом нет ничего специфического для JavaScript.

Justin Johnson 19.12.2010 12:12

С верхней части моей головы...

Функции

arguments.callee относится к функции, которая содержит переменную "arguments", поэтому ее можно использовать для рекурсии анонимных функций:

var recurse = function() {
  if (condition) arguments.callee(); //calls recurse() again
}

Это полезно, если вы хотите сделать что-то вроде этого:

//do something to all array items within an array recursively
myArray.forEach(function(item) {
  if (item instanceof Array) item.forEach(arguments.callee)
  else {/*...*/}
})

Объекты

Интересная вещь о членах объекта: они могут иметь любую строку в качестве своих имен:

//these are normal object members
var obj = {
  a : function() {},
  b : function() {}
}
//but we can do this too
var rules = {
  ".layout .widget" : function(element) {},
  "a[href]" : function(element) {}
}
/* 
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
  var elements = document.querySelectorAll(rules[item]);
  for (var e, i = 0; e = elements[i++];) rules[item](e);
}

Струны

String.split может принимать в качестве параметров регулярные выражения:

"hello world   with  spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]

String.replace может принимать регулярное выражение в качестве параметра поиска и функцию в качестве параметра замены:

var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"

То, что вы упомянули ... Реализованы ли они во всех браузерах?

cllpse 28.09.2008 18:58

Нет. Я почти уверен, что большинство из них у Mosaic отсутствует.

jsight 01.10.2008 20:58

Да, функции javascript реализованы во всех основных браузерах (IE6 / 7, FF2 / 3, Opera 9+, Safari2 / 3 и Chrome). document.querySelectorAll пока поддерживается не во всех браузерах (это версия JQuery $ () от W3C и $$ () от Prototype)

Leo 09.10.2008 07:33

arguments.callee устарел и будет вызывать исключение в ECMAScript 5.

Hello71 10.01.2011 06:17

не совсем так. Ключ объекта не может (или, скорее, не должен) использовать строку hasOwnProperty в качестве имени, так как это переопределит встроенный метод объекта.

Breton 07.03.2011 13:02

Вы можете на лету переопределить большие части среды выполнения, например изменение конструктора Array или определение undefined. Не то чтобы вам следовало, но это может - мощная функция.

Несколько менее опасная форма этого - добавление вспомогательных методов к существующим объектам. Вы можете, например, сделать IE6 "родной" поддержкой indexOf на массивах.

Вот несколько интересных вещей:

  • Сравнение NaN с чем-либо (даже с NaN) всегда неверно, включая ==, < и >.
  • NaN означает не число, но если вы спросите тип, он фактически вернет число.
  • Array.sort может выполнять функцию компаратора и вызывается драйвером, подобным быстрой сортировке (зависит от реализации).
  • «Константы» регулярных выражений могут поддерживать состояние, как последнее, с чем они сопоставлялись.
  • Некоторые версии JavaScript позволяют получить доступ к членам $0, $1, $2 с помощью регулярного выражения.
  • null не похож ни на что другое. Это ни объект, ни логическое значение, ни число, ни строка, ни undefined. Это немного похоже на «альтернативу» undefined. (Примечание: typeof null == "object")
  • Во внешнем контексте this выдает безымянный объект [Global].
  • Объявление переменной с помощью var вместо того, чтобы просто полагаться на автоматическое объявление переменной, дает среде выполнения реальный шанс оптимизировать доступ к этой переменной.
  • Конструкция with разрушит такие оптимизации
  • Имена переменных могут содержать символы Юникода.
  • Регулярные выражения JavaScript на самом деле не являются регулярными. Они основаны на регулярных выражениях Perl, и можно создавать выражения с опережением, вычисление которых занимает очень и очень много времени.
  • Блоки могут быть помечены и использоваться в качестве целей break. Петли могут быть помечены и использоваться в качестве мишени для continue.
  • Массивы не редкие. Установка 1000-го элемента в пустом массиве должна заполнить его undefined. (зависит от реализации)
  • if (new Boolean(false)) {...} выполнит блок {...}
  • Механизм регулярных выражений Javascript зависит от реализации: например, можно писать "непереносимые" регулярные выражения.

[немного обновлено в ответ на хорошие комментарии; пожалуйста, смотрите комментарии]

null на самом деле (особый) объект. typeof null возвращает «объект».

Ates Goral 01.10.2008 08:35

Вы также можете получить объект [Global] откуда угодно, например так: var glb = function () {return this; } ();

Zilk 29.10.2008 00:35

Глобальный? Вы имеете в виду окно и себя?

some 19.11.2008 21:26

Только что укусил NaN === NaN === false.

some 20.11.2008 15:13

Глобальный объект в javascript в браузере - это объект окна. Когда в глобальной области действия выполняем: window.a == a;

Pim Jager 28.01.2009 02:21

Array.sort не реализован с использованием драйвера быстрой сортировки, потому что это необходимо, чтобы метод сортировки мог обрабатывать абсурдные вещи, такие как Math.random, используемый в качестве функции сортировки, или функции сравнения, которые они изменяют то, что они сравнивают. JavaScriptCore (например, WebKit) использует деревья AVL: - /

olliej 18.02.2009 06:25

«Массивы не редкие» зависит от реализации. Если вы установите значение [1000] и посмотрите на [999], то да, это undefined, но это просто значение по умолчанию, которое вы получаете при поиске несуществующего индекса. Если вы отметили [2000], это тоже будет undefined, но это не значит, что вы еще выделили для него память. В IE8 некоторые массивы являются плотными, а некоторые - разреженными, в зависимости от того, как движок JScript чувствовал себя в то время. Подробнее здесь: blogs.msdn.com/jscript/archive/2008/04/08/…

Chris Nielsen 19.09.2009 22:50

@Ates: не берите то, что возвращает typeof, за индикатор что-либо. Эта функция настолько неработоспособна и совершенно неточна, что вызывает отвращение.

SF. 18.02.2010 18:14

@Ates и @SF: typeof возвращает «объект» для ряда различных типов. Но как только вы узнаете, как он работает и какие типы идентифицируют как «объект», он будет по крайней мере надежным и последовательным в своей реализации.

thomasrutter 18.03.2010 19:00

+1, но это можно было бы значительно улучшить с помощью некоторых ссылок на примеры и т. д.

nickf 19.03.2010 19:57

typeof x === "object" довольно ненадежный, но typeof x === "function" по-прежнему полезен :)

chakrit 23.03.2010 16:24

Сравнение NaN с чем-либо (даже с NaN) всегда неверно. Представляет ли js NaN как фактическую двоичную последовательность с плавающей запятой? Если да, то соответствует ли сравнение двух идентичных NaN? Если вы запутались, посмотрите представление с плавающей запятой.

Razor Storm 28.07.2010 23:40

@Razor Storm: JS использует представление IEEE 754, которое имеет множество битовых шаблонов, которые являются значениями «не числа». NaN в JS представляет их всех (ECMA 262-3 s4.3.23) неразличимо (s8.5). Все NaN должны сравниваться как неравные (s11.9.3), поэтому даже «идентичные» NaN IEEE 754 будут сравниваться как неравные.

David Leonard 29.07.2010 02:29

@ Дэвид Леонард, хорошо, круто, спасибо за ваш ответ, это имеет смысл.

Razor Storm 29.07.2010 04:16

+1. новое логическое значение (false) == true меня взбесило

gion_13 19.01.2011 22:50

Также упоминается в "Javascript: The Good Parts" Крокфорда:

parseInt() опасен. Если вы передадите ему строку, не сообщив ему правильную базу, он может вернуть неожиданные числа. Например, parseInt('010') возвращает 8, а не 10. Передача базы в parseInt заставляет ее работать правильно:

parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.

При проверке кода всегда ищите этот. Отказ от «, 10» - распространенная ошибка, которая остается незамеченной в большинстве тестов.

Doug Domeny 25.06.2009 18:31

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

JamesEggers 23.09.2009 00:32

Почему бы не использовать Math.floor или Number? 10 === Math.floor("010"); 10 === Number("010"); поплавки: 42 === Math.floor("42.69"); 42.69 === Number("42.69");

just somebody 16.12.2009 19:30

@Infinity Если это еще не опубликованный ответ, вам следует это сделать. Я понятия не имел, что так просто переопределить поведение встроенной функции. Конечно, это должно заставить присмотреться к любым пакетам кода, которые они заимствуют с других сайтов. Эту безобидную функцию parseInt можно легко заставить делать что-то не столь безобидное.

bob-the-destroyer 21.06.2010 06:22

Ха .. ты думаешь, что parseInt может быть опасным? Попробуйте сделать undefined = 'foo' вверху страницы ... Javascript очень гибкий ... слишком гибкий

adamJLev 21.06.2010 18:53

Но на самом деле ответ был опубликован, поэтому я просто прокомментировал его: stackoverflow.com/questions/61088/hidden-features-of-javascr‌ ipt /…

adamJLev 21.06.2010 18:59

@Infinity: как насчет переопределения fn, чтобы выделить «ошибку кодирования»? __parseInt = parseInt; parseInt = function (str, base) { if (!base) throw new Error(69, "All your base belong to us"); return __parseInt(str, base); }

JBRWilkinson 26.07.2010 13:51

@ Просто кто-нибудь: Math.floor ведет себя иначе, чем parseInt, например, при работе с отрицательными числами, что означает проверки на + -носпособность и т.д. // истинный ; parseInt ('- 10.2') === -10; // истинный;

kwah 21.09.2010 21:24

Это исправлено в ES5, например parseInt('010') возвращает 10.

Mathias Bynens 30.12.2010 23:52

Это не unexpected number, это восьмеричное число: p

Salman von Abbas 25.03.2011 20:03

В этой теме есть несколько ответов, показывающих, как расширить объект Array через его прототип. Это ПЛОХО IDEA, потому что она нарушает заявление for (i in a).

Ничего страшного, если вы не используете for (i in a) где-нибудь в вашем коде? Ну, только если ваш собственный код только код, который вы используете, что маловероятно внутри браузера. Боюсь, что если люди начнут расширяться их объекты Array, как это, начнется переполнение стека переполнен кучей загадочных ошибок JavaScript.

См. Полезные подробности здесь.

Вам вообще не следует перебирать массив с помощью for..in! Используйте стандартный цикл for () или новый метод forEach () для массивов и for..in строго для итерации по свойствам объекта.

Zilk 29.10.2008 00:45

Попробуйте убедить существующий код в этом совете;)

Chris Noe 29.10.2008 01:31

for (x in y) никогда не работал для меня должным образом для массивов. Я очень быстро научился использовать длинную форму цикла for. Я бы не позволил никакому коду, который использует for (in) в массиве, приближаться к любой моей работе. Вместо этого я мог бы использовать множество действительно приличного, хорошо написанного кода.

Breton 29.01.2009 08:28

Вы просто недостаточно знаете JavaScript. Это не нарушает циклы for-in, вы неправильно их строите. Вы должны проверить все свойства с помощью "yourObject.hasOwnProperty (propertyName)", когда вы выполняете итерацию через for-in.

BYK 22.06.2009 02:06

проверка .hasOwnProperty может быть приемлемой для итерации по объекту, подобному словарю, но не кажется правильным использовать это для массива.

HS. 18.07.2009 16:44

@ statictype.org - да, это не так - в том-то и дело. Вместо этого просто используйте индексную переменную для итерации.

harto 22.07.2009 03:29

Если вам нужна скорость, итерация на основе индекса по массиву - самая быстрая из всех (по сравнению с for-in и forEach).

Srikumar 04.12.2011 14:36

Вот пара ярлыков:

var a = []; // equivalent to new Array()
var o = {}; // equivalent to new Object()

с var a = []; , вы не можете создавать массивы указанного размера. Вам нужно будет использовать var a = new Array (arraySize);

Rajat 07.01.2010 22:20

Есть ли ощутимое преимущество в производительности при объявлении массива в JavaScript с указанным размером?

travis 08.01.2010 02:46

Я бы сказал самоисполняющиеся функции.

(function() { alert("hi there");})();

Поскольку Javascript не имеет области действия блока, вы можете использовать самоисполняющуюся функцию, если хотите определить локальные переменные:

(function() {
  var myvar = 2;
  alert(myvar);
})();

Здесь myvar не мешает и не загрязняет глобальную область видимости и исчезает при завершении функции.

Для чего это полезно? Вы получите те же результаты, если поместите предупреждение вне функции.

PotatoEngineer 20.03.2009 18:39

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

ScottKoon 31.03.2009 23:08

@Paul это хорошо для инкапсуляции.

Mike Robinson 18.05.2009 18:50

Это также хорошо для определения области видимости блока.

Jim Hunziker 23.05.2009 23:41

Это может быть полезно для создания и объявления объекта и его методов за один шаг.

staticsan 22.06.2009 04:52

Да, я заключаю все свои файлы .js в анонимную самоисполняющуюся функцию и прикрепляю все, что хочу глобально доступным внутри нее, к объекту window. Предотвращает загрязнение глобального пространства имен.

cdmckay 05.11.2009 23:11

Я добавил пример того, почему это полезно для этого ответа.

thomasrutter 10.04.2010 07:32

Это также можно использовать для переименования переменных: (function ($) {...}) (jQuery) будет обращаться к глобальному объекту jQuery как $.

Tgr 01.05.2010 17:32

Я не согласен с названием; это вовсе не "самоисполняющееся".

hasen 07.06.2010 08:11

@hasen j: согласен .. он просто создает анонимную функцию и сразу вызывает ее.

Claudiu 24.06.2010 18:43

@ Пол, согласен с Майком; хорошо подходит для инкапсуляции; прочтите книгу Крокфорда, чтобы получить хорошее объяснение.

Neil 05.10.2010 21:27

я думаю, что лучшее название - "немедленная функция"

Jason Miesionczek 05.02.2011 06:15

На самом деле это «выражение немедленно вызываемой функции». Проверьте это: benalman.com/news/2010/11/…

Salman von Abbas 18.07.2011 07:17

Оператор == имеет очень особое свойство, которое создает это тревожное равенство (да, я знаю, что в других динамических языках, таких как Perl, такое поведение было бы ожидаемым, но JavaScript обычно не пытается быть умным в сравнении):

>>> 1 == true
true
>>> 0 == false
true
>>> 2 == true
false

Предотвращение раздражающих ошибок при тестировании в Internet Explorer при использовании console.info () для Firebug:

function log(message) {
    (console || { log: function(s) { alert(s); }).log(message);
}

это не имеет отношения к языку ... :)

gblazex 10.07.2010 14:49

"function (s) {alert (s);}" можно просто заменить на "alert"

mickael9 14.08.2010 08:00

let.

Аналогом отсутствие у var области видимости блока является let, введено в JavaScript 1.7.

  • The let statement provides a way to associate values with variables within the scope of a block, without affecting the values of like-named variables outside the block.
  • The let expression lets you establish variables scoped only to a single expression.
  • The let definition defines variables whose scope is constrained to the block in which they're defined. This syntax is very much like the syntax used for var.
  • You can also use let to establish variables that exist only within the context of a for loop.
  function varTest() {
        var x = 31;
    if (true) {
      var x = 71;  // same variable!
      alert(x);  // 71
    }
    alert(x);  // 71
  }

  function letTest() {
    let x = 31;
    if (true) {
      let x = 71;  // different variable
      alert(x);  // 71
    }
    alert(x);  // 31
  }

С 2008 года JavaScript 1.7 поддерживается в FireFox 2.0+ и Safari 3.x.

Генераторы и итераторы (работает только в Firefox 2+ и Safari).

function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();
for (var i = 0; i < 10; i++) {
  document.write(g.next() + "<br>\n");
}

The function containing the yield keyword is a generator. When you call it, its formal parameters are bound to actual arguments, but its body isn't actually evaluated. Instead, a generator-iterator is returned. Each call to the generator-iterator's next() method performs another pass through the iterative algorithm. Each step's value is the value specified by the yield keyword. Think of yield as the generator-iterator version of return, indicating the boundary between each iteration of the algorithm. Each time you call next(), the generator code resumes from the statement following the yield.

In normal usage, iterator objects are "invisible"; you won't need to operate on them explicitly, but will instead use JavaScript's for...in and for each...in statements to loop naturally over the keys and/or values of objects.

var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "<br>\n");
}

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

var obj = { prop1: 42, prop2: 43 };

obj.prop2 = undefined;

for (var key in obj) {
    ...

Свойство prop2 по-прежнему будет частью итерации. Если вы хотите полностью избавиться от prop2, вам следует вместо этого сделать:

delete obj.prop2;

Свойство prop2 больше не будет отображаться при итерации свойств.

Обратите внимание, что оператор удаления не лишен специфических особенностей браузера. Например, это приведет к сбою с большой ошибкой, если вы попробуете его в IE, а объект не является собственным JS-объектом (даже при удалении свойства, которое вы добавили сами). Он также не предназначен для удаления переменной, как в delete myvar; но я думаю, что это работает в некоторых браузерах. Однако код в приведенном выше ответе кажется довольно безопасным.

thomasrutter 10.04.2010 07:37

кстати, undefined тоже может быть переменной! Попробуйте var undefined = "something"

Johann Philipp Strathausen 13.02.2012 01:01

Если вы ищете в Google достойную ссылку на JavaScript по данной теме, включите в свой запрос ключевое слово «mdc», и ваши первые результаты будут из Центра разработчиков Mozilla. Я не ношу с собой никаких офлайн-справочников или книг. Я всегда использую трюк с ключевыми словами "mdc", чтобы напрямую добраться до того, что я ищу. Например:

Google: Сортировка массива javascript mdc
(в большинстве случаев вы можете опустить "javascript")

Обновлять: Mozilla Developer Центр был переименован в Mozilla Developer Сеть. Уловка с ключевым словом "mdc" по-прежнему работает, но вскоре нам может потребоваться вместо этого начни использовать "mdn".

Что мы сделали, чтобы заслужить связь с LMGTFY ...

MiseryIndex 18.06.2009 21:04

Вау, отличный ресурс. Мгновенно лучше, чем дерьмовые w3schools ...

DisgruntledGoat 23.09.2009 03:31

Вам даже не нужно гуглить, если вы используете Firefox: просто введите "array mdc" в адресную строку и нажмите Enter.

Sasha Chedygov 10.04.2010 08:00

Лучшая часть - это то, как этот вопрос о переполнении стека находится на первой странице результатов :)

Jiaaro 26.05.2010 17:05

Предложение это: Promotejs.com, массовая инициатива SEO, направленная на продвижение результатов MDC в результатах поиска Google.

Yahel 11.11.2010 03:30

Теперь это центр документации MDN, поэтому ключевое слово mdc по-прежнему актуально :)

Aleadam 15.03.2011 00:14

Если вы слепо eval() строку JSON для ее десериализации, вы можете столкнуться с проблемами:

  1. Это небезопасно. Строка может содержать вызовы вредоносных функций!
  2. Если вы не заключите строку JSON в круглые скобки, имена свойств могут быть ошибочно приняты за метки, что приведет к неожиданному поведению или синтаксической ошибке:

    eval("{ \"foo\": 42 }"); // syntax error: invalid label
    eval("({ \"foo\": 42 })"); // OK
    

Вы не должны использовать eval для JSON. Используйте JSON.parse () и JSON.stringify ().

Srikumar 04.12.2011 14:48

function l(f,n){n&&l(f,n-1,f(n));}

l( function( loop ){ alert( loop ); }, 5 );

предупреждения 5, 4, 3, 2, 1

В этом есть смысл, но ... Я бы никогда тебя не нанял.

user55776 13.07.2009 04:36

Чтобы преобразовать число с плавающей запятой в целое число, вы можете использовать один из следующих загадочных приемов (пожалуйста, не делайте этого):

  1. 3.14 >> 0 (через 2.9999999999999999 >> .5?)
  2. 3.14 | 0 (через Как лучше всего преобразовать числа с плавающей запятой в целое число в JavaScript?)
  3. 3.14 & -1
  4. 3.14 ^ 0
  5. ~~3.14

По сути, применение любой бинарной операции к веществу с плавающей запятой, которая не изменяет конечное значение (т.е. функцию идентификации), приводит к преобразованию числа с плавающей запятой в целое число.

Пожалуйста, просто используйте Math.floor ().

Jason S 23.09.2009 03:46

@TheLindyHop, дело в том, что действительные числа и бинарные операторы нелегко смешивать, и в качестве эмульгатора используется неявное приведение к целому числу :) Даже если вы можете утверждать, что something_binary ^ 0 == something_binary, для этого потребуется исключение должно быть сделано в реализации и документации оператора xor.

Ates Goral 04.10.2011 21:53

Интересно. Это сделано специально для разработчиков javascript? может из-за лени? обычно это считается сломанным.

NullVoxPopuli 04.10.2011 23:04

@TheLindyHop: Лень, глупость - факт остается фактом: это детерминированное поведение от имени JavaScript. Я указал на это только потому, что речь идет о «скрытых возможностях JavaScript». :) И будет ли это считать сломано немного спорный в контексте этого вопроса, но я бы сказал, что это было бы ожидаемое поведение.

Ates Goral 04.10.2011 23:17

jQuery и JavaScript:

Имена переменных могут содержать несколько нечетных символов. Я использую символ $ для обозначения переменных, содержащих объекты jQuery:

var $links = $("a");

$links.hide();

Шаблон связывания объектов в jQuery довольно хорош, но применение этого шаблона может немного запутать. К счастью, JavaScript позволяет разбивать строки, например:

$("a")
.hide()
.fadeIn()
.fadeOut()
.hide();

Общий JavaScript:

Я считаю полезным эмулировать область видимости с помощью самоисполняющихся функций:

function test()
{
    // scope of test()

    (function()
    {
        // scope inside the scope of test()
    }());

    // scope of test()
}

Если вы хотите, чтобы это было действительно странно: function 喂 (我) {alert (我)};喂 («мир»);

some 19.11.2008 21:45

Операторы функций и выражения функций обрабатываются по-разному.

function blarg(a) {return a;} // statement
bleep = function(b) {return b;} //expression

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

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

Прототипное наследование (популяризированный Дугласом Крокфордом) полностью меняет ваше представление о множестве вещей в Javascript.

Object.beget = (function(Function){
    return function(Object){
        Function.prototype = Object;
        return new Function;
    }
})(function(){});

Это убийца! Жалко как почти никто не пользуется.

Это позволяет вам «порождать» новые экземпляры любого объекта, расширять их, сохраняя при этом (живую) прототипную ссылку наследования на другие их свойства. Пример:

var A = {
  foo : 'greetings'
};  
var B = Object.beget(A);

alert(B.foo);     // 'greetings'

// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo);     // 'hello'

A.bar = 'world';
alert(B.bar);     // 'world'


// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo);     // 'hello'

B.bar = 'universe';
alert(A.bar);     // 'world'

Значение window.name сохраняется при изменении страницы, может быть прочитано родительским окном, если оно находится в том же домене (если в iframe, используйте document.getElementById("your frame's ID").contentWindow.name для доступа к нему) и ограничено только доступной памятью.

Обязательно используйте метод hasOwnProperty при итерации по свойствам объекта:

for (p in anObject) {
    if (anObject.hasOwnProperty(p)) {
        //Do stuff with p here
    }
}

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

Если вы хотите удалить элемент из массива, можно использовать оператор Удалить как таковой:

var numbers = [1,2,3,4,5];
delete numbers[3];
//numbers is now [1,2,3,undefined,5]

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

Таким образом, чтобы обойти эту проблему, вместо использования Удалить используйте метод массива сращивание ... как таковой:

var numbers = [1,2,3,4,5];
numbers.splice(3,1);
//numbers is now [1,2,3,5]

Первый аргумент сращивание - порядковый номер в массиве [index], а второй - количество удаляемых элементов.

Микрософт подарок для JavaScript: AJAX

AJAXCall('http://www.abcd.com/')

function AJAXCall(url) {
 var client = new XMLHttpRequest();
 client.onreadystatechange = handlerFunc;
 client.open("GET", url);
 client.send();
}

function handlerFunc() {
 if (this.readyState == 4 && this.status == 200) {
 if (this.responseXML != null)
   document.write(this.responseXML)
 }
}

Большие циклы быстрее выполняются в состоянии while и в обратном направлении - то есть, если порядок цикла для вас не имеет значения. Примерно в 50% моего кода это обычно не так.

т.е.

var i, len = 100000;

for (var i = 0; i < len; i++) {
  // do stuff
}

Медленнее, чем:

i = len;
while (i--) {
  // do stuff
}

Есть ли у вас статьи, объясняющие этот результат? Было бы интересно получить дополнительную информацию, почему это происходит.

Alex 18.06.2009 20:39

Так ли это во всех реализациях Javascript?

Esteban Küber 30.06.2009 19:26

Я предполагаю, что второй быстрее, потому что ему не нужно оценивать i <len каждый ход, что требует 100000 для сравнения с i. Это, вероятно, быстрее, чем проверка, равен ли i 0 или нет.

user55776 13.07.2009 04:20

-1; у вас есть доказательства этого? какую реализацию вы используете? Я просто попробовал следующий код (замените pipe | символы на символы новой строки) на jsdb, который использует Spidermonkey (движок javascript Firefox), и это, по сути, такое же время выполнения. var i, len = 15000000; | d1 = новая дата (); для (var я = 0; я <len; я ++) {}; новая дата () - d1 | d1 = новая дата (); i = len; в то время как я--) {}; новая дата () - d1

Jason S 23.09.2009 03:42

@Jason - эталоном является IE, так как это доминирующий браузер - по мере того, как новые браузеры конкурируют, мы наблюдаем потрясающие улучшения в движках JS, поэтому, конечно, вы увидите, что движки улучшатся по этому шаблону, но вы имеют, чтобы пересечь браузер протестирует вашу оптимизацию, когда подсчитываются миллисекунды Итак, вы проверяли этот код и в других браузерах?

Remy Sharp 25.09.2009 01:42

Это верно, когда вы ничего не делаете, но когда вы меняете массив, он работает быстрее.

tmim 06.08.2010 14:54

Также существует почти неизвестный синтаксис JavaScript:

var a;
a=alert(5),7;
alert(a);    // alerts undefined
a=7,alert(5);
alert(a);    // alerts 7

a=(3,6);
alert(a);    // alerts 6

Подробнее об этом здесь.

В большинстве случаев вы можете использовать объекты вместо переключателей.

function getInnerText(o){
    return o === null? null : {
        string: o,
        array: o.map(getInnerText).join(""),
        object:getInnerText(o["childNodes"])
    }[typeis(o)];
}

Обновление: если вас беспокоит неэффективность заранее оцененных случаев (почему вы беспокоитесь об эффективности на столь раннем этапе разработки программы?), Вы можете сделать что-то вроде этого:

function getInnerText(o){
    return o === null? null : {
        string: function() { return o;},
        array: function() { return o.map(getInnerText).join(""); },
        object: function () { return getInnerText(o["childNodes"]; ) }
    }[typeis(o)]();
}

Это более обременительно для ввода (или чтения), чем для переключателя или объекта, но при этом сохраняются преимущества использования объекта вместо переключателя, подробно описанные в разделе комментариев ниже. Этот стиль также упрощает превращение этого в настоящий «класс», когда он достаточно вырастет.

update2: с предлагаемыми расширениями синтаксиса для ES.next это становится

let getInnerText = o -> ({
    string: o -> o,
    array: o -> o.map(getInnerText).join(""),
    object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);

Вот как Python обходится без оператора switch.

outis 23.07.2009 14:32

Проблема в том, что он всегда оценивает все случаи.

Kornel 03.01.2011 00:53

@porneL, это правда, но дает некоторые преимущества: это логически чище: прецеденты - это строки, которые ищутся в хеш-таблице, а не выражения, каждое из которых должно оцениваться на равенство, пока одно из них не вернет истину. Таким образом, хотя оценивается больше «значений», оценивается меньшее количество «ключей». Объекты могут быть динамически сгенерированы и изменены для последующего масштабирования, отражены для печати пользовательского интерфейса или создания документов и даже заменены функцией динамического «поиска», что лучше, чем копирование / вставка кейсов. Нет никакой путаницы в отношении разрывов, провалов или значений по умолчанию. Может быть сериализован JSON ...

Breton 02.02.2011 06:04

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

Breton 02.02.2011 06:11

Я знаю, что это поздний ввод, но если у вас нет специальной логики проверки типов, когда массив когда-либо будет работать с вашим примером? var arr = []; typeof arr; // object

keeganwatkins 08.10.2011 08:57

Слишком верно, хотя обратите внимание, что в последнем примере я использую «typeis (o)», хотя на самом деле typeof был просто тем, что я использовал в качестве целесообразного примера, и это довольно второстепенно по отношению к основному вопросу. Я отредактирую другие примеры, чтобы они соответствовали.

Breton 08.10.2011 10:45

Вы можете поймать исключения в зависимости от их типа. Цитируется из MDC:

try {
   myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
   // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
   // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
   // statements to handle EvalError exceptions
} catch (e) {
   // statements to handle any unspecified exceptions
   logMyErrors(e); // pass exception object to error handler
}

ПРИМЕЧАНИЕ: Условные предложения catch - это расширение Netscape (и, следовательно, Mozilla / Firefox), которое не является частью спецификации ECMAScript и, следовательно, на него нельзя полагаться, за исключением определенных браузеров.

Я ничего не мог с собой поделать: поймай (меня, если сможешь)

Ates Goral 29.01.2009 08:24

Прочтите примечание со страницы MDC, которую вы процитировали: условные предложения catch - это расширение Netscape (и, следовательно, Mozilla / Firefox), которое не является частью спецификации ECMAScript и, следовательно, на него нельзя полагаться, за исключением определенных браузеров.

Jason S 23.09.2009 03:38

Вы можете превратить любой * объект с целочисленными свойствами и свойство длины в собственно массив и, таким образом, снабдить его всеми методами массива, такими как push, pop, splice, map, filter, reduce и т. д.

Array.prototype.slice.call({"0":"foo", "1":"bar", 2:"baz", "length":3 }) 

// возвращает ["foo", "bar", "baz"]

Это работает с объектами jQuery, коллекциями html и объектами Array из других фреймов (как одно из возможных решений для всего типа массива). Я говорю, что если у него есть свойство length, вы можете превратить его в массив, и это не имеет значения. Существует множество объектов, не являющихся массивами, со свойством length, помимо объекта arguments.

Синтаксический сахар: встроенные замыкания цикла for

var i;

for (i = 0; i < 10; i++) (function ()
{
    // do something with i
}());

Нарушает почти все кодовые соглашения Дугласа Крокфорда, но я думаю, что на это довольно приятно смотреть, тем не менее :)


Альтернатива:

var i;

for (i = 0; i < 10; i++) (function (j)
{
    // do something with j
}(i));

Извините, я имел в виду и аргумент, и параметр :)

Ionuț G. Stan 09.03.2009 13:07

Разве это не превращает функцию в каждую итерацию цикла?

user55776 13.07.2009 04:43

Кажется, это работает только в Firefox (SpiderMonkey). Внутри функции:

  • arguments[-2] дает количество аргументов (то же, что и arguments.length)
  • arguments[-3] дает функцию, которая была вызвана (так же, как arguments.callee)

Проверка наличия. Так часто я вижу такие вещи

var a = [0, 1, 2];

// code that might clear the array.

if (a.length > 0) {
 // do something
}

вместо этого, например, просто сделайте это:

var a = [0, 1, 2];

// code that might clear the array.

if (a.length) { // if length is not equal to 0, this will be true
 // do something
}

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

Вот пример того, как использовать значение по умолчанию.

function (someArgument) {
      someArgument || (someArgument = "This is the deault value");
}

Это мои два цента. Есть и другие самородки, но пока это все.

Предупреждение: someArgument будет переопределен, если он оценивается как false (который включает значения 0, NaN, false, "" и null, а также пропуск аргумента)

Jason S 23.09.2009 03:35

Вам никогда не придется использовать eval() для сборки имен глобальных переменных.

То есть, если у вас есть несколько глобальных объектов (по какой-либо причине) с именем spec_grapes, spec_apples, вам не нужно обращаться к ним с помощью eval("spec_" + var).

Все глобальные объекты являются членами window[], поэтому вы можете использовать window["spec_" + var].

Также вы можете сократить «if (typeof myvar! = 'Undefined')» до «if (window.myvar)»

BarelyFitz 01.06.2009 05:19

Помните, что это Только в движке javascript браузера. Вы можете запустить автономный движок Javascript. Кто-нибудь на стороне сервера javascript? - Просто придирки, я знаю ...

Esteban Küber 30.06.2009 17:29

@voyager: Согласен - jaxer.org круто!

Lucas Jones 23.09.2009 01:00

@BarelyFitz: Неправда. Переменная window.myvar может иметь любое из следующих значений: 0, false, "", null или NaN. (могут быть и другие, но я думаю, что уже рассказал о них.)

Jason S 23.09.2009 03:34

функция getGlobal () {return (function inner () {return this;}) (); }; - даже махинации "применить", "вызов" и прототипы не могут заставить это не возвращать глобальную область видимости (которая в сети называется "окном")

Luke Schafer 30.12.2009 06:55

В начале вашего скрипта вы можете просто указать var global = this. Это сработает независимо от того, в каком контексте вы находитесь.

kzh 22.02.2011 00:26

@kzh: ваша переменная global могла быть перегружена охватывающей областью.

dolmen 29.03.2011 19:13

Вы можете перебирать массивы, используя "for in"

Марк Сидад указал на полезность цикла for in:

// creating an object (the short way, to use it like a hashmap)
var diner = {
"fruit":"apple"
"veggetable" = "bean"
}

// looping over its properties
for (meal_name in diner ) {
    document.write(meal_name+"<br \n>");
}

Результат :

fruit
veggetable

Но это еще не все. Поскольку вы можете использовать такой объект, как ассоциативный массив, вы можете обрабатывать ключи и значения, точно так же, как цикл foreach:

// looping over its properties and values
for (meal_name in diner ) {
    document.write(meal_name+" : "+diner[meal_name]+"<br \n>");
}

Результат :

fruit : apple
veggetable : bean

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

var my_array = ['a', 'b', 'c'];
for (index in my_array ) {
    document.write(index+" : "+my_array[index]+"<br \n>");
}

Результат :

0 : a
1 : b
3 : c

Вы можете легко удалить известный элемент из массива

var arr = ['a', 'b', 'c', 'd'];
var pos = arr.indexOf('c');
pos > -1 && arr.splice( pos, 1 );

Вы можете легко перемешать массив

arr.sort(function() Math.random() - 0.5); - не совсем случайное распределение, см. Комментарии.

+1 за красивую перетасовку массива

Peter Perháč 26.05.2009 18:59

-1 для перемешивания массива. Аргумент функции sort () всегда должен приводить к последовательному упорядочиванию. У вас нет доказательств того, что результаты будут отображаться как случайное распределение; это зависит от реализации sort ().

Jason S 23.09.2009 03:26

Если вам действительно нужна случайная сортировка, используйте функцию (a, b), которая сравнивает "случайную" функцию g (x, k), примененную к a и b (сравните g (a, k) и g (b, k)) где k - некоторый параметр, который остается постоянным, по крайней мере, в течение всего времени сортировки, а g () - хэш-функция некоторого вида.

Jason S 23.09.2009 03:29

Или, что еще лучше, просто используйте тасование Фишера-Йетса. en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

Jason S 23.09.2009 03:30

Скобки необязательны при создании новых «объектов».

function Animal () {

}

var animal = new Animal();
var animal = new Animal;

То же самое.

это часть ECMAScript или просто движок Mozilla Spidermonkey? (работает с оболочкой Spidermonkey)

Jason S 23.09.2009 03:24

не уверен, я только что воспользовался этим предположением в течение некоторого времени. работает в IE, IIS тоже

Dave 23.09.2009 20:19

Мне нравится оставлять здесь круглые скобки, потому что они напоминают мне, что вы на самом деле вызываете функцию (а 'new' заставляет неявно возвращать 'this').

Nick 25.07.2010 19:37

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

function fn(){
    var cat = "meow";
    var dog = "woof";
    return [cat,dog];
};

var [cat,dog] = fn();  // Handy!

alert(cat);
alert(dog);

Это часть ядра JS, но я почему-то не осознавал этого до этого года.

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

Kamarey 22.09.2009 23:56

Это «деструктурирующее задание»; Я считаю, что он поддерживается только в версиях Firefox с JavaScript 1.7 и новее. Это определенно вызывает ошибку в Opera 10 и Chrome 3, а также в IE. См. developer.mozilla.org/en/…

NickFitz 08.10.2009 15:16

Мне бы хотелось увидеть подобный синтаксис в других языках, например в C#.

Greg 01.01.2010 03:07

А пока это не хуже: function fn(){ return {cat:"meow",dog:"woof"}; // Handy! }; var snd = fn(); alert(snd.cat); alert(snd.dog);.

Plynx 20.02.2010 01:46

не работает в Chrome> 15 w> JS 1.6, иначе это было бы самым большим удивлением. Я даже пробовал это однажды, пытаясь подражать списку PHP (...)

Lorenz Lo Sauer 27.10.2011 01:39

Может быть, один из менее известных:

arguments.callee.caller + Функция # toString ()

function called(){
    alert("Go called by:\n"+arguments.callee.caller.toString());
}

function iDoTheCall(){
    called();
}

iDoTheCall();

Распечатывает исходный код iDoTheCall - Устарело, но иногда может быть полезно, когда единственным вариантом является оповещение ...

Вы можете привязать объект JavaScript как атрибут элемента HTML.

<div id = "jsTest">Klick Me</div>
<script type = "text/javascript">
    var someVariable = 'I was klicked';
    var divElement = document.getElementById('jsTest');
    // binding function/object or anything as attribute
    divElement.controller = function() { someVariable += '*'; alert('You can change instance data:\n' + someVariable ); };
    var onclickFunct = new Function( 'this.controller();' ); // Works in Firefox and Internet Explorer.
    divElement.onclick = onclickFunct;
</script>

Если вы пытаетесь изолировать код javascript и отключить все возможные способы оценки строк в код javascript, имейте в виду, что блокировка всех очевидных eval / document.write / new Function / setTimeout / setInterval / innerHTML и других манипуляций с DOM недопустима. довольно.

Для любого объекта o o.constructor.constructor("alert('hi')")() вызовет диалоговое окно с предупреждением со словом «привет» в нем.

Вы можете переписать это как

var Z = "constructor";
Z[Z][Z]("alert('hi')")();

Веселая штука.

Это скорее скрытая ошибка, чем скрытая функция, но она чрезвычайно интересна, учитывая, что я уже пытался заблокировать такие вещи, как eval. Действительно очень интересно :-) +1

JJ. 29.04.2010 18:33

Вы могли бы с пользой упомянуть здесь, что причина этого заключается в том, что конструктор любого объекта всегда является некоторой функцией, и что конструктором этой функции всегда будет Function - конструктор функции, который может создавать функции из строк. Function(str) фактически возвращает function() { eval(str) }.

James Hart 18.08.2010 01:23

Самые быстрые циклы в JavaScript - это while (i--). Во всех браузерах. Поэтому, если порядок обработки элементов вашего цикла не так важен, вы должны использовать форму while (i--):

var names = new Array(1024), i = names.length;
while(i--)
  names[i] = "John" + i;

Кроме того, если вам нужно использовать цикл for () в дальнейшем, не забудьте всегда кешировать свойство .length:

var birds = new Array(1024); 
for(var i = 0, j = birds.length; i < j; i++)
  birds[i].fly();

Для объединения больших строк используйте массивы (это быстрее):

var largeString = new Array(1024), i = largeString.length;
while(i--) {
  // It's faster than for() loop with largeString.push(), obviously :)
  largeString[i] = i.toString(16);
}

largeString = largeString.join("");

Это намного быстрее, чем largeString += "something" внутри цикла.

Я уже некоторое время использую вариант цикла for вашего while(i--): for (var i=names.length;i--;) {...

slebetman 11.01.2010 17:00

Я не согласен. В firefox (function(){var a=new Array(10000),i=10000;while(--i){a[i]=i}})() занимает около 7 миллисекунд, тогда как (function () {var a = new Array (10000); for (var i = 0; i <10000; i ++) {a [i] = i}}) () занимает около 2 миллисекунды.

tmim 06.08.2010 14:46

Оператор объединения очень крутой и создает чистый и лаконичный код, особенно когда вы объединяете его в цепочку: a || b || c || "default"; Проблема в том, что, поскольку он работает, вычисляя значение bool, а не null, если значения, которые оцениваются как false, допустимы, они будут часто перебираться смотрел. Не волнуйтесь, в этих случаях просто вернитесь к старому доброму тернарному оператору.

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

var getInstance = function(objectName) {
  if ( !getInstance.instances ) {
    getInstance.instances = {};
  }

  if ( !getInstance.instances[objectName] ) {
    getInstance.instances[objectName] = new window[objectName];
  }

  return getInstance.instances[objectName];
};

Также обратите внимание на new window[objectName];, который был ключом к созданию экземпляров объектов по имени. Я понял это 2 месяца назад.

В том же духе, работая с DOM, я часто закапываю функциональные параметры и / или флаги в узлы DOM, когда я впервые инициализирую любую добавляемую функциональность. Я добавлю пример, если кто-то кричит.

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

var x = [1,2,3];
for ( i in x ) {
    if ( !x.hasOwnProperty(i) )  { continue; }
    console.info(i, x[i]);
}

Прочтите здесь, чтобы узнать больше об этом.

Наконец, with - это почти всегда плохая идея.

Вы можете сделать «классы», у которых есть частные (недоступные вне определения «класса») статические и нестатические члены, в дополнение к публичным членам, используя замыкания.

Обратите внимание, что в приведенном ниже коде есть два типа открытых членов. Зависящие от экземпляра (определенные в конструкторе), которые имеют доступ к частным членам пример, и общие члены (определенные в объекте prototype), которые имеют доступ только к частным членам статический.

var MyClass = (function () {
    // private static
    var nextId = 1;

    // constructor
    var cls = function () {
        // private
        var id = nextId++;
        var name = 'Unknown';

        // public (this instance only)
        this.get_id = function () { return id; };

        this.get_name = function () { return name; };
        this.set_name = function (value) {
            if (typeof value != 'string')
                throw 'Name must be a string';
            if (value.length < 2 || value.length > 20)
                throw 'Name must be 2-20 characters long.';
            name = value;
        };
    };

    // public static
    cls.get_nextId = function () {
        return nextId;
    };

    // public (shared across instances)
    cls.prototype = {
        announce: function () {
            alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
                  'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
        }
    };

    return cls;
})();

Чтобы проверить этот код:

var mc1 = new MyClass();
mc1.set_name('Bob');

var mc2 = new MyClass();
mc2.set_name('Anne');

mc1.announce();
mc2.announce();

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

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

Чтобы расширить этот класс, вы должны поместить MyClass.call(this); в начало конструктора в расширяющемся классе. Вам также потребуется копировать для объекта MyClass.prototype (не используйте его повторно, так как вы также измените элементы MyClass.

Если бы вы заменили метод announce, вы бы вызвали из него MyClass.announce следующим образом: MyClass.prototype.announce.call(this);

Оператор JavaScript typeof, используемый с массивами или нулями, всегда возвращает значение object, которое в некоторых случаях может не соответствовать ожиданиям программиста.

Вот функция, которая также вернет правильные значения для этих элементов. Распознавание массивов было скопировано из книги Дугласа Крокфорда «JavaScript: хорошие части».

function typeOf (value) {
    var type = typeof value;
    if (type === 'object') {
        if (value === null) {
             type = 'null';
        } else if (typeof value.length === 'number' && 
            typeof value.splice === 'function' && 
            !value.propertyIsEnumerable('length')) {
            type = 'array';
        }
    }
    return type;
}

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

RaYell 30.12.2009 11:49

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

Luke Schafer 18.01.2010 02:10

Использование Function.apply для указания объекта, над которым будет работать функция:

Предположим, у вас есть класс

function myClass(){
 this.fun = function(){
   do something;
 };
}

если позже вы сделаете:

var a = new myClass();
var b = new myClass();

myClass.fun.apply(b); //this will be like b.fun();

Вы даже можете указать массив параметров вызова в качестве второго аргумента

посмотрите это: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Function/apply

Мое первое представление - это не столько скрытая функция, сколько редко используемое приложение функции переопределения свойств. Поскольку вы можете переопределить методы объекта, вы можете кэшировать результат вызова метода, что полезно, если вычисление является дорогостоящим и вам нужна ленивая оценка. Это дает простейшую форму мемоизация.

function Circle(r) {
    this.setR(r);
}

Circle.prototype = {
  recalcArea: function() {
        this.area=function() {
            area = this.r * this.r * Math.PI;
            this.area = function() {return area;}
            return area;
        }
    },
  setR: function (r) {
      this.r = r;
      this.invalidateR();
    },
  invalidateR: function() {
        this.recalcArea();
    }
}

Выполните рефакторинг кода, который кэширует результат в метод, и вы получите:

Object.prototype.cacheResult = function(name, _get) {
  this[name] = function() {
    var result = _get.apply(this, arguments);
    this[name] = function() {
      return result;
    }
    return result;
  };
};

function Circle(r) {
    this.setR(r);
}

Circle.prototype = {
  recalcArea: function() {
        this.cacheResult('area', function() { return this.r * this.r * Math.PI; });
    },
  setR: function (r) {
      this.r = r;
      this.invalidateR();
    },
  invalidateR: function() {
        this.recalcArea();
    }
}

Если вам нужна мемоизированная функция, вы можете ее использовать. Переопределение собственности не происходит.

Object.prototype.memoize = function(name, implementation) {
    this[name] = function() {
        var argStr = Array.toString.call(arguments);
        if (typeof(this[name].memo[argStr]) == 'undefined') {
            this[name].memo[argStr] = implementation.apply(this, arguments);
        }
        return this[name].memo[argStr];
    }
};

Обратите внимание, что это зависит от стандартного преобразования массива в строку и часто не работает должным образом. Исправление оставлено в качестве упражнения для читателя.

Моя вторая заявка - это геттеры и сеттеры. Я удивлен, что они еще не были упомянуты. Поскольку официальный стандарт отличается от стандарта де-факто (defineProperty vs. определить [GS] etter), а Internet Explorer почти не поддерживает официальный стандарт, они обычно бесполезны. Может, поэтому их не упомянули. Обратите внимание, что вы можете довольно хорошо комбинировать методы получения и кеширование результатов:

Object.prototype.defineCacher = function(name, _get) {
    this.__defineGetter__(name, function() {
        var result = _get.call(this);
        this.__defineGetter__(name, function() { return result; });
        return result;
    })
};

function Circle(r) {
    this.r = r;
}

Circle.prototype = {
  invalidateR: function() {
        this.recalcArea();
    },
  recalcArea: function() {
        this.defineCacher('area', function() {return this.r * this.r * Math.PI; });
    },
  get r() { return this._r; }
  set r(r) { this._r = r; this.invalidateR(); }
}

var unit = new Circle(1);
unit.area;

Эффективное объединение геттеров, сеттеров и кеширования результатов немного сложнее, потому что вам нужно предотвратить аннулирование или обойтись без автоматического аннулирования при наборе, что и делается в следующем примере. В основном это проблема, если изменение одного свойства приведет к аннулированию нескольких других (представьте, что в этих примерах есть свойство «диаметр»).

Object.prototype.defineRecalcer = function(name, _get) {
  var recalcFunc;
  this[recalcFunc='recalc'+name.toCapitalized()] = function() {
    this.defineCacher(name, _get);
  };
  this[recalcFunc]();
  this.__defineSetter__(name, function(value) {
      _set.call(this, value);
      this.__defineGetter__(name, function() {return value; });
  });
};

function Circle(r) {
    this.defineRecalcer('area',
             function() {return this.r * this.r * Math.PI;},
             function(area) {this._r = Math.sqrt(area / Math.PI);},
    );
    this.r = r;
}

Circle.prototype = {
  invalidateR: function() {
        this.recalcArea();
    },
  get r() { return this._r; }
  set r(r) { this._r = r; this.invalidateR(); }
}

Шаблон модуля

<script type = "text/javascript">
(function() {

function init() {
  // ...
}

window.onload = init;
})();
</script>

Переменные и функции, объявленные без оператора var или вне функции, будут определены в глобальной области видимости. Если переменная / функция с таким же именем уже существует, она будет автоматически переопределена, что может привести к очень трудным для поиска ошибкам. Распространенное решение - заключить все тело кода в анонимную функцию и немедленно выполнить ее. Таким образом, все переменные / функции определены в области действия анонимной функции и не попадают в глобальную область видимости.

Чтобы явно определить переменную / функцию в глобальной области видимости, они должны иметь префикс window:

window.GLOBAL_VAR = 12;
window.global_function = function() {};

Пространства имён

В более крупных приложениях или фреймворках JavaScript может быть полезно организовать код в пространствах имен. В JavaScript нет встроенного модуля или концепции пространства имен, но его легко эмулировать с помощью объектов JavaScript. Это создаст пространство имен ns и присоединит к нему функцию foo.

if (!window.ns) {
  window.ns = {};
}

window.ns.foo = function() {};

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

Заголовок файла ns/button.js может выглядеть так:

if (!window.ns) {
  window.ns = {};
}
if (!window.ns.button) {
  window.ns.button = {};
}

// attach methods to the ns.button namespace
window.ns.button.create = function() {};

Или вы можете использовать это: «window.ns = window.ns || {} ”Ad @ m

kirb 30.08.2011 14:34

Вот простой способ думать об «этом». 'This' внутри функции будет ссылаться на будущие экземпляры объекта функции, обычно созданные с помощью оператора new. Итак, ясно, что «this» внутренней функции никогда не будет относиться к экземпляру внешней функции.

Вышесказанное должно уберечь человека от неприятностей. Но есть более сложные вещи, которые вы можете сделать с этим.


Пример 1:


     function DriveIn()
     {
          this.car = 'Honda';
          alert(this.food);  //'food' is the attribute of a future object 
                             //and DriveIn does not define it.
     }

     var A = {food:'chili', q:DriveIn};  //create object A whose q attribute 
                                         //is the function DriveIn;

     alert(A.car); //displays 'undefined' 
     A.q();        //displays 'chili' but also defines this.car.
     alert(A.car); //displays 'Honda' 


Правило этого:

Всякий раз, когда функция вызывается как атрибут объекта, любое вхождение this внутри функции (но вне любых внутренних функций) относится к объекту.

Нам нужно прояснить, что «Правило этого» применяется даже при использовании оператора new. За кулисами new прикрепляет this к объекту через атрибут конструктора объекта.


Пример 2:


      function Insect ()
      {
           this.bug = "bee";
           this.bugFood = function()
           {
               alert("nectar");
           }
       }

      var B = new Insect();
      alert(B.constructor); //displays "Insect"; By "The Rule of This" any
                            //ocurrence of 'this' inside Insect now refers 
                            //to B.    

Чтобы сделать это еще яснее, мы можем создать экземпляр Insect без использования оператора new.

Пример 3:

   
    var C = {constructor:Insect};  //Assign the constructor attribute of C, 
                                   //the value Insect.
    C.constructor();               //Call Insect through the attribute. 
                                   //C is now an Insect instance as though it 
                                   //were created with operator new. [*]
    alert(C.bug);                  //Displays "bee." 
    C.bugFood();                   //Displays "nectar." 

[*] Единственное различие, которое я могу различить, состоит в том, что в примере 3 'конструктор' является перечислимым атрибутом. Когда используется оператор new, «конструктор» становится атрибутом, но его нельзя перечислить. Атрибут перечислим, если операция for-in «for (имя переменной в объекте)» возвращает имя атрибута.

Знайте, сколько параметров ожидает функция

function add_nums(num1, num2, num3 ){
    return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.

Знайте, сколько параметров получает функция

function add_many_nums(){
    return arguments.length;
}    
add_many_nums(2,1,122,12,21,89); //returns 6

Никогда не знал о первой части. Отлично!

mcjabberz 17.09.2009 23:48

Точно так же вы можете узнать, сколько аргументов ожидает функция с помощью function.length.

Xavi 27.07.2010 19:18

@Xavi, что является 1-й частью ответа

pramodc84 06.08.2010 07:49

Что ж, это не особенная функция, но очень полезная:

Показывает выбираемые и отформатированные предупреждения:

alert(prompt('',something.innerHTML ));

Это не всегда хорошая идея, но вы можете преобразовать большинство вещей с помощью кратких выражений. Важным моментом здесь является то, что не каждое значение в JavaScript является объектом, поэтому эти выражения будут успешными, если доступ к элементам не-объектов, таких как null и undefined, завершится ошибкой. В частности, будьте осторожны с typeof null == "object", но вы не можете использовать null.toString () или ("name" в null).

Преобразуйте что угодно в число:

+anything
Number(anything)

Преобразуйте что угодно в четырехбайтовое целое число без знака:

anything >>> 0

Преобразуйте что угодно в строку:

'' + anything
String(anything)

Преобразуйте что угодно в логическое значение:

!!anything
Boolean(anything)

Кроме того, использование имени типа без "new" по-разному ведет себя для String, Number и Boolean, возвращая примитивное число, строку или логическое значение, но с "new" они возвращают "упакованные" типы объектов, которые почти бесполезны.

Мой любимый трюк - использовать apply для выполнения обратного вызова метода объекта и поддержания правильной переменной this.

function MakeCallback(obj, method) {
    return function() {
        method.apply(obj, arguments);
    };
}

var SomeClass = function() { 
     this.a = 1;
};
SomeClass.prototype.addXToA = function(x) {
     this.a = this.a + x;
};

var myObj = new SomeClass();

brokenCallback = myObj.addXToA;
brokenCallback(1); // Won't work, wrong "this" variable
alert(myObj.a); // 1


var myCallback = MakeCallback(myObj, myObj.addXToA);
myCallback(1);  // Works as expected because of apply
alert(myObj.a); // 2

Хм, я не прочитал всю тему, хотя она для меня довольно интересна, но позвольте мне сделать небольшое пожертвование:

// forget the debug alerts
var alertToFirebugConsole = function() {
    if ( window.console && window.console.info ) {
        window.alert = console.info;
    }
}

В Chrome эта функция не работает, потому что log может вызываться только как экземпляр console. Это будет работать: window.alert = function(){console.info.apply(null,Array.prototype.slice.call‌​(arguments));}. Часть Array.prototype.slice.call необходима для совместимости со старыми браузерами, которые не могут обрабатывать объект arguments как параметр для apply.

Rob W 02.02.2012 16:01

функция может иметь методы.

Я использую этот шаблон отправки форм AJAX.

var fn = (function() {
        var ready = true;
        function fnX() {
            ready = false;
            // AJAX return function
            function Success() {
                ready = true;
            }
            Success();
            return "this is a test";
        }

        fnX.IsReady = function() {
            return ready;
        }
        return fnX;
    })();

    if (fn.IsReady()) {
        fn();
    }

Этот узор совсем не скрывается :)

Lyubomyr Shaydariv 17.12.2009 18:14

Считается, что JavaScript очень хорошо раскрывает весь свой объект, независимо от того, является ли его объект окна.

Поэтому, если я хочу переопределить предупреждение браузера с помощью всплывающего окна JQuery / YUI div, которое также принимает строку в качестве параметра, это можно сделать, просто используя следующий фрагмент.


function divPopup(str)
{
    //code to show the divPopup
}
window.alert = divPopup;

С этим изменением все вызовы alert () будут показывать хорошее новое всплывающее окно на основе div, а не конкретное предупреждение браузера.

Дзен замыканий

Другие люди упомянули закрытия. Но удивительно, как много людей знают о замыканиях, пишут код с использованием замыканий, но все еще имеют неправильное представление о том, что такое замыкания на самом деле. Некоторые люди путают первоклассные функции с замыканиями. Третьи видят в нем своего рода статическую переменную.

Для меня замыкание - это своего рода глобальная переменная 'частный'. Это своего рода переменная, которую некоторые функции считают глобальной, но не видят другие. Я знаю, что с описанием лежащего в основе механизма ничего не происходит, но именно так он себя чувствует и ведет себя именно так. Проиллюстрировать:

// Say you want three functions to share a single variable:

// Use a self-calling function to create scope:
(function(){

    var counter = 0; // this is the variable we want to share;

    // Declare global functions using function expressions:
    increment = function(){
        return ++counter;
    }
    decrement = function(){
        return --counter;
    }
    value = function(){
        return counter;
    }
})()

теперь три функции increment, decrement и value совместно используют переменную counter, при этом counter не является реальной глобальной переменной. Это истинная природа закрытия:

increment();
increment();
decrement();
alert(value()); // will output 1

Вышеупомянутое не совсем полезное использование замыканий. На самом деле, я бы сказал, что использование этого способа - антипаттерн. Но это полезно для понимания природы замыканий. Например, большинство людей попадают в ловушку, когда они пытаются сделать что-то вроде следующего:

for (var i=1;i<=10;i++) {
    document.getElementById('span'+i).onclick = function () {
        alert('this is span number '+i);
    }
}
// ALL spans will generate alert: this span is span number 10

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

Чтобы обойти это, вам нужно отделить * закрытие:

function makeClickHandler (j) {
    return function () {alert('this is span number '+j)};
}

for (var i=1;i<=10;i++) {
    document.getElementById('span'+i).onclick = makeClickHandler(i);
}
// this works because i is passed by reference 
// (or value in this case, since it is a number)
// instead of being captured by a closure

* примечание: я не знаю здесь правильной терминологии.

Это очень полезный пост, спасибо. Просто мелкая придирка. В цикле for должно быть i = 1, а не i = i. Кроме того, я не мог заставить работать обходной путь. Возможно, вы имели в виду это вместо этого: function makeClickHandler (j) {return function () {alert ('this is span number' + j); }; }

Steve 04.06.2010 20:51

@ Стив: Спасибо за обнаружение ошибок.

slebetman 07.06.2010 07:06

Я знаю, что опаздываю на вечеринку, но я просто не могу поверить, что о полезности оператора + не упоминалось, кроме «преобразования чего-либо в число». Может быть, вот насколько хорошо эта функция скрыта?

// Quick hex to dec conversion:
+"0xFF";              // -> 255

// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();

// Safer parsing than parseFloat()/parseInt()
parseInt("1,000");    // -> 1, not 1000
+"1,000";             // -> NaN, much better for testing user input
parseInt("010");      // -> 8, because of the octal literal prefix
+"010";               // -> 10, `Number()` doesn't parse octal literals 

// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null;                // -> 0;

// Boolean to integer
+true;                // -> 1;
+false;               // -> 0;

// Other useful tidbits:
+"1e10";              // -> 10000000000
+"1e-4";              // -> 0.0001
+"-12";               // -> -12

Конечно, вы можете сделать все это с помощью Number(), но оператор + намного красивее!

Вы также можете определить числовое возвращаемое значение для объекта, переопределив метод прототипа valueOf(). Любое преобразование чисел, выполненное для этого объекта, приведет не к NaN, а к возвращаемому значению метода valueOf():

var rnd = {
    "valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd;               // -> 442;
+rnd;               // -> 727;
+rnd;               // -> 718;

Вы можете сделать просто 0xFF и т. д., +"0xFF" не нужен.

nyuszika7h 14.01.2011 13:21

@ Nyuszika7H: вы как бы упускаете суть, которая заставляет другие примитивы и объекты числа к. Конечно, вы можете просто написать 0xFF, почти так же, как вы можете написать 1 вместо +true. Я предлагаю вам использовать +("0x"+somevar) в качестве альтернативы parseInt(somevar, 16), если хотите.

Andy E 14.01.2011 13:49

Универсальность JavaScript - переопределение функций по умолчанию


Вот код для переопределения функции window.alert с помощью Виджет диалога пользовательского интерфейса jQuery. Я сделал это как плагин jQuery. И вы можете прочитать об этом в моем блоге; altAlert, плагин jQuery для персонализированных предупреждающих сообщений..

jQuery.altAlert = function (options)  
{  
    var defaults = {  
        title: "Alert",  
        buttons: {  
            "Ok": function()  
            {  
                jQuery(this).dialog("close");  
            }  
        }  
    };  

    jQuery.extend(defaults, options);  

    delete defaults.autoOpen;  

    window.alert = function ()  
    {  
        jQuery("<div />", {
            html: arguments[0].replace(/\n/, "<br />")
        }).dialog(defaults);  
    };  
};

Практически никогда не бывает хорошей идеей ... но, безусловно, полезно знать. Я использую его только для исправления ужасного поведения parseInt по умолчанию (восьмеричное основание по умолчанию). Итак, чтобы десятичная дробь была по умолчанию: ___parseInt = parseInt; parseInt = function (str, base) { return ___parseInt(str, base || 10) };

adamJLev 21.06.2010 18:58

Кэширование возвращаемого значения простой автономной функции:

function isRunningLocally(){
    var runningLocally = ....; // Might be an expensive check, check whatever needs to be checked.

    return (isRunningLocally = function(){
        return runningLocally;
    })();
},

Дорогостоящая часть выполняется только при первом вызове, и после этого функция возвращает это значение. Конечно, это полезно только для функций, которые всегда возвращают одно и то же.

В функции вы можете вернуть саму функцию:

function showSomething(a){
   alert(a);
   return arguments.callee;
}

// Alerts: 'a', 'b', 'c'
showSomething('a')('b')('c');

// Or what about this:
(function (a){
   alert(a);
   return arguments.callee;
}​)('a')('b')('c');​​​​

Я не знаю, когда это может быть полезно, в любом случае, это довольно странно и весело:

var count = function(counter){
   alert(counter);
   if (counter < 10){
      return arguments.callee(counter+1);
   }
   return arguments.callee;
};

count(5)(9); // Will alert 5, 6, 7, 8, 9, 10 and 9, 10

На самом деле, похоже, что Фреймворк FAB для Node.js реализовал эту функцию; см., например, Эта тема.

Закрытие:

function f() { 
    var a; 
    function closureGet(){ return a; }
    function closureSet(val){ a=val;}
    return [closureGet,closureSet];
}

[closureGet,closureSet]=f(); 
closureSet(5);
alert(closureGet()); // gives 5

closureSet(15);
alert(closureGet()); // gives 15

Дело здесь не в так называемом деструктурирующем назначении ([c,d] = [1,3] эквивалентно c=1; d=3;), а в том факте, что вхождения a в closureGet и closureSet по-прежнему относятся к одной и той же переменной. Даже после того, как closureSet присвоил a новое значение!

Я считаю, что вы делаете с [closureGet,closureSet]=f();является назначение деструктуризации. Это не работает в nodejs (Google V8), но работает в smjs (Spidermonkey Mozilla).

kzh 23.02.2011 22:36

Вы правы, это деструктурирующее присваивание, но читайте внимательнее: я хотел сказать, что [a, b] = f () на самом деле интересно, но «закрытие» находится где-то в другом месте. Поскольку [a, b] = f (), когда вы видите его в первый раз, привлекает больше внимания, чем должно быть в этом примере.

wnrph 10.03.2011 13:42

Это скрытая функция jQuery, а не Javascript, но поскольку вопрос о "скрытых функциях jQuery" никогда не возникает ...

Вы можете определить свои собственные селекторы :something в jQuery:

$.extend($.expr[':'], {
  foo: function(node, index, args, stack) {
    // decide if selectors matches node, return true or false
  }
});

Для выбора с использованием :foo, такого как $('div.block:foo("bar,baz") span'), функция foo будет вызываться для всех узлов, которые соответствуют уже обработанной части селектора. Смысл аргументов:

  • node содержит текущий узел
  • index - это индекс узла в наборе узлов.
  • args - это массив, который полезен, если у селектора есть аргумент или несколько имен:
    • args[0] - это весь текст селектора (например, :foo("bar, baz"))
    • args[1] - это имя селектора (например, foo).
    • args[2] - это символ кавычки, используемый для обертывания аргумента. (например, " для :foo("bar, baz")) или пустая строка, если нет кавычек (:foo(bar, baz)) или undefined, если аргумента нет
    • args[3] - это аргумент, включая любые кавычки (например, "bar, baz") или undefined, если нет аргументов
  • stack - это набор узлов (массив, содержащий все узлы, которые совпадают в этой точке)

Функция должна вернуть true, если селектор совпадает, иначе false.

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

$.extend($.expr[':'], {
  matches: function(node, index, args, stack) {
    if (!args.re) { // args is a good place for caching
      var re = args[3];
      if (args[2]) { // get rid of quotes
        re = re.slice(1,-1);
      }
      var separator = re[0];
      var pos = re.lastIndexOf(separator);
      var modifiers = re.substr(pos+1);
      var code = re.substr(1, pos-1);
      args.re = new RegExp(code, modifiers);
    }
    return $(node).text().match(args.re);
  }
});

// find the answers on this page which contain /**/-style comments
$('.answer .post-text code:matches(!/\*[\s\S]*\*/!)');

Вы можете достичь аналогичного эффекта с версией обратного вызова .фильтр(), но пользовательские селекторы гораздо более гибкие и обычно более читабельные.

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

ken 02.06.2010 19:40

@kenb: проверено с 1.3.2 и 1.4.2. Содержимое args отличается от 1.2.6.

Tgr 06.06.2010 02:17
"поскольку никогда не будет вопроса о" скрытых возможностях jQuery "..." - believe me there will be...
gblazex 10.07.2010 14:55

Скрытые (или малоизвестные) возможности jQuery: stackoverflow.com/questions/121965/…

Ates Goral 19.08.2010 18:51

Когда вы пишете обратные вызовы, у вас много кода, который будет выглядеть так:

callback: function(){
  stuff(arg1,arg2);
}

Вы можете использовать приведенную ниже функцию, чтобы сделать ее несколько чище.

callback: _(stuff, arg1, arg2) 

Он использует менее известную функцию объекта Function JavaScript, apply.

Он также показывает другой символ, который вы можете использовать как имя функции: _.

function _(){
        var func;
        var args = new Array();
        for(var i = 0; i < arguments.length; i++){
                if ( i == 0){
                        func = arguments[i];
                } else {
                        args.push(arguments[i]);
                }
        }
        return function(){
                return func.apply(func, args);
        }
}

Существуют похожие реализации, в первую очередь метод Function.prototype.bind() в ECMAScript 5th Edition и библиотека PrototypeJS. С этим вы можете сделать stuff.bind(null, arg1, arg2);. См. Ответ Бобинса здесь.

Andy E 24.06.2010 18:41

Это действительно каррирование функции, поэтому я бы назвал функцию curry вместо _. Также в идеале карри должен быть методом Function.prototype.

adamJLev 26.06.2010 07:06

Не поддерживает использование из объектного контекста. Измените первый параметр, чтобы применить к this. А как насчет просто: function _() { var args = Array.prototype.slice.call(arguments); return function() { args.shift().apply(this,args); }; }

nicerobot 26.06.2010 14:55

@nicerobot Tnx, это получше. @ Бесконечность Это не каррирование. По крайней мере, в haskell это означает изменение типа функции <code> (a, b) -> c на a -> b -> c </code> <br/> См. Дополнительную информацию: haskell.org/haskellwiki/Currying С каррированием вы можете сделать например: <code> func (1,2,3) == func (1) (2,3) == func (1) (2) (3). </code> Существует множество реализаций каррирования в javascript. <br/> Это действительно похоже на привязку.

Edgar Klerks 29.06.2010 16:55

Это менее читаемая форма частичного приложения.

gblazex 10.07.2010 14:59

Другие вопросы по теме