Как стать автором
Обновить

Комментарии 150

Для получения того самого типа — внутреннего свойства [[Class]] можно использовать особенность работы Object.prototype.toString и написать вот такой код
var allowedTypes = ["Object", "Undefined", "Null", "Boolean", "Number", "String"];
/**
 * @param {Mixed} x
 *
 * @return {String}
 */
function Type(x) {
    var type = Object.prototype.toString.call(x).replace(/^\[object\s|\]$/g, '');
    return ~allowedTypes.indexOf(type) && type || "Object";
}

Еще есть интересная особенность оператора new — он не может вызвать функцию у которой нет свойства prototype — все нативные функции и функции () => из ES6
new Array.prototype.slice
// TypeError: Array.prototype.slice is not a constructor

// VS

var A = function () {};

Object.getOwnPropertyDescriptor(A, "prototype");
// {"configurable":false,"enumerable":false,"value":{},"writable":true}

// Убить prototype у пользовательской функции нельзя
delete A.prototype; // false - "configurable":false

new A(); // ok
Спасибо за пример, таким способом действительно можно получить тип объекта, но, как я и говорил вышел, не вижу этому применения
с typeof и [[Class]] вообще интересного много: blgo.ru/t/jstypes/table/
По второму уточню: не в отсутствии prototype дело, а в отсутствии внутреннего метода [[Construct]]:
Array.prototype.slice.prototype={}
new Array.prototype.slice // TypeError: function slice() { [native code] } is not a constructor
По поводу работы с дробными числами. Вместо писать велосипед с «function sum...», я бы рекомендовал Вам воспользоваться toFixed
Вот Вам явный пример:
console.log((0.1+0.22 -0.2+ 0.3 + 0.7).toFixed(2));
В функции автора в каких-то случаях даже есть смысл, ибо toFixed: String
Math.PI.toFixed(2); // "3.14"
1e+22.toFixed(2) // "1e+22"
Какая хорошая статья, спасибо!
И правда, в этом месяце на Хабре ещё не было описания подводных камней JS.
Я с нетерпением жду ремейк «наследование в js» или «подробное описание prototype».
Я с нетерпением жду ремейк «наследование в js» или «подробное описание prototype».

Та да, уже недели две не было. Я уж и забывать начал.
И ни слова про неугомонный this…
Использовать паттерн immediately-invoked function:

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

С таким же успехом кто-то может перезаписать все свойства документа, jQuery, и методы массивов. После этого он может облить ваш компьютер бензином и поджечь его.
Нелогично то, что кто-то может это сделать с undefined, но не может, например, с NaN. undefined так же могло быть not-writable свойством — это было бы логично.

А jQuery пока не является нативным объектом JS, так что не будем о нём в этой статье ;)
void 0 и будет вам счастье
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Просто оставлю это здесь
NodeJS 10.13.0
"use strict";

let undefined = "test";
let a;
console.log(a == undefined);
console.log(undefined);
-> false
-> test
НЛО прилетело и опубликовало эту надпись здесь
Вот Вы иронизируете, а у меня когда-то получилось сделать это непреднамеренно.
хорошо бы узнать как автор сделает это в глобальном контексте. в локальном это возможно — но это тогда будет Ваша проблема, а не глобальная.
В js чем меньше знаешь, тем лучше спишь:
только что сделал
var x = 1000/0;
console.log(typeof x); // number
console.log(typeof 1000/0) // NaN

var x = 1000/0;// — это бесконечность, Infinity, тип Number.
console.log(typeof x); // number, всё верно
console.log(typeof 1000/0) // NaN
//Теперь поставим скобки правильно:
console.log((typeof 1000)/0); //NaN
console.log(typeof(1000/0)); //Number

