1.类型

ECMAScript语言中所有的值都有一个对应的语言类型。ECMAScript语言类型包括Undefined、Null、Boolean、String、Number和Object。

对语言引擎和开发人员来说,类型是值的内部特征,它定义了值的行为,以使其区别于其他值。

内置类型

JavaScript有七种内置类型:

  • 空值(null)
  • 未定义(undefined)
  • 布尔值(boolean)
  • 数字(number)
  • 字符串(string)
  • 对象(object)
  • 符号(symbol,ES6中新增)

除了对象之外,其他统称为“基本类型”。

我们可以用typeof运算符来查看值的类型,它返回的是类型的字符串值。

typeof undefined === "undefined";//true
typeof true === "boolean";//true
typeof 42 === "number";//true
typeof "42" === "string";//true
typeof {life:42} === "object";//true typeof Symbol() === "symbol";//true //下面是一个bug
typeof null === "object";//true typeof function a(){ /*...*/ } === "function";//true

JavaScript中的变量是没有类型的。只有值才有。变量可以随时持有任何类型的值。

在对变量执行typeof操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类型,因为JavaScript中的变量没有类型。

var a = 42;
typeof a;//"number" a = true;
typeof a;//"boolean" //因为typeof 42返回"number"
typeof typeof 42;//"string"

2.值

2.1 数组

在JavaScript中,数组可以容纳任何类型的值,可以是字符串、数字、对象(object),甚至是其他数组。

var a = [1,"2",[3]];

a.length;//3
a[0] === 1;//true
a[2][0] === 3;//true

对数组声明后即可向其中加入值,不需要预先设定大小。

var a = [];

a.length;//0

a[0] = 1;
a[1] = "2";
a[2] = [3]; a.length;//3

使用delete运算符可以将单元从数组中删除,但是要注意,单元删除后,数组的length属性并不会发生变化。

var a = [];

a[0] = 1;
a[2] = [3]; a[1];//undefined a.length;//3

数组通过数字进行索引,但有趣的是它们也是对象,所以也可以包含字符串键值和属性,但这些并不计算在数组长度内:

var a = [];

a[0] = 1;
a["foobar"] = 2; a.length;//1
a["foobar"];//2
a.foobar;//2

如果字符串键值能够被强制类型转换为十进制数字的话,它就会被当作数字索引来处理。

var a = [];

a["13"] = 42;

a.length;//14

建议使用对象来存放键值/属性值,用数组来存放数字索引值。

2.2 字符串

JavaScript中的字符串和字符数组并不是一回事。

var a = "foo";
var b = ["f","o","o"]; a.length;//3
b.length;//3 a.indexOf("o");//1
b.indexOf("o");//1 a;//"foo"
b;//["f","o","o"] a[1] = "0";
b[1] = "0"; a;//"foo"
b;//["f","0","o"]

JavaScript中字符串是不可变的,而数组是可变的。

a[1]在JavaScript中并非总是合法语法,正确的方法应该是a.charAt(1)

字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。

许多数组函数用来处理字符串很方便(字符串没有这些函数)。

var a = "foo";
var b = ["f","o","o"]; a.join;//undefined
a.map;//undefined var c = Array.prototype.join.call(a,"-");
var d = Array.prototype.map.call(a,function(v){
return v.toUpperCase() + ".";
}).join(""); c;//"f-o-o"
d;//"F.O.O."

2.3 数字

number(数字),包括"整数"和带小数的十进制数。

数字的语法

var a = 0.42;
var b = .42;
var c = 42.0;
var d = 42.;

特别大的特别小的数字默认用指数格式显示。

var a = 5E10;
a;//50000000000
a.toExponential();//"5e+10" var b = a*a;
b;//2.5e+21 var c = 1/a;
c;//2e-11
var a = 42.59;

a.toFixed(0);//43
a.toFixed(1);//42.6
a.toFixed(2);//42.59
a.toFixed(3);//42.590
a.toFixed(4);//42.5900 a.toPrecision(1);//4e+1
a.toPrecision(2);//43
a.toPrecision(3);//42.6
a.toPrecision(4);//42.59

但是下面的语法是有效的(请注意其中的空格):

2.4 特殊数值

undefined类型只有一个值,即undefined。null类型也只有一个值,即null

null指空值。

undefined指没有值。

null是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。

undefined是一个标识符,可以被当作变量来使用和赋值。

我们通过void运算符即可得到undefined这个值。

var a = 42;

