警告:创建对本机对象和/或属性的扩展被视为错误形式,并且必然会导致问题。如果您的代码不是仅供您使用,或者您不知道如何正确使用它,请不要使用此
我知道您可以使用Object
,String
,Number
,Boolean
等来定义方法,如下所示:
String.prototype.myFunction = function(){return this;} //only works on strings.
但我需要做的是在任何值上使用它,并访问函数中的值。
我用Google搜索,看了here,但找不到合适的东西。
2015年2月18日编辑:如果我使用Object.prototype
,是否有任何解决方法可以将此作为任何对象的属性?
每个请求,这是用于isString()
function isString(ins) {
return typeof ins === "string";
}
根据几个答案,我提出了一些由它引起的代码和错误。
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
答案 0 :(得分:14)
“点运算符函数”称为方法。在JavaScript中创建可以处理任何数据类型的方法的最简洁方法是创建包装器。例如:
var Wrapper = defclass({
constructor: function (value) {
this.value = value;
},
isString: function () {
return typeof this.value === "string";
},
describe: function () {
if (this.isString()) {
alert('"' + this.value + '" is a string.');
} else {
alert(this.value + " is not a string.");
}
}
});
var n = new Wrapper(Math.PI);
var s = new Wrapper("Hello World!");
n.describe(); // 3.141592653589793 is not a string.
s.describe(); // "Hello World!" is a string.
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}