Всё логично:)
О спасибо. Как-то казалось оператор деления будет иметь приоритет перед typeof. Тогда да логично.
typeof унарный оператор, он выполняется раньше.
Непонятно, в чём смысл минусов. Если вы спецификацию не читаете, это ваше дело.
А когда 1000/0 стал безконечностью?
1000/0 как раз таки неопределенность, поскольку не существует числа, которое при умножении на 0 даст 1000. И бесконечность при умножении на 0 не даст 1000.
НЛО прилетело и опубликовало эту надпись здесь
В комментарии KELiON «это бесконечность, Infinity, тип Number.»
Кроме того, даже если бесконечность не число — с чего вдруг бесконечность умножить на 0 будет 1000?
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Я ведь делю 1000 на 0. Это числа?
НЛО прилетело и опубликовало эту надпись здесь
Продолжайте строить из себя умника, не уважающего других. Вы уже ОЧЕНЬ близко к цели.
1000/0 — это бесконечность, если исходить из математики. Т.к. если делить 1000 на бесконечно малое число, то получим бесконечность. Грубо говоря 0 это вообще ничего не существует, всегда хоть что то да есть, даже что то бесконечно малое. Вот и выходит, что 1000 / (1/10000000000000) получается бесконечно большое число.

P.S. во я завернул)
Да не правда это. Ноль — это строго ноль. 1/10000000000000 — не ноль, хоть тысячу раз в квадрат возведите. Нужно понимать, что есть разница между нулем, и бесконечно малым.
Вы немного путаете. Бесконечности будет равен предел выражения 1000/x, где x приближается к нулю. В математике результат деления на 0 же неопределен.
По хорошему, при выходе за границы применимости следовало бы бросать исключение.
Она-то обратима, вот только делить на ноль нельзя. Разработчики ECMAScript (и не одни они) это решили весьма интересным (и часто очень удобным) способом.
На 0 делить нельзя только в элементарной алгебре. Я с первого курса матнализа помню, что:
  • 0/0 — неопределенность,
  • любое положительное число делить на 0 = +∞
  • любое отрицательное число число делить на 0 = -∞
  • ∞/∞ — неопределенность
  • ∞*∞=∞


В решении JS нет ничего интересного, если заменить неопределенность на NaN, а бесконечность на Infinity. Операции с ними не противоречат матанализу. Единственное замечание — в JS нет разницы между +0 и -0, но есть Infinity и -Infinity.
любое положительное число делить на положительное число СТРЕМЯЩЕЕСЯ К НУЛЮ равно числу, СТРЕМЯЩЕМУСЯ К БЕСКОНЕЧНОСТИ.
Не вижу противоречия: 0 стремится к 0, а ∞ стремится к ∞
Мы говорим о разных вещах. НА НОЛЬ ДЕЛИТЬ НЕЛЬЗЯ, никак.

На курсе матана вы проходили ПЕРЕМЕННЫЕ стремящиеся к нулю/бесконечности.

5 / 0 — бред, это только для упрощения пишут, например, 0/0. На деле подразумевается x/y при x, y -> 0.

— Единственное замечание — в JS нет разницы между +0 и -0

Глупости:
console.log( 1/(-0) )
В ECMAScript в The Abstract Equality Comparison Algorithm отдельным пунктом прописывается -0 == +0
Деление же на 0 со знаком Applying the / Operator опирается на IEEE 754
Division of a non-zero finite value by a zero results in a signed infinity. The sign is determined by the rule already stated above.

PS Я прекрасно понимаю ваши чувства и то, что для получения бесконечности надо поделить на бесконечно малую величину, а не ноль. Вы так же «поймите и простите» ECMAScript :)
5/0 — это не бред. это элемент кольца замыкание®, а именно бесконечность.
Можно подробнее? Хотя бы, куда копать?
вообще 5/0 = 5*(0)^(-1) = 5*Infinity = Infinity (при этом обратного к Infiniti не существует)
/ — это ведь просто значёк для упрощения записи умножения на обратный эллемент
А ещё это алгебра и теория чисел, а не матан
Просто меня смущает то, что вы выше написали… Разве можно говорить, что бесконечность есть обратный элемент относительно операции умножения для нуля? Вроде в определении поля как раз у него нет обратного.

Или я путаю понятия?
Если вы смотрите на это как на поле, то вы правы, но можно смотреть как на кольцо. Тогда можно к R добавить два элемента +-бесконечность и доопределить нужные операции. При этом довольно формально можно определить операцию деления и обратные для некоторых элементов (кольцо не требует их существования).

