JavaScript进阶内容1:各种对象类型判断
该文章主要用来介绍JavaScript中常用的一些对象检测判断方法,整理资源来自书本和网络,如有错误或说明不详之处,望评论提出,本菜定提名感谢……(本文章知识比较基础,大牛请提些意见再绕道,三克油^_^)
1.检测原始值(typeof)
结论:
JavaScript五种原始类型:字符串、数字、布尔值、undefined、null。其中前四种的类型检测请使用 typeof ,最后一种 null 的类型检测请使用恒等(===)或者非恒等(!==)运算符。
原因:
typeof 运算符返回一个表示值的类型的字符串,
如:
typeof(字符串) => "string"
typeof(数字) => "number"
typeof(布尔值) => "boolean"
typeof(undefined) => "undefined" typeof 的基本语法是:
typeof 变量 //推荐语法
也可以使用:
typeof(变量) //虽然这是合法的,但这让 typeof 看起来更像是函数,而非运算符。 typeof 检测四种原始类型做法: //检测字符串
if(typeof mytype === "string"){
……
}
// 检测数字
if(typeof mytype === "number"){
……
}
// 检测布尔值
if(typeof mytype === "boolean" && mytype){
……
}
// 检测 undefined
if(typeof mytype ==="undefined"){
……
} 最后一种是对 null 的检测,因为简单地把一个对象和 null 进行比较,不足以判断其值的类型是否合法,比如:
if(items !== null){//不好的做法
items.sort();//如果items不是数组,该执行将报错
items.foreach(function(item){
//执行一些逻辑
})
}
其实,items 是一个数组,但是仅仅通过和 null 比较,不足以判断其是合法的数组类型,因为tiems 也可以是1、字符串、对象等,都和 null 不相等。
因此,只有在你明确预见某个值真的是 null ,则可以直接和 null 比较,比如:
var element = document.getElementById("my-div");
if(element !== null){//因为 getElementById 要么返回节点,要么返回 null
……
}
特别提示:typeof(null) 返回 "object",这被认为是标准规范的严重"bug",所以一定要杜绝使用 typeof 检测 null类型。
2.检测引用值(instanceof)
结论:
JavaScript引用类型有:Object、Array、Date、Error、RegExp 等等。检测引用类型的最好方法是使用 instanceof 运算符(Array 无法跨帧,需另讲)。
原因:
不能使用 typeof 检测引用类型,因为所有对象都会返回"object":
typeof {} => "object"
typeof [] => "object"
typeof new Date() => "object"
typeof new RegExp() => "object"
所以不能用 typeof 来检测。
instanceof 意思是"实例",也就是说只要一个变量是某个对象(引用类型)的实例,则返回 true,如:
// 检测日期
if(value instanceof Date){
……
}
// 检测正则表达式
if(value instanceof RegExp){
……
}
// 检测 Error
if(value instanceof Error){
……
} 另外,instanceof 还可以检测原型链,比如,所有对象都继承自 Object,所以 value instanceof Object 都会返回 true。
如:
var now = new Date();
now instanceof Object => true
now instanceof Date => true
3.检测函数(typeof)
结论:
检测函数使用 typeof;而IE8及其更早浏览器中检测DOM的方法时(document.getElementById/document.createElement/document.getElementsByTageName……)时使用 in 运算符。
原因:
function 也是引用类型,虽然
function myFun(){}
console.log(myFun instanceof Function)// true
返回true,但是每个函数中都有自己的 Function 构造方法,如果跨帧(frame)使用,在另一个帧中就不会识别另一个帧中的实例对象。
建议使用 typeof,返回"function".
function myFun(){}
console.log(typeof myFun === "function")// true(推荐使用) 另外,在IE8和更早版本中,使用typeof 检测document.getElementById/document.createElement/document.getElementsByTageName……时,返回 "object"
推荐使用:
if("querySelectorAll" in document){
images=document.querySelectorAll('img');
}
虽然不是最理想的,如果想在IE8及其更早版本中使用,这无疑是最安全的。其他情况则使用 typeof 检测是否为函数。
4.检测数组(Array.isArray + Object.prototype.toString.call(value) === '[object Array]' )
结论:
function isArray(value){
if(typeof Array.isArray === 'function'){
return Array.isArray(value);
}else{
return Object.prototype.toString.call(value) === '[object Array]';
}
}
原因:
最开始检测数组采用“鸭式辨型”:
function isArray(value){
return typeof value.sort === 'function';
}
因为目前只有数组才有排序 sort() 方法,但是如果传递的 value 包含自定义的 sort(),该方法就会失效。 目前比较流行的方法是:
function isArray(value){
return Object.prototype.toString.call(value) === '[object Array]';
}
该方法是基于 toString()方法在所有浏览器中都会返回标准的字符串结果。对于数组则返回 '[object Array]'。
由于ECMAScript5正式引用了 Array.isArray() 方法,IE9+、FireFox4+、Safari 5+、Opera 10.5+、Chrome都支持了该方法,所以
推荐使用:
function isArray(value){
if(typeof Array.isArray === 'function'){
return Array.isArray(value);
}else{
return Object.prototype.toString.call(value) === '[object Array]';
}
}
5.检测属性(in 或 hasOwnProperty)
结论:
判断属性是否存在最好的方法是使用 in 运算符。只有需要判断实例属性时才会用到 hasOwnProperty。
原因:
有时候检测属性会这样使用:
//不好的写法:检测假值
if(object[propertyName]){
……
}
//不好的写法:和 null 比较
if(object[propertyName] != null){
……
}
//不好的写法:和 undefined 比较
if(object[propertyName] != undefined){
……
}
以上的代码,是通过获取该属性值来判断是否包含该属性,但是如果该属性的值本身就是 false、0、""、null、undefined呢?是不是就不管用了!
所以,最好的办法是使用 in 运算符。in 仅仅只会判断属性是否存在,而不会获取属性值。如果只需要判断实例属性可以用 hasOwnProperty。 in vs hasOwnProperty:
in:判断对象(包括原型链)是否具备指定的属性。(有中说法叫:判断实例对象属性、或者继承自对象的原型的属性)
hasOwnProperty:判断对象自身(不包括原型链)是否具有指定名称的属性。 (有种说法叫:仅用于判断实例属性) 上面说明很晦涩,继续看就明白了:
先来对比几个关键词:
实例属性 vs 原型的属性 vs 静态属性:
先看代码:
function Man(myname, age) {
//定义实例属性
this.myname = myname;
this.age = age;
}
//定义静态属性
Man.sex = '男';
//定义原型属性
Man.prototype.phone = '123456'; document.writeln(Man.sex);//男
document.writeln(Man.myname);//undefined
document.writeln(Man.age);//undefined
document.writeln(Man.phone);//undefined
document.writeln(Man.prototype.phone);// var man = new Man("Tom", 24);
document.writeln(man.myname);//Tom
document.writeln(Man.sex);//男
document.writeln(man.age);//
document.writeln(man.phone);//
代码总结:
实例属性:构造函数中定义的属性,类似C#/java中 只能通过 new 实例化一个对象后才能访问到的属性。
原型属性:属于原型链中的属性,通过prototype扩展的属性。
静态属性:在构造函数外,直接通过【对象名.新属性】追加的属性叫静态属性,类似C#/java中的 static 属性。
另外,
(1)构造函数中定义的属性和方法要比原型中定义的属性和方法的优先级高,如果定义了同名称的属性和方法,构造函数中的将会覆盖原型中的。
(2)把方法写在原型中比写在构造函数中消耗的内存更小,因为在内存中一个类的原型只有一个,写在原型中的行为可以被所有实例共享,实例化的时候并不会在实例的内存中再复制一份。而写在类中的方法,实例化的时候会在每个实例中再复制一份,所以消耗的内存更高。所以没有特殊原因,我们一般把属性写到类中,而行为写到原型中。
言归正传,
in 和 hasOwnProperty 如何使用呢,看代码:
function Site(){
//判断是否有这些实例属性方法:s.hasOwnProperty("name/url...") 或 "name/url..." in s
this.name = "CodePlayer";
this.url = "http://www.365mini.com/"; this.sayHello = function(){
document.writeln("欢迎来到" + this.name);
};
} Site.ower='Alec';//判断是否有静态属性方法:Site.hasOwnProperty('ower') 或 "ower" in Site var obj = {
//判断是否有这些原型属性方法:"engine/sayHi.." in s (这些对象是s原型链中的对象,如果该obj又有更高级原型域,同样可以使用 '属性名' in s 判断)
engine: "PHP",
sayHi: function(){
document.writeln("欢迎访问" + this.url);
}
};
Site.prototype = obj; var s = new Site();
document.writeln( s.hasOwnProperty("name") ); // true
document.writeln( s.hasOwnProperty("sayHello") ); // true
// 以下属性继承自原型链,因此为false
document.writeln( s.hasOwnProperty("engine") ); // false
document.writeln( s.hasOwnProperty("sayHi") ); // false
document.writeln( s.hasOwnProperty("toString") ); // false
//静态属性只能通过原型对象判断,无法用实例对象判断
document.writeln( s.hasOwnProperty("ower") ); // false
document.writeln( Site.hasOwnProperty('ower') );//true // 想要查看对象(包括原型链)是否具备指定的属性,可以使用in操作符
document.writeln( "url" in s ); // true
document.writeln( "sayHello" in s ); // true
document.writeln( "engine" in s ); // true
document.writeln( "sayHi" in s ); // true
document.writeln( "toString" in s ); // true document.writeln( "ower" in s ); // false
document.writeln( "ower" in Site ); // true 静态属性需要使用原型对象名访问
附图一张,进一步说明:
看到这里,应该对 in 和 hasOwnProperty 的使用场景有所了解了吧?
最后,需要特别说明的一点是:
IE8及其更早的IE版本中,DOM对象并非继承自Object,因此,无法使用hasOwnProperty()方法,换句话说,如果你在调用DOM对象的hasOwnProperty()方法之前需要先检测器是否存在(假如你已经知道对象不是DOM,就可以省略此步骤)
//对于所有非DOM对象来说,这是好的写法
if(object.hasOwnProperty('related')){
……
}
//如果你不确定是否为DOM对象,则这样写是好的
if('hasOwnProperty' in object && object.hasOwnProperty('related')){
……
}
因为IE浏览器存在此问题,在判断实例对象是否存在时,我更倾向于使用 in运算符,只有在需要判断实例属性时才会用到hasOwnProperty()。
看到这里,说明你是个善良的人,非常感谢!如有错误之处,请留言讨论,共同进步……tks!
参考资料:
《编写可维护的JavaScript》
http://www.365mini.com/page/javascript-hasownproperty.htm
http://www.jb51.net/article/20236.htm
http://blog.sina.com.cn/s/blog_54d1f65b0101dfv3.html
JavaScript进阶内容1:各种对象类型判断的更多相关文章
- JavaScript进阶内容笔记1:各种对象类型判断
该文章主要用来介绍JavaScript中常用的一些对象检测判断方法,整理资源来自书本和网络,如有错误或说明不详之处,望评论提出,本菜定提名感谢……(本文章知识比较基础,大牛请提些意见再绕道,三克油^_ ...
- javascript进阶课程--第二章--对象
javascript进阶课程--第二章--对象 学习要点 理解面向对象的概念 掌握对象的创建方法 掌握继承的概念和实现方法 基本概念 对象究竟是什么?什么叫面向对象编程? 对象是从我们现实生活中抽象出 ...
- javascript进阶教程第二章对象案例实战
javascript进阶教程第二章对象案例实战 一.学习任务 通过几个案例练习回顾学过的知识 通过案例练习补充几个之前没有见到或者虽然讲过单是讲的不仔细的知识点. 二.具体实例 温馨提示 面向对象的知 ...
- JavaScript进阶知识点——函数和对象详解
JavaScript进阶知识点--函数和对象详解 我们在上期内容中学习了JavaScript的基本知识点,今天让我们更加深入地了解JavaScript JavaScript函数 JavaScript函 ...
- JavaScript进阶内容——DOM详解
JavaScript进阶内容--DOM详解 当我们已经熟练掌握JavaScript的语法之后,我们就该进入更深层次的学习了 首先我们思考一下:JavaScript是用来做什么的? JavaScript ...
- JavaScript进阶内容——BOM详解
JavaScript进阶内容--BOM详解 在上一篇文章中我们学习了DOM,接下来让我们先通过和DOM的对比来简单了解一下BOM 首先我们先来复习一下DOM: 文档对象模型 DOM把文档当作一个对象来 ...
- JavaScript进阶内容——jQuery
JavaScript进阶内容--jQuery 我们在前面的文章中已经掌握了JavaScript的全部内容,现在让我们了解一下JavaScript库 这篇文章主要是为了为大家大致讲解JavaScript ...
- js对象类型判断工具
对象类型判断工具 /** *类功能:对象类型判断工具 **/ var TypeUtil = { /** *方法说明:是否是数组 **/ isArray: function (obj) {//是否是数组 ...
- JS框架设计之对象类型判断一种子模块
Javascript有两套数据类型,一套是基础数据类型,一套是对象数据类型.基础数据类型包括5种基本数据类型,分别是null,bool,undefined,number,string,也叫简单数据类型 ...
随机推荐
- 1120练习,CSS制作网页
<title>智博星主页</title> <style type="text/css"> *{ margin:0px auto; padding ...
- paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)
paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1 锁的缺点 2 CAS(Compare ...
- 用sessionStorage实现页面之间的数据传输
1.sessionStorage主要含几种方法: //页面A:存放一个简单的字符串 sessionStorage.obj = '123'; //页面B:取到给obj var str = session ...
- 使用Reveal查看任意App的技巧
转:http://www.jianshu.com/p/4dc8f94ca27c 前言 Reveal(http://revealapp.com)是一个很强大的iOS View Hierarchy工具,与 ...
- 转:LIRE的使用
LIRE的使用:创建索引 LIRE(Lucene Image REtrieval)提供一种的简单方式来创建基于图像特性的Lucene索引.利用该索引就能够构建一个基于内容的图像检索(content- ...
- 使用Webpack和Babel来搭建React应用程序
用Webpack(npm install -g webpack)代码打包,Webpack大致需要知道三件事: 1)让Webpack知道应用程序或js文件的根目录 2)让Webpack知道做何种转换 3 ...
- linux服务器调整参数支持高并发
服务端调整系统的参数,在/etc/sysctl.conf中: ◦net.core.somaxconn = 2048◦net.core.rmem_default = 262144◦net.core.wm ...
- ubuntu 16.04 有道词典
依赖环境 sudo apt install \ python3-pyqt5 \ python3-requests \ python3-xlib \ python3-pil \ tesseract-oc ...
- 安装redis监控
在修改登录中心的时候,数据存储在redis里面,需要对redis进行监控,使用的是Redis-Live 参考文章: http://www.nkrode.com/article/real-time-da ...
- BabeLua
http://cn.cocos2d-x.org/tutorial/show?id=507 command : -workdir E:\xg_svn\client\cocos2d-x-2.2.2\pro ...