通过创建自己的包装器构造函数,您可以确保:
像underscore和lodash这样的流行JavaScript库为此目的创建了包装构造函数。
答案 1 :(得分:9)
首先,为什么定义Object(或其他内置类型)的属性是不受欢迎的 - 它们出现在意想不到的地方。以下是一些输出一些字符所具有的总英尺数的代码:
var feetMap = {
jerry : 4,
donald : 2,
humpty: 0
}
function countFeet(feetMap) {
var allFeet = 0;
for (var character in feetMap) {
allFeet += feetMap[character];
}
return allFeet;
}
console.log('BEFORE DEFINITION', countFeet(feetMap));
Object.prototype.isString = function() {
return typeof this === "string";
};
console.log('AFTER DEFINITION', countFeet(feetMap));
请注意,如何简单地定义isString函数将影响countFeet函数的结果,该函数现在迭代一个意外的属性。当然,如果迭代是使用hasOwnProperty检查保护的,或者属性被定义为不可枚举,则可以避免这种情况。
避免在内置类型上定义属性的另一个原因是碰撞的可能性。如果每个人都定义了他们自己的isNumber方法,根据用例给出了稍微不同的结果 - 可以考虑字符串" 42"一个数字和另一个人可能会说它不是 - 当人们使用多个图书馆时,整个地方就会出现一些漏洞。
问题是 - 为什么需要一个可以影响任何值类型的方法?方法应该是它所属的对象类所固有的东西。拥有一个isString方法对Number对象毫无意义 - 它与Numbers没有任何关系。
更有意义的是有一个函数/方法可以返回作为参数赋予它的值的类型:
var Util = Util || {};
Util.isString(value) {
return typeof value === "string";
}
Util.isString('test') // true
Util.isString(5) // false
您当前代码的原因
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
不起作用是因为当您访问原始值的属性时,JS会创建适当类型的包装器对象,并在该包装器对象上解析该属性(之后它将其抛弃)。这是一个应该阐明它的例子:
Object.prototype.getWrapper = function(){
return this;
}
console.log((5).getWrapper()); // Number [[PrimitiveValue]]:5
console.log("42".getWrapper()); // String [[PrimitiveValue]]:"42"
请注意,原始值5和对象new Number(5)是不同的概念。
您可以通过返回原始值的类型来改变您的功能。另外,不要忘记使其不可枚举,以便在迭代随机对象时不显示。
Object.defineProperty(Object.prototype, 'isString', {
value : function() {
return typeof this.valueOf() === "string";
},
enumerable : false
});
"5".isString() //returns true
"".isString() //returns true
var str = "string"
str.isString() //returns true
答案 2 :(得分:5)
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
如果有人能解释该函数是任何对象的属性的解决方法,以及为什么当前方法不起作用,我将提供125个代表。
<强>答案:强>
在javascript中,当你调用一个对象的子方法/属性时,如“myFunction”(object.myFunction或object [“MyFunction”])
它将开始查看对象本身是否具有它
如果不是:它将遵循原型链(如正常oop中的超类),
直到找到带有方法/属性的“父/超类”
这个原型链的最后一步是Object
如果Object dosnt有方法,它将返回“undefined”。
当您扩展Object类本身时,它总是会看
任何将该方法作为Object调用的对象(在oop中:所有类也是Object,另外还有自己的classtype)
这就像在正常的OOP中错过了“演员”一样
所以你的函数返回false的原因是在这种情况下它的“对象”不是“字符串”
尝试使用此功能:
Object.prototype.typeString = function() {
return typeof this;
}
"5".typeString() //returns "object"
正如大家所说,扩展任何原生JS 类非常糟糕,但解决方法将从以下内容开始:
Object.prototype.objectTypeString = function(){
return Object.prototype.toString.call(this);
}
这是一个小提琴: http://jsfiddle.net/fwLpty10/13/
请注意,null dosnt有原型,NaN(Notanumber)被认为是一个数字!!! 这意味着您将始终需要检查变量是否为空, 在调用此方法之前!
Object.prototype.isString = function(){
return Object.prototype.toString.call(this) === "[object String]";
};
最后的小提琴:http://jsfiddle.net/xwshjk4x/5/
这里的技巧是这个方法返回toString方法的结果,用“this”调用,这意味着在toString方法的上下文中,你调用它的对象是它自己的类(不是只是原型链中的任何超类型)
答案 3 :(得分:5)
发布的代码扩展了对象原型将工作,如果更正。
然而,它对调用方法中的this
内容做出了错误的假设。使用发布的代码,以下输出正确并且是预期的(除了一些旧的实现错误);
"5".isString() //returns false
这是因为JavaScript将&#34; wrap&#34; 或&#34;将原始值提升为相应的对象类型在之前它调用方法 - this
实际上是一个String 对象,而不是字符串值。 (JavaScript有效地伪造了对原始值的调用方法。)
将功能替换为:
Object.prototype.isString = function() {
return this instanceof String;
}
然后:
"5".isString() // => true (a string was "promoted" to a String)
(5).isString() // => false (`this` is a Number)
另一种解决方案也是使用多态性;修改标准原型的相同&#34;陷阱&#34; 1 。
Object.prototype.isString = function () { return false; }
String.prototype.isString = function () { return true; }
1 使用defineProperty可以减轻向全局原型添加新的可枚举属性的顾虑,这会创建一个&#34;不可枚举&# 34;属性默认。
只需更改
x.prototype.y = ..
到
Object.defineProperty(x.prototype, 'y', { value: .. })
(我不是在修改原型的使用;只是解释原始的有问题的输出并指出一种防止枚举行为的方法。)
答案 4 :(得分:4)
向你展示一些例子:
String.prototype.myFunction = function() {
return this+"asd";
};
此函数会在调用"asd"
时为每个字符串添加myFunction()
。
var s = "123";
s = s.myFunction();
//s is now "123asd"
答案 5 :(得分:4)
在我们开始之前,很少有重要的语句要记住并注意(对于所有字符串文字/原语,String对象,数字文字/原语,数字对象等都是如此):
Object
,并继承Object.prototype中的方法和属性 - String
,Number
等(非常类似于Java)。String
,Number
,Boolean
和Symbol
Object
Object
类型。String
对象的类型为Object
。instanceof
运算符测试对象在其原型链中是否具有构造函数的prototype属性。 (这里获得TRUE的第一个条件是instanceof应该用于对象或其子类)typeof
运算符返回一个字符串,指示未评估的操作数的类型。 String as primitive:
字符串原语或文字可以通过以下方式构建:
var str1 = “Hello”;
var str2 = String(“Hello”);
typeof str1; //Output = "string"
typeof str2; //Output = "string"
str1 instanceof (String || Object) //Output = false because it is a primitive not object
str2 instanceof (String || Object) //Output = false because it is a primitive not object
String as Object:
可以通过从新对象调用其构造函数来构造String对象:
var str3 = new String(“Hello”);
typeof str3; //Output = "string"
str3 instanceof (String) //Output = true because it is a String object
str3 instanceof (Object) //Output = true because it is an Object
最重要的是看起来不太明显,但有必要设置基础。
现在,让我谈谈你的案例。
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
由于概念称为自动装箱,因此o / p会变为FALSE。当您在字符串文字上调用任何方法时,它将转换为String对象。 Read this来自MSDN - “字符串文字的方法”,以确保自己。
因此,在原型中,当您使用typeof
检查类型时,它将永远不会是文字(typeof == "string"
),因为它已经转换为对象。那是你错误的原因,如果你检查typeof
object
那么你会得到真的,我将在下面详细讨论:
现在让我谈谈提供给你的解决方案。它说要进行instanceof
检查,这是100%正确的,但请注意,在到达原型时,它可能是对象类型或功能类型。因此,我在下面提供的解决方案将为您提供相同的图片。
我的建议是拥有一个通用函数,它会返回实例的类型,然后你可以做任何你想做的事情,如果它是一个数字或字符串等。isString
是好的但是你有写isNumber
等,所以改为只有一个函数可以返回实例的类型,甚至可以处理函数类型。
以下是我的解决方案:
Object.prototype.getInstanceType = function() {
console.log(this.valueOf());
console.log(typeof this);
if(typeof this == "object"){
if(this instanceof String){
return "String";
} else if(this instanceof Boolean){
return "Boolean";
} else if(this instanceof Number){
return "Number";
} else if(this instanceof Symbol){
return "Symbol";
} else{
return "object or array"; //JSON type object (not Object) and array
}
} else if(typeof this == "function"){
return "Function";
} else{
//This should never happen, as per my knowledge, glad if folks would like to add...
return "Nothing at all";
}
}
输出:
new String("Hello").getInstanceType() //String
"Hello".getInstanceType() //String
(5).getInstanceType() //Number
(true).getInstanceType() //Boolean
Symbol().getInstanceType() //Symbol
var ddd = function(){}
var obj = {}
obj.getInstanceType() //object or array
var arr = []
arr.getInstanceType() //object or array
ddd.getInstanceType() //Function
($).getInstanceType() //Function, because without double quotes, $ will treated as a function
("$").getInstanceType() //String, since it came in double quotes, it became a String
总结:您的2个问题如下
但我需要做的是在任何值和访问上使用它 函数中的值。
您可以使用this
访问函数中的值。在我的解决方案中,您可以看到console.log(this.valueOf());
是否有任何解决方法让这是任何Object的属性if 我使用Object.prototype?
您可以按照上述解决方案从Object.prototype.getInstanceType
实现它,您可以在任何有效的JS对象上调用它,您将获得所需的信息。
希望这有帮助!
答案 6 :(得分:2)
JavaScript中的所有对象都来自Object
因此,您可以向Object.prototype
添加方法,然后可以在任何上调用这些方法。例如:
Object.prototype.isString = function() {
return this.constructor.name === 'String';
}
console.log("hi".isString()); //logs true
console.log([].isString()); //logs false
console.log(5..isString()); //logs false
&#13;
如果需要,您可以为每种类型的基元创建此isX
函数。无论哪种方式,都可以为每种类型添加方法,因为JavaScript中的所有内容都来自Object
。
希望有所帮助,祝你好运:)。
- 编辑 -
我确实想指出,仅仅因为你可以这样做并不意味着你应该。扩展JavaScript的内置功能通常是一种不好的做法,对于其他人将使用的库来说更是如此。但这取决于你的用例。祝你好运。
答案 7 :(得分:2)
除了讨论之外,这不是一个好的做法而不是像包装构造函数这样的常用方法,你应该通过要求构造函数的名称来实现这一点:
Object.defineProperty(Object.prototype, 'isString', {
value: function() { return this.constructor.name === "String"; }
});
或者已经提到的 instanceof 方法:
Object.defineProperty(Object.prototype, 'isString', {
value: function() { return this instanceof String; }
});
解释为什么你的方法不起作用是在this post中处理。
如果您希望新定义的属性可枚举,可配置或可写,您应该查看docs for defineProperty。
答案 8 :(得分:2)
正如其他一些人所指出的那样,typeof this === 'string'
部分的代码几乎是正确的,因为当涉及到原语与对象时,由于JavaScript的古怪行为而无法正常工作。测试对象是否为字符串的最有效方法之一是Object.prototype.toString.call(this) === '[object String]'
(请查看this article)。考虑到这一点,您可以简单地编写isString
的实现,如下所示:
Object.prototype.isString = function () {
return Object.prototype.toString.call(this) === '[object String]';
};
"abc".isString(); // ==> true
"".isString(); // ==> true
1..isString(); // ==> false
{}.isString(); // ==> false
答案 9 :(得分:2)
这是因为字符串文字是本机字符串类型,实际上并不是String对象的实例,因此实际上,您无法实际调用Object或String原型中的任何方法。
当您尝试通过类型为字符串的变量调用任何方法时,Javascript 会自动将该值强制转换为新构造的String对象。
所以
"abc".isString();
与:
相同(new String("abc")).isString();
这样做的副作用是你在isString()方法中接收的是一个(类型的变量)Object,它也是String对象的一个实例。
也许你可以通过简化的例子更清楚地看到它:
var a = "Hello";
console.log(typeof a); // string
var b = new String("Hello");
console.log(typeof b); // object
顺便说一下,正如许多其他人所说,你必须在函数中检测字符串的最好机会是检查它是否是String对象的实例:
foo instanceof String
如果您还想检查其他可能的类型,您应该进行如下所示的双重检查:
function someOtherFn(ins) {
var myType = typeOf ins;
if (myType == "object" && ins instanceof String) myType = "string";
// Do more stuf...
}