console.log(void a, a);//undefined 42

按惯例我们用void 0来获得undefined。void 0、void 1和undefined之间并没有实质上的区别。

特殊的数字

如果数学运算的操作数不是数字类型,就无法返回一个有效的数字,这种情况下返回值为NaN

var a = 2/"foo";//NaN

typeof a === "number";//true

NaN仍然是数字类型。

NaN用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”。

var a = 2/"foo";

a == NaN;//false
a === NaN;//false

NaN是一个特殊值,它和自身不相等,是唯一一个非自反的值。

可以使用内建的全局工具函数isNaN(..)来判断一个值是否是NaN。

NaN是JavaScript中唯一一个不等于自身的值。

if(!Number.isNaN){
Number.isNaN = function(n){
return n != n;
};
}
无穷数
var a = 1/0;//Infinity
var b = -1/0;//-Infinity

JavaScript的运算结果有可能溢出。

规范规定,如果数学运算的结果超出处理范围,则由IEEE754规范中的“就近取整”模式来决定最后结果。

计算结果一旦溢出为无穷数就无法再得到有穷数。换句话说,就是你可以从有穷走向无穷,但无法从无穷回到有穷。

无穷除以无穷(Infinity/ Infinity)是一个未定义操作,结果为NaN

零值
var a = 0/-3;//-0
var b = 0*-3;//-0

加法和减法运算不会得到负零。

根据规范,对负零进行字符串化会返回"0":

var a = 0/-3;
a.toString();//"0"
a + "";//"0"
String(a);//"0"
JSON.stringify(a);//"0"
+"-0";//-0
Number("-0");//-0
JSON.parse("-0");//-0
var a = 0;
var b = 0/-3; a == b;//true
-0 == 0;//true
a === b;//true
-0 === 0;//true //区分-0和0
function isNegZero(n){
n = Number(n);
return (n === 0)&&(1/n === -Infinity);
} isNegZero(-0);//true
isNegZero(0/-3);//true
isNegZero(0);//false

特殊的等式

ES6中新加入了一个工具方法Object.is(..)来判断两个值是否绝对相等。

var a = 2/"foo";
var b = -3*0; Object.is(a,NaN);//true
Object.is(b,-0);//true Object.is(b,0);//false

能使用=====时就尽量不要使用Object.is(..),因为前者效率更高,更为通用。Object.is(..)主要用来处理那些特殊的相等比较。

2.5 值和引用

var a = 2;
var b = a;//b是a的值的一个副本
b++;
a;//2
b;//3 var c = [1,2,3];
var d = c;//d是[1,2,3]的一个引用
c;//[1,2,3,4]
d;//[1,2,3,4]

简单值总是通过值复制的方式来赋值/传递,包括null、undefined、字符串、数字、布尔和ES6中的symbol。

复合值——对象(包括数组和封装对象)和函数,则总是通过引用复制的方式来赋值/传递。

var a = [1,2,3];
var b = a;
a;//[1,2,3]
b;//[1,2,3] b = [4,5,6]
a;//[1,2,3]
b;//[4,5,6] //由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向。
function foo(x){
x.push(4);
x;//[1,2,3,4] x = [4,5,6];
x.push(7);
x;//[4,5,6,7]
} var a = [1,2,3]; foo(a);
a;//[1,2,3,4] //我们不能通过引用x来更改引用a的指向,只能更改a和x共同指向的值。
function foo(x){
x.push(4);
x;//[1,2,3,4] x.length = 0;
x.push(4,5,6,7);
x;//[4,5,6,7]
} var a = [1,2,3]; foo(a);
a;//[4,5,6,7] /*
function foo(wrapper){
wrapper.a = 42;
} var obj = {
a : 2
}; foo(obj);
obj.a;//42
*/ /*
function foo(x){
x = x + 1;
x;//3
} var a = 2;
var b = new Number(a);//Object(a)也一样 foo(b);
console.log(b);//2
*/

我们无法自行决定使用值复制还是引用复制,一切由值的类型来决定。

参考资料:《你不知道的JavaScript》(中卷) 第一部分 前两章

