这个题很有意思?
x
想想为啥??
有时会看到:
toString() 是一个怎样的方法, 他定义在哪里呢?
很多人就会在想,为神马
参考:
其实说白了,就是怕你重写了 toString, 所以才要用 object 最原始的他 toString, 所以才去 call:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>
- </title>
- <script type="text/javascript">
- function A() {
- this.say = function() {
- console.log("我是1");
- }
- }
- function B() {
- this.say = function() {
- console.log("我是2");
- }
- }
- var a = new A();
- var b = new B();
- a.say.call(b); //我是1
- </script>
- </head>
- <body>
- </body>
- </html>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>
- </title>
- <script type="text/javascript">
- function A() {
- this.name = 'SB';
- this.say = function() {
- console.log("我是1");
- }
- }
- function B() {
- A.call(this); //B继承A,重写say方法
- this.say = function() {
- console.log("我是2");
- }
- }
- var a = new A();
- var b = new B();
- console.log(b.name); //SB
- b.say(); //我是2
- a.say.call(b); //我是1
- </script>
- </head>
- <body>
- </body>
- </html>
至于为啥???看
它是能将某一个值转化为字符串的方法。然而它是如何将一个值从一种类型转化为字符串类型的呢?
通过下面几个例子,我们便能获得答案:
1. 将 boolean 类型的值转化为 string 类型:
- console.log(true.toString()); //"true"console.log(false.toString());//"false"
2. 将 string 类型按其字面量形式输出:
- var str = "test123y";
- console.log(str.toString()); //"test123y"
3. 将 Object 类型转化成 string 类型(JavaScript 原生的 Array 类型、Date 类型、RegExp 类型以及 Number、Boolean、String 这些包装类型都是 Object 的子类型):
- 自定义Object类型(没有重新定义toString方法):
- var obj = {
- name: "Tom",
- age: 18
- };
- console.log(obj.toString()); //"[object Object]"此时调用的是从Object继承来的原始的toString()方法
接下来的三个例子都是以重写的方式实现了 toString() 方法;
1.Array 类型:
- var arr = ["tom", 12, "rose", 18];
- console.log(arr.toString()); //"tom,12,rose,18"
2.RegExp 类型
- var patten = new RegExp("//[hbc//]at", "gi");
- console.log(patten.toString()); //"//[hbc/]at/gi"
3.Date 类型
- var date = new Date(2014, 02, 26); //注意这种格式创建的日期,其月份是3月console.log(date.toString());//"Wed Mar 26 2014 00:00:00 GMT+0800"输出格式因浏览器不同而不同,此为firefox的输出格式;
4.Number 类型也是以重写的方式实现 toString() 方法的,请看以下例子:
(1) 它可以接受一个整数参数,并将调用这个方法的数值转化成相应进制的字符串:
- var num = 16;
- console.log(num.toString(2)); //10000 二进制console.log(num.toString(8));//20 八进制console.log(num.toString(16));//10 十六进制console.log(num.toString(5));//31 虽然没有五进制,但是这样传参是可以被toString()方法接受的
(2) 再看下面的代码:
- console.log(1.toString()); //这种写法会报错语法错误,但是下面的写法都是合法的;console.log((1).toString());//"1"console.log(typeof (1).toString());//stringconsole.log(1..toString());//"1"console.log(typeof (1).toString());//stringconsole.log(1.2.toString());//"1"console.log(typeof (1).toString());//string
这是因为 javascript 引擎在解释代码时对于 "1.toString()" 认为 "." 是浮点符号,但因小数点后面的字符是非法的,所以报语法错误;而后面的 "1..toString() 和 1.2.toStirng()" 写法,javascript 引擎认为第一个 "." 小数点,的二个为属性访问语法,所以都能正确解释执行;对于 "(1).toStirng()" 的写法,用 "()" 排除了 "." 被视为小数点的语法解释,所以这种写法能够被解释执行;
(3) 纯小数的小数点后面有连续 6 或 6 个以上的 "0" 时,小数将用 e 表示法进行输出;
- var num = 0.000006; //小数点后面有5个"0"console.log(num.toString());//"0.000006"var num = 0.0000006;//小数点后面有6个"0"console.log(num.toString());//"6e-7"
(4) 浮点数整数部分的位数大于 21 时,输出时采用 e 表示法;
- var num = 1234567890123456789012;
- console.log(num.toString()); //"1.2345678901234568e+21"
看到这里大家难免会有些疑问,这些基本的数据类型的值都是常量,而常量是没有方法的,为什么能够调用方法呢?答案是这样的,五种基本类型除了 null、undefined 以外都有与之对应的特殊的引用类型——包装类型。当代码被解释执行时,底层会对基本类型做一个类型转换,即将基本类型转换成引用类型,这样就可以调用相应引用类型有权访问到的方法。
二、toString() 方法定义在何处?
运行以下代码:
- var pro = Object.prototype;
- var pr = pro.__proto__; //ie11之前版本不支持该属性console.log(typeof pro);//"object"console.log(String(pro));//"[object Object]"console.log(pro.hasOwnProperty("toString"));//trueconsole.log(typeof pr);//"object"console.log(String(pr));//"null"console.log(pr.hasOwnProperty("toString"));//报错
由此可知,toString() 定义在 Object.prototype 上;
三、使用 Object.prototype 上的原生 toString() 方法判断数据类型,使用方法如下:
Object.prototype.toString.call(value)
1. 判断基本类型:
- Object.prototype.toString.call(null); //"[object Null]"Object.prototype.toString.call(undefined);//"[object Undefined]"Object.prototype.toString.call("abc");//"[object String]"Object.prototype.toString.call(123);//"[object Number]"Object.prototype.toString.call(true);//"[object Boolean]"
2. 判断原生引用类型:
函数类型
- Function fn() {
- console.log("test");
- }
- Object.prototype.toString.call(fn); //"[object Function]"
日期类型
- var date = new Date();
- Object.prototype.toString.call(date); //"[object Date]"
数组类型
- var arr = [1, 2, 3];
- Object.prototype.toString.call(arr); //"[object Array]"
正则表达式
- var reg = /[hbc]at/gi;
- Object.prototype.toString.call(arr); //"[object Array]"
自定义类型
- person = new Person("Rose", 18);
- Object.prototype.toString.call(arr); //"[object Object]"
很明显这种方法不能准确判断 person 是 Person 类的实例,而只能用 instanceof 操作符来进行判断,如下所示:
- console.log(person instanceof Person); //输出结果为true
3. 判断原生 JSON 对象:
- var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);
- console.log(isNativeJSON); //输出结果为"[object JSON]"说明JSON是原生的,否则不是;
- 注意:Object.prototype.toString()本身是允许被修改的,而我们目前所讨论的关于Object.prototype.toString()这个方法的应用都是假设toString()方法未被修改为前提的。
在 JavaScript 中, 如何准确获取变量的类型名是一个经常使用的问题.
但是常常不能获取到变量的精确名称, 或者必须使用 jQuery 中的方法, 这里 我通过 typeof ,jQuery.type 和 通过构造函数来获取变量类型 这三种方法详细介绍一遍.
希望可以对你提供帮助.
看到题目的第一眼, 有些同学可能会想到 typeof 运算符.
在 JavaScript 语言中, 给出了使用 typeof 运算符来获取基本的类型名.(注意不是基本类型)
这是 typeof 的全部用法
01-typeof.htm
- console.log('typeof of 10 ~~~~' + typeof 10);
- console.log('typeof of "a" ~~~~' + typeof 'a');
- console.log('typeof of true ~~~~' + typeof true);
- console.log('typeof of {} ~~~~' + typeof {});
- console.log('typeof of /123/ ~~~~' + typeof / 123 / );
- console.log('typeof of function(){} ~~~~' + typeof
- function() {});
- console.log('typeof of undefined ~~~~' + typeof undefined);
- console.log('typeof of null ~~~~' + typeof null);
这是结果
按照上面的打印结果, 总结出下面要注意的几点
- ("10x" - 0) == ("10x" - 0);
- // 结果为假!
现在看看 jQuery 是怎么做的
- // 先申明一个对象,目的是用来做映射
- var class2type = {};
- // 申明一个core_toString() 的方法,得到最原始的toString() 方法,因为在很多对象中,toStrintg() 已经被重写
- var core_toString() = class2type.toString;
- // 这里为 toStrintg() 后的结果和类型名做一个映射,申明一个core_toString() 后的结果,而值就是类型名
- jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),
- function(i, name) {
- class2type["[object " + name + "]"] = name.toLowerCase();
- });
因为 Object.prototype.toString() 方法调用结果如下
- var core_toString = {}.toString;
- console.log(core_toString.call(1));
- console.log(core_toString.call("11"));
- console.log(core_toString.call(/123/));
- console.log(core_toString.call({}));
- console.log(core_toString.call(function() {}));
- console.log(core_toString.call([]));
- console.log(core_toString.call(true));
- console.log(core_toString.call(new Date()));
- console.log(core_toString.call(new Error()));
- console.log(core_toString.call(null));
- console.log(core_toString.call(undefined));
- console.log(String(null));
- console.log(String(undefined));
上面的打印结果与
- class2type["[object " + name + "]"] = name.toLowerCase();
不谋而合!
这是 jQuery.type 的核心方法
- type: function(obj) {
- if (obj == null) {
- return String(obj);
- }
- // Support: Safari <= 5.1 (functionish RegExp)
- return typeof obj === "object" || typeof obj === "function" ? class2type[core_toString.call(obj)] || "object": typeof obj;
- },
注意, 为什么把 null 或者 undefined 单独讨论呢, 因为 在一些版本浏览器中
- console.log(core_toString.call(null));
- console.log(core_toString.call(undefined));
这是会报错的!
如果是对象类型, 另: 由于 在一些低版本的浏览器中, typeof /123/ 会返回的是 "function" 而不是 "object", 所以这里要判断是否是函数, 要明白 这里的
不是为了函数讨论的, 因为函数本身就可以通过 typeof 来得到类型.
- typeof obj === function
- typeof obj === "object" || typeof obj === "function" ? class2type[core_toString.call(obj)]
就直接返回 class2type 中键值对的结果,, 如果不是, 那么一定就是基本类型, 通过 typeof 就可以啦.
- class2type[core_toString.call(obj)] || "object":
- // 这是防止一些未知情况的,如果未取到,就返回object
但是 jQuery.type 有一个很大的缺陷
这是一个自定义类型
- function Person() {
- this.name = 'pawn';
- }
- var p = Person.toString();
// 注意, 这里会打印 [object Object], 通过上面的方法, 无法得到精确的自定义类型
这也是 它的一个大缺陷了!
下面, 我们通过构造函数的方式来获取精确类型
这种方式 是蒋坤老师 (jk) 教会我的, 非常感谢他.
在理解这个方法之前, 需要理解两个点
我们知道, 任何对象或者函数都直接或者间接的继承自 Object 或者 Function, (其实最终 Function 是继承自 Object 的,这属于原型链的知识了)。那么,任何一个对象都具有原型对象 __proto__ (这个对象只在 chrome 和 firefox 暴露,但是在其他浏览器中也是存在的),这个原型对象就是这个对象的构造函数的原型属性 (这里可能有点绕).
由于 任何函数都具有 原型属性 prototype, 并且这个原型属性具有一个默认属性 constructor, 它是这个函数的引用, 看下面的代码
- function Person() {
- this.name = 'pawn';
- }
- console.log(Person.prototype.constructor === Person);
发现, 这两个东西其实一个东西
但是, 在某些情况下, 需要这么写
- function Person() {
- this.name = 'pawn';
- }
- Person.protype = {
- XX: ...,
- xx: ...,
- ...
- }
这么做, 就会覆盖原本的 protype 方法, 那么 construcor 就不存在了, 这是, 必须要显示的申明这个对象
- Person.protype = {
- construction: Person,
- XX: ...,
- xx: ...,
- ...
- }
在 jQuery 的中, 就是这么做的,
- jQuery.fn = jQuery.prototype = {
- constructor: jQuery,
- init: function(selector, context, rootjQuery) {
- var match, elem;
关于 jQuery 对象封装的方式 也是非常值得研究
注意, 这里已经不是熟悉 [object Object], 而是 已经重写了.
也就是, 如果调用一个函数的 toString() 方法. 那么就会打印这个函数的函数体.
好了, 经过上面两个步骤, 你明白我要做什么了吗
如何通过构造函数来获得变量的类型
- var getType = function(obj) {
- if (obj == null) {
- return String(obj);
- }
- if (typeof obj === 'object' || typeof obj === 'fucntion') {...
- } else {
- // 如果不是引用类型,那么就是基本类型
- return typeof obj
- }
- }
- function Person() {
- this.name = 'pawn';
- }
- var p = new Person();
- console.log(p.constructor);
现在要做的事 : 如何将 Person 提取出来呢?
毋庸置疑, 字符串切割那一套肯定可以办到, 但是太 low 啦!
这里, 我使用正则将 Person 提取出来
- var regex = /function\s(.+?)\(/
- function Person() {
- this.name = 'pawn';
- }
- var p = new Person();
- var c = p.constructor
- var regex = /function\s(.+?)\(/;
- console.log('|' + regex.exec(c)[1] + '|');
其实, 除了上面的正则, 每个函数还有一个 name 属性, 返回函数名, 但是 ie8 是不支持的.
因此上面的代码可以写为:
- var getType = function(obj) {
- if (obj == null) {
- return String(obj);
- }
- if (typeof obj === 'object' || typeof obj === 'function') {
- var constructor = obj.constructor;
- if (constructor && constructor.name) {
- return constructor.name;
- }
- var regex = /function\s(.+?)\(/;
- return regex.exec(c)[1];
- } else {
- // 如果不是引用类型,那么就是基本;类型
- return typeof obj;
- }
- };
但是上面的代码太丑啦, 将其简化
- var getType = function(obj) {
- if (obj == null) {
- return String(obj);
- }
- if (typeof obj === 'object' || typeof obj === 'function') {
- return obj.constructor && obj.constructor.name.toLowerCase() || /function\s(.+?)\(/.exec(obj.constructor)[1].toLowerCase();
- } else {
- // 如果不是引用类型,那么就是基本类型
- return typeof obj;
- }
- };
还是比较麻烦, 继续简化
- var getType = function(obj) {
- if (obj == null) {
- return String(obj);
- }
- return typeof obj === 'object' || typeof obj === 'function' ? obj.constructor && obj.constructor.name && obj.constructor.name.toLowerCase() || /function\s(.+?)\(/.exec(obj.constructor)[1].toLowerCase() : typeof obj;
- };
好了, 已经全部弄完了, 写个代码测试一下:
- function Person() {
- this.name = 'pawn';
- }
- var p = new Person();
- console.log(getType(p));
- console.log(getType(1));
- console.log(getType("a"));
- console.log(getType(false));
- console.log(getType(/123/));
- console.log(getType({}));
- console.log(getType(function() {}));
- console.log(getType(new Date()));
- console.log(getType(new Error()));
- console.log(getType(null));
- console.log(getType(undefined));
<
来源: http://www.cnblogs.com/libin-1/p/5901580.html