我正在编写一个提供函数tablify(anything);
的JavaScript库,它可以将任何数组或对象表示为HTML表。
现在我正在尝试扩展Array和Object原型,以便像这样使用它:
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"
?(42).tablify();
,"string".tablify();
...)答案 0 :(得分:2)
为什么
typeof
始终返回"object"
?
因为在草率模式下,this
context总是应该是一个对象。当您调用函数或传递undefined或null时,您将获得全局对象,当您调用方法时,上下文将被转换为对象。
对tablify
方法使用strict mode,它会起作用!
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();,"字符串" .tablify(); ...)
不是真的。所有原始包装器都继承自Object.prototype
。
这些人的名字是什么"正常"对象?我该怎么称呼他们?
Just" objects"。或者"普通物体"如果你愿意(将它们与数组,内置函数,主机对象区分开来)。
答案 1 :(得分: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
}
}
// ...
}
您将无法判断是否隐式创建了盒装基元,但这可能对您的代码无论如何都无关紧要。