判断数据类型
在js中可以判断数据类型的关键字有typeof,instanceof,constructor ,Object.prototype.toString()
js中的数据类型分为:
- 基础数据类型:String,Nmuber,Boolean,Symbol,Null,Undefined
- 引用数据类型:Object
typeof 运算符返回一个字符串,表示操作数的类型。
console.log('typeof ""= ', typeof "");
console.log('typeof 1= ', typeof 1);
console.log('typeof true= ', typeof true);
console.log('typeof Undefined= ', typeof undefined)
console.log('typeof Symbol= ', typeof Symbol('11'))
console.log('typeof Function= ', typeof new Function())
console.log('typeof null= ', typeof null)
console.log('typeof array= ', typeof [])
console.log('typeof Date= ', typeof new Date())
console.log('typeof Object= ', typeof {})
运算结果如下
这个的结果:typeof 对 null ,Object 和Date 等一些数据都返回了Object,这个结果不是我们想要的
instanceof 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
根据字面意思就是实例对象的原型链上有没有某个prototype
function C(){}
function D(){}
C.prototype.add = {};
var o = new C(); //这个 __proto__ 指向了原型的内存地址,引用类型
console.log(o instanceof C)
C.prototype = {}; // 这个改变了 不影响O的原型地址
console.log(o instanceof C)
MDN描述:如果表达式
obj instanceof Foo返回true,则并不意味着该表达式会永远返回true,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false。另外一种情况下,原表达式的值也会改变,就是改变对象obj的原型链的情况,虽然在目前的 ES 规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的__proto__伪属性,是可以实现的。比如执行obj.__proto__ = {}之后,obj instanceof Foo就会返回false了。
在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array 会返回 false,因为 Array.prototype !== window.frames[0].Array.prototype,并且数组从前者继承。所以这个结果也并不是我们想要的
constructor 构造函数属于被实例化的特定类对象
当一个函数被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向函数的引用
实例化对象指向,内部使用原型链查找本身不存在 constructor 属性
但是有一个问题:null 和 undefined 是有 constructor 属性他们还需要单独判断下,如果我改写了prototype那么就不准确了,为啥P1还能准确呢因为P1的__proto__ 是指向之前的引用地址的,所以不响应的
Object.prototype.toString
每个对象都有一个
toString()方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString()返回 "[object type]",其中type是对象的类型
如果我们直接调用 Object.prototype.toString 。其他的对象覆写了这个方法,没有办法直接调用因为 this 指向的Object。我们想调用这个方法话是不是可以使用改变 this 来调用呀
// Boolean 类型,tag 为 "Boolean"
Object.prototype.toString.call(true); // => "[object Boolean]"
// Number 类型,tag 为 "Number"
Object.prototype.toString.call(1); // => "[object Boolean]"
// String 类型,tag 为 "String"
Object.prototype.toString.call(""); // => "[object String]"
// Array 类型,tag 为 "String"
Object.prototype.toString.call([]); // => "[object Array]"
// Arguments 类型,tag 为 "Arguments"
Object.prototype.toString.call((function() {
return arguments;
})()); // => "[object Arguments]"
// Function 类型, tag 为 "Function"
Object.prototype.toString.call(function(){}); // => "[object Function]"
// Error 类型(包含子类型),tag 为 "Error"
Object.prototype.toString.call(new Error()); // => "[object Error]"
// RegExp 类型,tag 为 "RegExp"
Object.prototype.toString.call(/\d+/); // => "[object RegExp]"
// Date 类型,tag 为 "Date"
Object.prototype.toString.call(new Date()); // => "[object Date]"
// 其他类型,tag 为 "Object"
Object.prototype.toString.call(new class {}); // => "[object Object]"
这个方法可以准确的数据类型: 方便大家使用封装为方法
/* slice 提取某个字符串的一部分,并返回一个新的字符串
且不会改动原字符串 支持负数从后往前找
substring 法返回一个字符串在开始索引到结束索引之间的一个子集,
或从开始索引直到字符串的末尾的一个子集。
*/
// 这样觉得不想引用方法 建议使用该方法
function typeOf(params){
// const value =Object.prototype.toString.call(params)
// return value.substring(8,value.length - 1)
return Object.prototype.toString.call(params).slice(8,-1)
}
// 做原型链引用的操作,数据劫持来实现,null 和 undefined 不能使用,还有可能被覆写了问题
Object.defineProperty(Object.prototype, '_typeOf', {
//writable:false, //属性的值是否可以被重写
enumerable: false, //是否会出现在for in 或者 Object.keys()的遍历中
configurable: false, //是否配置,以及可否删除
get() {
return function () {
return Object.prototype.toString.call(this).slice(8, -1)
}
}
})
学习到的知识点
- 原型链,继承
- 判断数据类型的方法
- 字符串截取的方法
- 数据劫持的方法
- js中的数据类型有那些
- 如有错误,请评论我校正