本文中,将简述JavaScript类型系统和数据类型,以及如何使用typeof操作符执行类型检查。
还讲解了使用typeof操作符进行某些数据类型检查是不完善的,并介绍其他几种类型检查的方法。
每种编程语言都有自己的类型系统和数据类型,但各种编程语言的数据结构常有不同之处。使用JavaScript时,其引擎会在脚本执行期间隐式强制转换执行值的类型。类型检查对于编写可预测的JavaScript程序是非常有必要的。
JavaScript中的typeof操作符就是用于基础的类型检查
typeof操作符返回字符串,表示未经计算的操作数的类型(来自MDN)
在此之前,需要了解JavaScript有哪些数据类型,最新标准定义了8种数据类型:
JavaScript还有几个对象类构造函数,用于创建其他类型的对象:
1、语法
typeof使用一元操作符(只需要一个操作数)的计算结果作为其操作数的类型结果字符串。
另一种替代语法就是将操作数放入括号中使用,这种对JavaScript表达式返回的值进行类型检查非常有用。
typeof 参数 typeof(参数)
参数:一个表示对象或原始值的表达式,其类型将被返回
typeof "sueRimn"; // 'string' typeof 22; // 'number' typeof NaN; // 'number' typeof Infinity; // 'number' typeof true; // 'boolean' typeof false; // 'boolean' typeof [1, 2]; // 'object' typeof {age: 22}; // 'object' typeof null; // 'object' typeof undefined; // 'undefined' typeof String; // 'function' typeof Boolean; // 'function' typeof Number; // 'function' typeof Object; // 'function' typeof Function; // 'function' typeof person; // 'function'
undefined是它自己的JavaScript类型
在ES6之前,typeof不管操作数是否声明,总是返回一个字符串,即对于未声明的标识符,总是返回而不是抛出错误。
在ES6中,使用let或const声明的块级作用域变量在初始化之前与typeof操作符使用,将抛出错误。
原因是:块级作用域变量在被初始化之前一直保留在临时死区。
console.log(typeof name==='undefined'); // ReferenceError const name='sueRimn';
2、一般类型检查
在JavaScript中执行类型检查主要使用typeof操作符
function add(a, b) { if (typeof a !=='number' || typeof b !=='number') { throw '参数必须是数值' } return a + b; }
以下是对类型检查的简单摘要:
检测值是否存在在不同环境是这样的:
if (typeof window !=='undefined') { // 浏览器 }; if (typeof process !=='undefined') { // Node.js } if (typeof $ !=='undefined') { // jQuery }
3、其他类型检查
对于某些值需要额外的类型检查才可以区分,例如null和[]在使用typeof操作符执行type-check时都是"object"类型,但是区分它们需要额外的操作。
一些其他数据类型值检查方法:
(1)检测是否为空
使用typeof操作符检查值是否为空并不好,检查值是否为空的最佳方法是对值与关键字进行严格相等比较。
以上代码呈现的结果是不一样的,所以使用严格相等操作符是非常重要的。
(2)检测NaN
任何涉及NaN的算术运算都将对NaN求值,如果想为任何形式的算术运算使用值,那么需要确保该值不是NaN。
使用typeof操作符检查NaN值是否返回"number"。要检查NaN值,可以使用全局函数isNaN(),或者ES6中的Number.isNaN()函数:
NaN值非常特殊,通过比较,它永远不等于任何其他值,包括它自己:
可以使用以下方法在非ES6环境下检测NaN:
function isNan(value) { return value !==value; }
最后,你可以利用ES6中的Object.is()函数来测试值是否为NaN。
以下函数作用是检查两个值是否相同:
function isNan(value) { return Object.is(value, Number.NaN); }
(3)检测数组
使用typeof检查数组将返回object。这里介绍几种检测数组的方法,并进行对比:
function isArray(value) { return typeof value=='object' && value.constructor===Array; }
function isArray(value) { return value instanceof Array; }
function isArray(value) { return Object.prototype.toString.call(value)==='[object Array]'; }
object.prototype.tostring()方法对于检查任何JavaScript值的对象类型都非常有用
量的数据类型转换:将一种数据类型转换为另外一种数据类型。
通常有三种形式的类型转换:
你会专门把某个数据类型转换成 null 或者 undefined 吗?不会,因为这样做,没有意义。
我们先来讲一下 typeof,再讲类型转换。
typeof()表示“获取变量的数据类型”,返回的是小写,语法为:(两种写法都可以)
// 写法1typeof 变量;// 写法2typeof(变量);
typeof 这个运算符的返回结果就是变量的类型。那返回结果的类型是什么呢?是字符串。
返回结果:
typeof 的代码写法返回结果typeof 数字numbertypeof 字符串stringtypeof 布尔型booleantypeof 对象objecttypeof 方法functiontypeof nullobjecttypeof undefinedundefined
备注 1:为啥 typeof null的返回值也是 object 呢?因为 null 代表的是空对象。
备注 2:typeof NaN的返回值是 number,上一篇文章中讲过,NaN 是一个特殊的数字。
返回结果举例:
console.log(type []); // 空数组的打印结果:objectconsole.log(type {}); // 空对象的打印结果:object
代码解释:这里的空数组[]、空对象{} ,为啥他们在使用 typeof 时,返回值也是 object呢?因为这里的 返回结果object指的是引用数据类型。空数组、空对象都是引用数据类型 Object。
类型转换分为两种:显示类型转换、隐式类型转换。
针对上面这两种类型转换,这篇文章来详细介绍。
格式:变量+”” 或者 变量+”abc”
举例:
var a=123; // Number 类型console.log(a + ''); // 转换成 String 类型console.log(a + 'haha'); // 转换成 String 类型
上面的例子中,打印的结果,都是字符串类型的数据。实际上内部是调用的 String() 函数。也就是说,c=c + "" 等价于 c=String(c)。
语法:
变量.toString()
【重要】该方法不会影响到原变量,它会将转换的结果返回。当然我们还可以直接写成a=a.toString(),这样的话,就是直接修改原变量。
注意:null 和 undefined 这两个值没有 toString()方法,所以它们不能用方法二。如果调用,会报错。
另外,Number 类型的变量,在调用 toString()时,可以在方法中传递一个整数作为参数。此时它将会把数字转换为指定的进制,如果不指定则默认转换为 10 进制。例如:
var a=255;//对于Number调用toString()时可以在方法中传递一个整数作为参数//此时它将会把数字转换为指定的进制,如果不指定则默认转换为10进制a=a.toString(2); // 转换为二进制console.log(a); // 11111111console.log(typeof a); // string
语法:
String(变量)
使用 String()函数做强制类型转换时:
我们在 JS 基础的第 01 篇里,就讲过,prompt()就是专门用来弹出能够让用户输入的对话框。重要的是:用户不管输入什么,都当字符串处理。
情况一:字符串 —> 数字
情况二:布尔 —> 数字
情况三:null —> 数字
情况四:undefined —> 数字
补充:怎么理解这里的 NaN 呢?可以这样理解,使用 Number() 函数之后,如果无法转换为数字,就会转换为 NaN。
parseInt()的作用是将字符串中的有效的整数内容转为数字。parse 表示“转换”,Int 表示“整数”(注意Int的拼写)。例如:
parseInt("5");
得到的结果是数字 5。
parseInt()的转换情况如下。
情况一:字符串 —> 数字
情况二:Boolean —> 数字
情况三:Null —> 数字
情况四:Undefined —> 数字
Number() 函数和 parseInt() 函数的区别:
就拿Number(true) 和 parseInt(true)/parseFloat(true)来举例,二者在使用时,是有区别的:
parseInt()具有以下特性:
(1)只保留字符串最开头的数字,后面的中文自动消失。例如:
console.log(parseInt("2017在公众号上写了6篇文章")); //打印结果:2017console.log(parseInt("2017.01在公众号上写了6篇文章")); //打印结果仍是:2017 (说明只会取整数)console.log(parseInt("aaa2017.01在公众号上写了6篇文章")); //打印结果:NaN (因为不是以数字开头)
(2)如果对非 String使用 parseInt()或 parseFloat(),它会先将其转换为 String 然后再操作。【重要】
比如:
var a=168.23;console.log(parseInt(a)); //打印结果:168 (因为是先将c转为字符串"168.23",然后然后再操作)var b=true;console.log(parseInt(b)); //打印结果:NaN (因为是先将a转为字符串"true",然后然后再操作)var c=null;console.log(parseInt(c)); //打印结果:NaN (因为是先将b转为字符串"null",然后然后再操作)var d=undefined;console.log(parseInt(d)); //打印结果:NaN (因为是先将b转为字符串"undefined",然后然后再操作)
(3)自动带有截断小数的功能:取整,不四舍五入。
例 1:
var a=parseInt(5.8) + parseInt(4.7);console.log(a);
打印结果:
9
例 2:
var a=parseInt(5.8 + 4.7);console.log(a);
打印结果:
10;
(4)带两个参数时,表示在转换时,包含了进制转换。
代码举例:
var a='110';var num=parseInt(a, 16); // 【重要】将 a 当成 十六进制 来看待,转换成 十进制 的 numconsole.log(num);
打印结果:
272
如果你对打印结果感到震惊,请仔细看上面的代码注释。就是说,无论 parseInt() 里面的进制参数是多少,最终的转换结果是十进制。
我们继续来看下面的代码,打印结果是多少。
var a='5';var num=parseInt(a, 2); // 将 a 当成 二进制 来看待,转换成 十进制 的 numconsole.log(num); // 打印结果:NaN。因为 二进制中没有 5 这个数,转换失败。
parseFloat()的作用是:将字符串转换为浮点数。
parseFloat()和 parseInt()的作用类似,不同的是,parseFloat()可以获得有效的小数部分。
代码举例:
var a='123.456.789px';console.log(parseFloat(a)); // 打印结果:123.456
parseFloat() 的几个特性,可以参照 parseInt()。
将其他的数据类型转换为 Boolean,可以使用 Boolean()函数。情况如下:
PS:转换为 Boolean 的这几种情况,很重要,开发中会经常用到。
比如070这个字符串,如果我调用 parseInt()转成数字时,有些浏览器会当成 8 进制解析,有些会当成 10 进制解析。
所以,比较建议的做法是:可以在 parseInt()中传递第二个参数,来指定当前数字的进制。例如:
var a="070";a=parseInt(a, 8); //将 070 当成八进制来看待,转换结果为十进制。console.log(a); // 打印结果:56。这个地方要好好理解。
重点:隐式类型转换,内部调用的都是显式类型的方法。下面来详细介绍。
语法:
isNaN(参数);
解释:判断指定的参数是否为 NaN(非数字类型),返回结果为 Boolean 类型。也就是说:任何不能被转换为数值的参数,都会让这个函数返回 true。
执行过程:
(1)先调用Number(参数)函数;
(2)然后将Number(参数)的返回结果和NaN进行比较。
代码举例:
console.log(isNaN('123')); // 返回结果:false。console.log(isNaN('abc')); // 返回结果:true。因为 Number('abc') 的返回结果是 NaNconsole.log(isNaN(null)); // 返回结果:falseconsole.log(isNaN(undefined)); // 返回结果:trueconsole.log(isNaN(NaN)); // 返回结果:true
举例 1:
var a="666";a++;console.log(typeof a); // 打印结果: numberconsole.log(a); // 打印结果:667
执行过程:
(1)先调用Number(参数)函数;
(2)然后将Number(参数)的返回结果进行 加 1 操作。
举例 2:
var a='abc';a++;console.log(typeof a); // 打印结果:numberconsole.log(a); // 打印结果:NaN。因为 Number('abc')的结果为 NaN,再自增后,结果依然是 NaN
注意,这里说的是正号/负号,不是加号/减号。
任何值做+a、-a、/a运算时,运算结果都会自动转换为 Number 类型。 内部调用的是 Number() 函数。
举例:
var a='666';var b=+a;console.log(typeof a); // 打印结果:string。说明 a 的数据类型保持不变。console.log(a); // 打印结果:666console.log(typeof b); // 打印结果:number。说明 b 的数据类型发生了变化。console.log(b); // 打印结果:666
情况一:字符串 + 数字
情况二:Boolean + 数字
情况三: null + 数字
情况四: undefined + 数字
1、任何非 Number 类型的值做-、*、/运算时,会将这些值转换为Number然后再运算(内部调用的是 Number() 函数),运算结果是 Number 类型。(注:任何值 + 字符串是特例,运算结果是字符串)
比如:
result1=true + 1; // 2=1+ 1 result2=true + false; // 1=1+ 0 result3=1 + null; // 1=1+ 0 result4=100 - '1' // 99
2、任何的值和字符串做加法运算,都会先转换为字符串,然后再做拼串操作。
比如:
result1=1 + 2 + '3' // 33 result2='1' + 2 + 3; // 123
3、任何值和NaN做运算的结果都是NaN。
页可见区域宽:document.body.clientWidth
网页可见区域高:document.body.clientHeight
网页可见区域宽:document.body.offsetWidth (包括边线的宽)
网页可见区域高:document.body.offsetHeight (包括边线的宽)
网页正文全文宽:document.body.scrollWidth
网页正文全文高:document.body.scrollHeight
网页被卷去的高:document.body.scrollTop
网页被卷去的左:document.body.scrollLeft
网页正文部分上:window.screenTop
网页正文部分左:window.screenLeft
屏幕分辨率的高:window.screen.height
屏幕分辨率的宽:window.screen.width
屏幕可用工作区高度:window.screen.availHeight
屏幕可用工作区宽度:window.screen.availWidth
HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth
scrollHeight: 获取对象的滚动高度。
scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离
scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
scrollWidth:获取对象的滚动宽度
offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度
offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置
offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置
event.clientX 相对文档的水平座标
event.clientY 相对文档的垂直座标
event.offsetX 相对容器的水平坐标
event.offsetY 相对容器的垂直坐标
document.documentElement.scrollTop 垂直方向滚动的值
event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量
IE,FireFox 差异如下:
IE6.0、FF1.06+:
clientWidth=width + padding
clientHeight=height + padding
offsetWidth=width + padding + border
offsetHeight=height + padding + border
IE5.0/5.5:
clientWidth=width - border
clientHeight=height - border
offsetWidth=width
offsetHeight=height
(需要提一下:CSS中的margin属性,与clientWidth、offsetWidth、clientHeight、offsetHeight均无关)
网页可见区域宽: document.body.clientWidth
网页可见区域高: document.body.clientHeight
网页可见区域宽: document.body.offsetWidth (包括边线的宽)
网页可见区域高: document.body.offsetHeight (包括边线的高)
网页正文全文宽: document.body.scrollWidth
网页正文全文高: document.body.scrollHeight
网页被卷去的高: document.body.scrollTop
网页被卷去的左: document.body.scrollLeft
网页正文部分上: window.screenTop
网页正文部分左: window.screenLeft
屏幕分辨率的高: window.screen.height
屏幕分辨率的宽: window.screen.width
屏幕可用工作区高度: window.screen.availHeight
屏幕可用工作区宽度: window.screen.availWidth
-------------------
技术要点
本节代码主要使用了Document对象关于窗口的一些属性,这些属性的主要功能和用法如下。
要得到窗口的尺寸,对于不同的浏览器,需要使用不同的属性和方法:若要检测窗口的真实尺寸,在Netscape下需要使用Window的属性;在IE下需要 深入Document内部对body进行检测;在DOM环境下,若要得到窗口的尺寸,需要注意根元素的尺寸,而不是元素。
Window对象的innerWidth属性包含当前窗口的内部宽度。Window对象的innerHeight属性包含当前窗口的内部高度。
Document对象的body属性对应HTML文档的标签。Document对象的documentElement属性则表示HTML文档的根节点。
document.body.clientHeight表示HTML文档所在窗口的当前高度。document.body. clientWidth表示HTML文档所在窗口的当前宽度。
实现代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>请调整浏览器窗口</title>
<meta http-equiv="content-type" content="text/html; charset=gb2312">
</head>
<body>
<h2 align="center">请调整浏览器窗口大小</h2><hr>
<form action="#" method="get" name="form1" id="form1">
<!--显示浏览器窗口的实际尺寸-->
浏览器窗口 的 实际高度: <input type="text" name="availHeight" size="4"><br>
浏览器窗口 的 实际宽度: <input type="text" name="availWidth" size="4"><br>
</form>
<script type="text/javascript">
<!--
var winWidth=0;
var winHeight=0;
function findDimensions() //函数:获取尺寸
{
//获取窗口宽度
if (window.innerWidth)
winWidth=window.innerWidth;
else if ((document.body) && (document.body.clientWidth))
winWidth=document.body.clientWidth;
//获取窗口高度
if (window.innerHeight)
winHeight=window.innerHeight;
else if ((document.body) && (document.body.clientHeight))
winHeight=document.body.clientHeight;
//通过深入Document内部对body进行检测,获取窗口大小
if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientWidth)
{
winHeight=document.documentElement.clientHeight;
winWidth=document.documentElement.clientWidth;
}
//结果输出至两个文本框
document.form1.availHeight.value=winHeight;
document.form1.availWidth.value=winWidth;
}
findDimensions();
//调用函数,获取数值
window.onresize=findDimensions;
//-->
</script>
</body>
</html>
源程序解读
(1)程序首先建立一个表单,包含两个文本框,用于显示窗口当前的宽度和高度,并且,其数值会随窗口大小的改变而变化。
(2)在随后的JavaScript代码中,首先定义了两个变量winWidth和winHeight,用于保存窗口的高度值和宽度值。
(3)然后,在函数findDimensions ( )中,使用window.innerHeight和window.innerWidth得到窗口的高度和宽度,并将二者保存在前述两个变量中。
(4)再通过深入Document内部对body进行检测,获取窗口大小,并存储在前述两个变量中。
(5)在函数的最后,通过按名称访问表单元素,结果输出至两个文本框。
(6)在JavaScript代码的最后,通过调用findDimensions ( )函数,完成整个操作。
*请认真填写需求信息,我们会在24小时内与您取得联系。