А в поле R всё верно R* = R\{0} — множество обратимых элементов.
Давайте решим, что на ноль делить нельзя, т.к. это абсурдно с логической точки зрения? :) Чтобы не думать о вариантах математических объектов.
А давайте решим, что деление на ноль даёт бесконечность, чтобы не продолжать этот бессмысленный спор.
В питоне 1/0 — ошибка; В JS 1/0 — infinity; Каждый язык хорош по своему — давайте расходиться, а то тред уже плющит :)
Ну так я о том же.
можно согласиться, что 5/0 — это формальность. делить — это тоже формальность =)
можно только умножать и брать обратный. вы можете работать с кольцом R U {+-Infinity, NaN} и определить все правила умножения — это просто. А потом формально доопределить обратные элементы для того, чтобы «делить». В общем-то так и делают все ЯП.

И ничего тут абсурдного нет, так ведь можно сказать что комплексные числа тоже абсурд с логической точки зрения =)
0 не стремится к 0, 0 достиг нуля.
1000/0 - Infinity, 0/0 - NaN, NaN !== NaN Это все IEEE 754
Ну наконец-то. Читал эту ветку и ужасался :) Действительно, достаточно просто сказать, что реализация Number соответствует стандарту IEEE 754 для чисел удвоенной точности. Откуда следует, в частности, что:
console.log((1e+16 + 1)  == 1e+16); //true
console.log((1e+16 + 100)  == 1e+16); //false

и прочие «забавные» вещи.
И что смущает?
Читаем Operator precedence на mdn
image
НЛО прилетело и опубликовало эту надпись здесь
нет — это проблема при оптимизации арифметеки. Я с такой проблемой столкнулся в mongoDB — там тоже пришлось делать враппер над представлениями чисел.
Почему нет? Это типичная ошибка огругления float. Вот почему к нему кастуется — другой вопрос.
Для получения реального «undefined»-значения можно использовать оператор void (кстати, я не знаю другого применения этому оператору):

Помимо
void 0 == undefined
void можно использовать для красивого замыкания без лишних скобок:
void function(global) {
    //closure
} (this);
Я часто замыкаю
~function() {

}

Но тут реально дело вкуса, как нравится.
НЛО прилетело и опубликовало эту надпись здесь
А еще из-за особенностей внутреннего представления JavaScript объектов V8 и Оперы в хэше сперва идут числа в порядке убывания, а потом стоковые элементы в порядке добавления. Притом, что при использовании ключа большего, чем 1e+9 ключи в них воспринимаются как строки и идут в порядке добавления.

var a = {};

a['pewpew'] = 1;
a['ololo'] = 2;
a[1] = 3;
a[0] = 4;
a[1e+9] = 5;
a[1e+10] = 6;

JSON.stringify(a);

JSON.stringify(a);
// V8 (Chrome, Node,js) и Опера
// {"0":4,"1":3,"1000000000":5,"pewpew":1,"ololo":2,"10000000000":6}

// FireFox и Safari
// {"pewpew":1,"ololo":2,"1":3,"0":4,"1000000000":5,"10000000000":6}

Мораль: не мешайте стоковые ключи с числовыми. Не опирайтесь на порядок добавления элементов в «Хэш».
Не знал о таких тонкостях, но почти во всех языках, включая js, хеши (в данном случае объекты) не гарантируют определенного порядка прохода по ключам, работая с ключами, как с неупорядоченным множеством.
В настоящее время во всех браузерах (и в Node.js также) ключи хэша выводятся в том порядке, в котором они были вставлены в объект, за исключением поведения Хрома и Оперы с числовыми ключами. Поэтому для получения ключей в порядке их поступления достаточно следовать двум простым правилам:

  • Имя ключа не должно начинаться с цифры (или со знака «+» или «−» с последующею цифрою).
     
  • Один и тот же ключ не должен добавляться в один и тот же объект дважды.