JS的类型和值的更多相关文章

  1. lua 基础 2 类型和值

    -- 类型 和 值--[[ 8中类型 滚动类nil.boolean. number.string.userdata.function.thread 和 table.]] print (type(&qu ...

  2. js基本数据类型和typeof

    JavaScript数据类型是非常简洁的,它只定义了6中基本数据类型 null:空.无.表示不存在,当为对象的属性赋值为null,表示删除该属性 undefined:未定义.当声明变量却没有赋值时会显 ...

  3. 判断js数据类型和clone

    判断返回js数据类型 function judgeType(arg){//判断返回js数据类型 return Object.prototype.toString.call(arg).slice(8,- ...

  4. 02深入理解C指针之---指针类型和值

    该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. 1.指针的类型: 可以在声明指针时,指定指针的类型,例如: (1)void *x  声 ...

  5. js中Boolean类型和Number类型的一些常见方法

    Boolean类型 Boolean类型重写了valueOf() 方法, 返回基本布尔类型值true或false,重写了toString() 方法,返回基本字符串"true" 和 & ...

  6. AngularJs:String类型和JSON相互转换

    最近一周做了一个页面,制作的过程中遇到各种问题,从中可以看出本人的js基础还不够扎实,angularjs也只是刚入门的水平,现在将制作过程中遇到的问题一一汇总,方便以后查阅. 一.String类型和J ...

  7. 数据类型和typeof操作符

    虽然学习js有一段时间了,但是对js的基础语法却是有些生疏.最近在看jquery源码,决定随带总结一些基础的语法知识.今天总结一下数据类型和typeof,这在写js的时候,是不得不知道的知识. 数据类 ...

  8. 一个重构的js分页类

    // JavaScript Document /**//** * js分页类 * @param iAbsolute 每页显示记录数 * @param sTableId 分页表格属性ID值,为Strin ...

  9. js监听输入框值的即时变化onpropertychange、oninput

    js监听输入框值的即时变化onpropertychange.oninput 很多情况下我们都会即时监听输入框值的变化,以便作出即时动作去引导浏览者增强网站的用户体验感. // //   要达到的效果 ...

随机推荐

  1. 使用maven&&make-distribution.sh编译打包spark源码

    1>基础环境准备: jdk1.8.0_101 maven 3.3.9scala2.11.8 安装好上述软件,配置好环境变量,并检查是否生效. 2>配置maven:intellij idea ...

  2. 分布式消息队列RocketMQ与Kafka架构上的巨大差异

    分布式消息服务 Kafka 是一个高吞吐.高可用的消息中间件服务,适用于构建实时数据管道.流式数据处理.第三方解耦.流量削峰去谷等场景,具有大规模.高可靠.高并发访问.可扩展且完全托管的特点,是分布式 ...

  3. 机器学习算法 --- Naive Bayes classifier

    一.引言 在开始算法介绍之前,让我们先来思考一个问题,假设今天你准备出去登山,但起床后发现今天早晨的天气是多云,那么你今天是否应该选择出去呢? 你有最近这一个月的天气情况数据如下,请做出判断. 这个月 ...

  4. Vue 入门之组件化开发

    Vue 入门之组件化开发 组件其实就是一个拥有样式.动画.js 逻辑.HTML 结构的综合块.前端组件化确实让大的前端团队更高效的开发前端项目.而作为前端比较流行的框架之一,Vue 的组件和也做的非常 ...

  5. C++:构造函数2——拷贝构造函数

     前言:拷贝构造函数是C++中的重点之一,在这里对其知识进行一个简单的总结. 一.什么是拷贝构造函数 在C++中,对于内置类型的变量来说,在其创建的过程中用同类型的另一个变量来初始化它是完全可以的,如 ...

  6. iOS学习资源搜集

    swift 2.0 新的开始 iOS7初学者入门 斯坦福大学公开课:iOS 8开发 苹果官方开发 中文 iOS/Mac 开发博客列表    git

  7. 冲刺One之站立会议4 /2015-5-17

    今天我们继续了昨天未完成的部分,把服务器端的在线人数显示做了出来,但是在调试的时候还有一些不可预知的自己也不会改的bug,让我们有点不知所措,启动时间的显示相对来说比较容易实现. 燃尽图4

  8. P2P通讯原理

    1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...

  9. c++工厂模式(Factory method)

    下面以女娲造黑人,白人,黄种人的例子来介绍一下工厂模式. 1.工厂的接口,相当于造人工厂总部. class IHumanFactory { public: IHumanFactory(void) { ...

  10. Sprint--5.21

    看到作业要求组长就召开小组成员开了一个简短的会议,会议内容大致是这样的: 1.再次明确任务:就是每一个人都要清楚知道自己扮演的角色应该做些什么,怎么去做: 2.组长定时更新博客,每一位小组成员也要写进 ...