2015-02-03 3 views
1

Я пишу JavaScript-библиотеку, которая предлагает функцию tablify(anything);, которая может представлять любой массив или объект в виде таблицы HTML.Как правильно расширить Obect.prototype?

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

var arr = ["a", "b", "c"]; 
var obj = {"A": "a", "B": "b", "C": "c"}; 
arr.tablify(); 
obj.tablify(); 

Это мой подход:

Array.prototype.tablify = function() { 
    return tablify(this);  
} 
Object.defineProperty(Object.prototype, 'tablify', { 
    value: function() { 
     return tablify(this); 
    }, 
    writable:  true, 
    configurable: true, 
    enumerable: false 
}); 

Проблема в том, что все в JavaScript - это объект, и поэтому не только литералы, как {a: 1, b: 2}, могут быть преобразованы, но и все остальное.

Это будет не такое большое дело, так как мой tablify() может также иметь дело с примитивными типами, но когда я расширяю Object.prototype, typeof anything всегда возвращает "object" и я не могу различать типы больше:

function tablify(object) { 
    if (object instanceof Array) { 
     return ArrayToTable(object); 
    } 
    //This is always true if I extend Object.prototype: 
    if (typeof object === "object") { //only for "normal" objects like "{a: 1, b: 2, c: [],...}" 
     return ObjectToTable(object); 
    } 
    return PrimitiveToTable(object); //strings, numbers, functions, ... 
} 
  • Почему typeof всегда возвращается "object"?
  • Хорошо ли JS-API обеспечить такую ​​функциональность (расширение массивов/объектов с помощью .tablify(); ")?
  • Как можно различать «нормальные» объекты, числа, функции, ...?
  • Возможно ли продлить только «обычные» объекты? (forbid (42).tablify();, "string".tablify(); ...)
  • Какое название для этих «нормальных» объектов? Как мне их называть?
+1

Функция, которая создает HTML из объекта, не похожа на то, что вы обычно хотели бы добавить в прототип собственных объектов? – adeneo

+0

Неверно, что «все в JavaScript - это объект». Строки, числа и булевы не являются объектами. Они * действуют как * объекты в ситуациях, когда они призваны сделать это, потому что язык неявно преобразует их в соответствующий тип объекта. – Pointy

+0

@Pointy Когда я использую свой код, '42.tablify();', '" string ".tablify();', 'func.tablify();' тоже работают, хотя я только расширяю Object.prototype. И 'typeof' возвращает' 'object" 'также ... – maja

ответ

2

Почему typeof всегда возвращается "object"?

Потому что в неаккуратном режиме всегда должен быть объект this context. Когда вы вызываете функцию или передаете неопределенный или нулевой, вы получаете глобальный объект, когда вы вызываете метод, контекст будет передан объекту.

Используйте strict mode для вашего tablify и он будет работать!

Хорошо ли для JS-API обеспечить такую ​​функциональность (расширение массивов/объектов с помощью .tablify();)?

Yes.No.. Многие люди будут хмуриться, чтобы использовать ваш скрипт, когда вы хотите поделиться им. См. Why is extending native objects a bad practice? для подробного обсуждения.

По крайней мере, у вас есть properly used non-enumerable properties - но я бы порекомендовал их использовать на Array.prototype, слишком много людей злоупотребляют for in перечислениями.

Как можно различать «нормальные» объекты, числа, функции, ...?

typeof похоже прекрасный.

Возможно ли продлить только «нормальные» объекты? (запретить (42) .tablify(); "string" .tablify(); ...)

Не совсем. Все примитивные обертки наследуются от Object.prototype.

Какое название для этих «нормальных» объектов? Как мне их называть?

Просто «объекты». Или «простые объекты», если хотите (отличает их от массивов, встроенных объектов, объектов хоста).

+0

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

1

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

"foo".tablify(); 

В этом вызове, перед тем функция вызывается, строка примитивная преобразуется в экземпляр String. Другими словами, он ведет себя так, как если бы вы написали:

new String("foo").tablify(); 

Я полагаю, вы можете использовать функцию Object.prototype.toString сказать разницу:

function tablify(obj) { 
    if (typeof obj === "object") { 
     var sig = {}.toString.call(obj); 
     if (/ (String|Number|Boolean)\]$/.test(sig)) { 
     // treat as primitive 
     } 
     else { 
     // object 
     } 
    } 
    // ... 
} 

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

Смежные вопросы