(Правила взяты из README-файла от библиотеки jParser.)
С Ваших слов очень интересно получается. И Chrome и Node.js используют V8 в качестве js-движка, но при этом работают с хэшами по-разному.
Я тоже сначала так прочёл, но с третьего раза таки понял товарища Mithgol. Они оба работают одинаково. И надо следовать двум правилам. Но написано странно, согласен.
1) не забывайте про версии
2) не забывайте про оптмизации
а еще запустите node --v8-options ;)
Сижу и тихо млею. Неужели кто-то до сих пор использует числа с плавающей точкой для работы с деньгами?

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

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

В Англии до 1971 использовалась более сложная схема 1 фунт = 20 шиллингам, шиллинг = 12 пенсов. Соответственно должна составляться таблица последовательных преобразований из пенсов в фунты, так как цена могла быть отображена в виде 1 фунт, 2 шиллинга, 4 пенса.

Некоторые страны имеют соотношение 1 к 1000, например ливийский динар состоит из 1000 дирхамов, а на Мадагаскаре и в Мавритании соотношение 1 к 5. В Японии нет деления на более мелкие валюты, там все операции производятся в иенах.

Вы все еще используете вещественные числа для рассчета валют? Тогда рефакторинг ждет вас! :)
ну давайте положим 1 рубль на счет и начнем ежедневно добавлять сотые доли процента %)
Поэтому в банках добавляют еще две цифры запаса (то есть считают всё в сотых долях копеек), а выводят с округлением до целых копеек.
в банках используют особый денежный формат 21:5 — т.е. 21 цифра для целых частей, и 5 для дробных, как правило более 4 знаков после запятой при делении валюты или начисления % не используется, а последний 5 разряд после запятой используйте как корректирующий для случаев проблем округления, также дополнительно используется расширенные правила округления (чаще по IEEE, но иногда и по локальным стандартам — для РФ — стандарт ЦБ РФ и МинФин РФ)
Во!
А то ходють тут любители рефакторинга и махают своим единственно правильным!
Я не понял к чему Ваш комментарий :) но обычно используют так, конечно Я не могу гарантировать что ВСЕ системы работают таким образом — но по стандартам обычно принято таким образом, а фин. секторе не принято их нарушать.
Есть один нюанс, для всех операций используется decimal floating point арифметика, в которой число хранится в целочисленке.
ну вот есть у меня на счете 99 рублей и 99.98 копеек, выводить будет 100 рубликов, а снять их не даст, ибо с нужной точностью их нету
вообще-то нет — обычно запрещено округлять подобным образом. в случае «грязного» округления дробная часть отбрасывается вовсе и Вам тогда отобразят 99, ОДНАКО «грязное» округление уже нигде не используется, если только за исключением каких либо аггрегированных показателей в регистрах накопителях для целей внутреннего учета.
Приходится :)
Например, пользователь хочет перевести 36.3 USD на счет. Конечно, мы переводим эту сумму в центы, но в итоге получится float :)
36.3 * 100 = 3629.9999999999995
Предпочитаю Math.round в таких случаях
Еще, на всякий случай напомню одну особенность которую данный программист не учел:
Хотя умножение/деление на 10 решает проблему
>>> (0.7*10 + 0.1*10)/10
0.8
но вот незадача
>>> (0.07*10 + 0.02*10)/10
0.09000000000000001

Не нужно всегда думать что у вас числа будут только с десятками, даже одна копейка при таких арифметических действиях может выйти в серьезную проблему.
Это проблема не яваскрипта, а особенность работы компьютера с float. floating-point-gui.de/
точнее реализации в JS движках.
я про javascript ничего не говорил, я говорил про умножение на 10, это вообще не выход из положения, округлять надо а не страдать фигней
Кстати если разобраться то {} + [] отработает как блок кода и унарный плюс к массиву, а +[] === 0
Дополню:

  • При арифметических null приводится к нулю. null+1===1 Это не то поведение, которого ждёшь от null после СУБД. Зачем нужен такой null, непонятно — вместо него кажется правильным использовать undefined.
  • Начиная с JavaScript 1.8.5 (Firefox 4), undefined неперезаписываемое, согласно спецификации ECMAScript 5.
Кто может объяснить это? Один раз увидел, и с тех пор меня мучают ночные кошмары.

[] + [] = ""
[] + {} = "[object Object]"
{} + [] = 0
{} + {} = NaN
в статье не указан тот факт что движок V8 использует свой парсер и правила обработки операций над объектами.
Можно автору написать, чтобы дополнил.
автора оригинала Я не знаю к сожалению, а т.к. статья перевод — то думаю не нужно вносить правки (от себя).
//(1) [] + [] = ""
[].toString() // -> "" - Array не является нативным типом - поэтому сериализуется черезе .toString()
"" + "" // -> "" - сложение двух пустых строк равняется пустой строке

//(2) [] + {} = "[object Object]"
{}.toString() // -> "[object Object]" - {} является упрощенной формой new Object() 
[].toString() // -> "" - Array не является нативным типом - поэтому сериализуется через .toString()
"" + {} // -> "[object Object]" - сложение строки с объектом невозможно, результат Object

//(3) {} + [] = 0 и {} + {} = NaN
// тут есть одна особенность - результат зависит от движка
// Mozilla Rhino, Opera Presto/2.12.388, Microsoft Trident
{} + [] = 0.0 // действует правило конвертации пустых объектов (нативный тип + ненативный тип), массивы конвертируются в "", объект в 0. 
// тоже самое будет если
0 /*{}*/ + "" /*[]*/ = 0.0
{} + {} = NaN // попытка приведения объекта к типу "number" приводит к NaN - что по сумме дает NaN т.к. оба аргумента неприводимы в тип доступный для складывания
// Google V8 
{} + [] = "[object Object]"
{} + {} = "[object Object][object Object]"

НЛО прилетело и опубликовало эту надпись здесь
Посмотрите внимательно — ЗАВИСИТ от движка, разные движки по разному собирают внутреннее представление.
Я поэтому и описал 2 вариант — (1) V8 (2) Все остальные движке (Rhino, Presto, Trident)
НЛО прилетело и опубликовало эту надпись здесь
вообще-то Вы своим комментов наоборот это подтвердили :)
значение пустой строки как раз "" а не 0
// Rhino
{} + 1 = 1.0 // {} = 0.0
[] + 1 = 1 // [] = 0
НЛО прилетело и опубликовало эту надпись здесь
1) установите JDK
2) запустите там jrunscript
3) ???
4) PROFIT!!!
НЛО прилетело и опубликовало эту надпись здесь
// Rhino
+[] = 0
+{} = NaN
+"" = 0.0
НЛО прилетело и опубликовало эту надпись здесь
Нужно будет проверить в багтрекере Mozilla
НЛО прилетело и опубликовало эту надпись здесь
Я тестирую в node.js 0.8.9 (Linux) + node.js 0.8.7 (Windows) если что :) результаты именно такие.
в этой-же статье не учтено что движок V8 по другому парсит и обрабатывает код — конкретный пример Я привел выше.
P.S. а т.к. V8 относится и к Chrome и node.js — то автоматически к этому применимо. А вот у Safari используется модифицированный WebKit с другим движком.
{}+{}
В этом примере нет операции сложения. Это пустой блок и «плюс пустой объект» (как +2). Приведение пустого объекта к числу дает NaN.
ОК. А теперь упакуйте этот код в функцию и удивитесь ;)
Как именно?
(function() { return ( {} + [] ); })(); // [object Object]
(function() { return ( {} + {} ); })(); // [object Object][object Object]
return требует вычисление выражения. А в вышеописанном случае это просто token, который парсер принимает как есть.
ОК, Вы часто используете выражения описанные выше в Global Scope?
Я вообще такие выражения не использую. Но они носят чисто академический интерес.
Углубльсю немного в один из примеров.
Завист все от того места, куда этот экспрешн будет вставлен:
{} + ""; // 0
"" + {}; // "[object Object]"

Дело в том, что парсер воспринимает в 1-м примере скобки как пустой блок
вот так:
{;} 
+""; // 0
Во втором случае скобки — литерал объекта т.к. стейтмент плюс еще не закрыт.

То как воспринял данный код браузер можно понять, используя вот такой хак Function.prototype.toString();
(function(){{}+""})+"";
/*FF распарсил эту функцию вот так:
"function () {
    + "";
}"*/

/*Опера
"function() {
	{}
	+""
}"
*/

/*Хром
"function (){{}+""}"
*/

/*Сафари
"function () {{}+"";}
*/

А вот в этом случае оба блоки
{2+1;} + ""; // 0 - аналогично первому примеру
"" + {2+1;}; // Syntax error - пытается распарсить блок {2+1;} как литерал объекта

Если поставить наше самое первое выражение в стейтмент (реальное условие), то парсер будет думать, что фигурные скобки это литерал объекта из-за того, что стейтмет var еще не закрыт.
var a = {} + ""; // "[object Object]"

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

1.
оператор typeof используется довольно часто, поэтому лучше запомнить

Так как в JS, всё — объекты, лучше использовать более универсальный и логичный оператор instanceof. Им можно сверять типы любых объектов, например:
[] instanceof Array // true

Для проверки на нулевые значения, лучше использовать прямые сравнения, вроде
var === undefined


2.
Значение Infinity также имеет свои особенности:
Infinity + 1 == Infinity // true

Существует как +Infinity, так и -Infinity.

3.
Если запрашивать не объявленную переменную, то будет ошибка.
someVar; // error

Но если запрашивать туже переменную, через свойство объекта, то ошибки не будет.
window.someVar; // undefined

В JS, всё — свойство какого либо объекта.
Из-за особенностей работы оператора instanceof такая операция не пройдет, если вы будете проверять инстанс у массива во фрейме.
frame.contentWindow.var instanceof Array;

В этом случае используют особенность алгоритма Object.prototype.toString и получают «Тип» из [[Class]]

var === undefined

Это требование зависит как от кодстайла так и от алгоритма. Однозначано так говорить не хорошо.

В JS, всё — свойство какого либо объекта.
Вы про какие объекты сейчас говорите? Даю код исключительно для уточнения ваших слов.
function a() {
    var a; // свойство какого объекта переменная а?
}

Если запрашивать / Но если запрашивать
тут важно понимание операций Identifier Resolution и Property Accessors, а не их последствий :)
Вообще с введением Harmony разницы особой не будет, можно будет поставить прокси на GLOBAL область и ловить исключения несуществующей переменной в рантайме.
В JS действительно — ВСЕ свойства какого либо объекта, просто не ко всем контекстам есть доступ — например к локальным переменным + без сохранения контекста видимости код с функцией a действительно будет «волшебными грибами».
От себя добавлю — сделал библиотеку typeis(«typename»)(object) — это позволяет ВСЕГДА гарантированно проверять тип объекта без лишних проблем, в т.ч. и проблема несуществующих переменных решает :)
ловить исключения несуществующей переменной в рантайме
Ошибку лучше предотвратить, чем обработать исключение.

можно будет поставить прокси на GLOBAL область
Вы уверены в понимании идеи Proxy? :) Пример, пожалуйста (Proxy сейчас есть в Firefox).

В JS действительно ВСЕ свойства какого либо объекта
Это я прекрасно понимаю. Хотел уточнить знание автора комента выше, а тут вы :)

сделал библиотеку typeis(«typename»)(object)
Из многолетнего опыта — мне всегда хватало typeof и Array.isArray. Зря вы так GC мучаете своими «красивыми» функциональными интерфейсами :)
typeis("typename")(object);

type(object) === "typename"; // faster - true, better IMO
1) ОК, если Вы такой маг и все пишите сразу отлично — то спорить не буду, мне лично проще вести трассировку подобным образом
2) идея Proxy это расширенный полиморфизм и метапрограммирование
3) сорри, не распознал сарказма
4) GC не не жалко, можно и вручную собрать — в моем вариант просто функционал шире, т.к. он позволяет верифицировать ОЧЕНЬ много custom типов — например Country (проверка страны по ISO), время, составные типы по паттернам и т.д. — также это позволяет ввести НЕнативный тип и использовать его 1 строкой с расширенной валидацией, теоретически можно и перегрузить typeof/type — но как мне кажется лучше не стоит. (например перегрузки и расширения свойств Object плохо совместимы с ранними версиями express.js)
P.S. Я например проверяю размеры typeis("<10KB")(number) или например так typeis("<MAX_FILE_SIZE")(number) — так весьма удобно ИМХО.
Я вашу позицию понял, спасибо за дополнение :)
Вообще то подумал про window, если говорить про «всё — свойство какого либо объекта». Хотя window и является сам свойством window, но не считаю что такой трюк равняет window с другими объектами.

По сути, должен быть один корневой элемент, и от этого не уйти. Даже строя кольцо из указателей, нужно помнить что начинается его строительство с одного элемента. Первый же созданный указатель на этот элемент из вне JS среды и является переменной не являющейся свойством какого либо объекта.
Хотя window может и неудачный пример, но тот или иной базовый элемент всё равно должен быть.
Код о Harmony Proxy и Identifier Resolution.
var windowDescriptor = Object.getOwnPropertyDescriptor(this, 'window');
// {"configurable":false,"enumerable":true,"value":window,"writable":false}

this.window = Proxy.create({}); // (А) "writable":false - ничего не получится

window.__noSuchMethod__ = function () {
    return function () {};
}

window.b(); // OK __noSuchMethod__ тут сработает

b(); // (B)  ReferenceError: b is not defined
Я работаю с node.js и тут можно использовать циклическую переменную GLOBAL — например переопределив ее так
(function(){ GLOBAL = Proxy.create({}); })();
Попробовать, к сожалению не могу.
» node -v
v0.8.8
» node --harmony_proxies
> GLOBAL = Proxy.create({get: console.log.bind(console)});

util.js:120
  var ctx = {
  ^
RangeError: Maximum call stack size exceeded


Но даже если мы перепишем GLOBAL на проксю, то от Identifier Resolution это не поможет.
» node
> GLOBAL = {a: 1};
{ a: 1 }
> a;
ReferenceError: a is not defined
    at repl:1:1
    at REPLServer.self.eval (repl.js:111:21)
    at rli.on.e (repl.js:260:20)
    at REPLServer.self.eval (repl.js:118:5)
    at Interface.<anonymous> (repl.js:250:12)
    at Interface.EventEmitter.emit (events.js:88:17)
    at Interface._onLine (readline.js:199:10)
    at Interface._line (readline.js:517:8)
    at Interface._ttyWrite (readline.js:735:14)
    at ReadStream.onkeypress (readline.js:98:10)
> 

Вобщем проксю не подмешать без патчинга ноды.
1) ЕСТЕСТВЕННО
console.log.toString() // 'function () {\n  process.stdout.write(util.format.apply(this, arguments) + \'\\n\');\n}' где process ссылается на GLOBAL

Для корректной перегрузки GLOBAL Вам нужно сделать 3 действия:
1) скопировать оригинальный инстанц GLOBAL в замыкание
2) создать Harmony Proxy Handler с реализацией ВСЕХ перегружаемых методов
3) передать в качестве опционального аргумента оригинальный инстанц GLOBAL из замыкания
только после этого у Вас не будет циклического переполнения стэка, и вообще Раэйн сказал что хочет все что можно переписать на JS из ядра node.js поэтому все функции ядра viсe-versa являются высокоуровневыми абстракциями. (например тот-же process.nextTick) ;)

Вообще-то нет, и если уже на то пошло — то не ноды, а движка V8, т.к. политика Joyent — не вносить патчи в V8, даже если кто-то вносит такой коммит — то его не принимают, и отправляют его на googlegroup чтобы был патч для основной ветки V8 на офф. сайте — при условии что это критический баг.
Проблему то мы не решили. У нас до сих пор `ReferenceError: a is not defined`
кстати по поводу
GLOBAL = {a: 1} 

было глупо т.к.
typeof(GLOBAL) // "[object global]" 

это особый тип и его нельзя заменять — можно только оборачивать через Proxy

например:
this.GLOBAL["a"] = 1 // 1
a // 1
Ну понятное же дело, что global :) Мы же сейчас говорим об подмене GLOBAL проксей — те попытке подменить/пропатчить объект на который ссылается GLOBAL.

По старой спеке первый параметр прокси target — это просто хранилище полей для прокси. Прокся его не пропатчивает и при работе с ним напрямую ничего не меняется. В новой все вроде бы так и осталось.

Show me the code ;-) пока я не верю в возможность влияния прокси на Identifier Resolution
в этом случае суперглобальные объекты будут обрабатыватся через Harmony Proxy handler
Интересно. instanceof только с кроссфреймовыми запросами себя так ведёт, или ещё в каких то ситуациях? Это баг реализации или это следует из стандарта?

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

Это требование зависит как от кодстайла так и от алгоритма. Однозначано так говорить не хорошо.
Не настаиваю, на том что это лучший вариант, это лишь дополнение к instanceof для проверки пустых типов. Хотя в конечном итоге всё сводится к кодстаилу и конкретной ситуации.

Вы про какие объекты сейчас говорите?
Да, похоже преувеличил, имея в виду общий случай, в которой дело имеется либо со свойствами объекта «this.var», либо с локальными переменными, объявленными и используемыми в пределах одного экрана, когда нет необходимости помнить была ли переменная объявлена. Реальный случай, когда действительно может остро встать проблема ошибок из-за не объявленных переменных — это десяти экранные функции со множеством переменных, или глобальная область определения, в которой можно воспользоваться «window.var».

тут важно понимание операций Identifier Resolution и Property Accessors, а не их последствий :)
Теория и практика — две части целого.
Это баг реализации или это следует из стандарта?
Это фича. instanceof использует цепочку прототипов, которая в разых фреймах разная. «Адреса» объектов разные, а функционал одинаковый.

Необходимость кроссфреймовых JS запросов очень редка
Не спорю. Лучше вообще использовать Array.isArray ;-)
Array.isArray в ИЕ с 9-й версии

если уж совсем кроссбраузерно, то наверное как-то так будет лучше:
toString.call(a) == "[object Array]"
Интересно. instanceof только с кроссфреймовыми запросами себя так ведёт, или ещё в каких то ситуациях?

Если писать UserJS плагины, то тоже такая фигня. В хроме есть window.Array и unsafeWindow.Array. И внутри приложения используется именно второе. То есть если вы хотите написать плагин — вам придётся использовать unsafeWindow.Array(1,2,3) вместо [1,2,3].
www.destroyallsoftware.com/talks/wat
Советую посмотреть, в этой короткометражке вы узнаете чему равно
{} + {}
{} + []
[] + {}
[] + []

и прочие радости яваскрипта :)
НЛО прилетело и опубликовало эту надпись здесь
Увы, не осилил все комменты, так что пусть это просто полежит здесь.
А зачем плюсовать объекты?
Этот вопрос я каждый раз задаю себе, когда вижу очередную ссылку на видео про «WAT» :)
(function(){
        var uscope = window, //window['utils'] = (window['utils']?window['utils'] : {}) ,//
            types = "Boolean Number String Function Array Date RegExp Object".split(" "),
            is = function (type, obj) {
                var clas = Object.prototype.toString.call(obj).slice(8, -1);
                return obj !== undefined && obj !== null && clas === type;
            };
        for(var i=0;i<types.length;i++)
            uscope['is'+types[i]] = (function( type ){
                return function( obj ){return is( type, obj )};
            }( types[i] ));
    }());

и получаем методы:
isBoolean
isNumber
isString
isFunction
isArray
isDate
isRegExp
isObject

если желаем — то в window.utils…
одна беда — при разработке использовать не удобно, среда их «не знает», т.к. они генерятся в runtime
За разъяснениями по таким вещам ->хорошо ходить на MDN. И стандарты упоминают, и совместимость, не только со своими продуктавми
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации