你不知道的JavaScript之类型和值

类型和值

定义

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

更精确的定义
类型是值的内部特征,它定义了值的行为,以使其区别于其他值。

string.proto === String => true
string instanceof String => false

内置类型

  • null -- 空值
  • undefined -- 未定义
  • string -- 字符串
  • number -- 数字
  • object -- 对象
  • boolean -- 布尔值
  • symbol -- es6 符号

typeof 操作符
typeof undefined // 'undefined'
typeof string // 'string'
typeof number // 'number'
typeof object || array // 'object'
typeof boolean // 'boolean'
typeof function // 'function'
typeof symbol // 'symbol'
typeof null // 'object'

typeof String || Number || Object || Function || Boolean || Array // function

Boolean(false) => boolean false
new Boolean(false) => object true

if (Boolean(false)) {
  // 不会执行里面的代码
}

if (new Boolean(false)) {
  // 会执行里面的代码,此时条件为 {} => 转换为 boolean 为true
}

如何把一个值转转变为布尔类型 => !!value

值和类型

JavaScript 中的变量是没有类型的,只有值才有。变量可以随时持有任何类型的值。
换个角度来理解就是, JavaScript 不做“ 类型强制”;也就是说,语言引擎不要求变量总是
持有与其初始值同类型的值。一个变量可以现在被赋值为字符串类型值,随后又被赋值为
数字类型值。(typescirpt 让我们更写代码具备静态特性,类型声明)
在对变量执行 typeof 操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类
型,因为 JavaScript 中的变量没有类型。

undefined && undeclared

undefined: 变量未持有值 => 未找到变量的值(right查询)

var a
console.log(a)  // undefined

undeclared: 变量未定义 => 未找到变量(left查询)

console.log(a)  // Uncaught ReferenceError: a is not defined

不合理的行为:typeof undefined === typeof undeclared // true undefined
typeof 俗称安全操作符,它的使用尽量不让程序报错,即使访问未声明的变量

number Number 相关 number 是 Number 的子类型

Boolean()  // 0
Boolean(-'')  // -0
Boolean('')  // 0
1 / ''  // Infinity
1 / -'' // -Infinity

一些判断

  • 判断一个值是否是空对象或者空数组
var foo = {}
foo === {}  // false 因为{} 是引用值,前面和后面的指向的不是一个地址,
JSON.stringify(foo) === '{}'  // true
  • 判断一个值是否为 null
function isNull(value) {
  return !value && typeof value === 'object'
}
  • 判断一个值是否是 NaN (非数)
// 写在 Number 调用方式 Number.isNaN()
if (!Number.isNaN) {
  Number.isNaN = function (num) {
    // 根据 NaN 六亲不认的特征,即 NaN 不等于自身
    return num !== num
  }
}
// 写在 Number 的原型上 调用方式 number.isNaN()
if (!Number.prototype.isNaN) {
  Number.prototype.isNaN = function () {
    return this !== this
  }
}

数组

和其他强类型语言不同,在 JavaScript 中,数组可以容纳任何类型的值,可以是字符串、
数字、对象( object),甚至是其他数组(多维数组就是通过这种方式来实现的)。

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

稀疏数组

var arr = []
arr.length = 5  // [empty x 5]
arr[1]  // undefined

arr = [1, 2, 3]
delete arr[1]  // [1, empty, 3]
arr[1]  // undefined

数组通过数字进行索引,但有趣的是它们也是对象,所以也可以包含字符串键值和属性,如果字符串键值能够被强制类型转换为十进制数字的话,它
就会被当作数字索引来处理。

arr = []
arr[10] = 10  // [empty x 10, 10]

不要这样做。

类数组 -- 通过类名选择的 Dom 集合; jquery() 返回的值集合;函数的实参列表 arguments

类数组转化为数组方法

  • 借用 Array.prototype.slice
let arrayLike
let array = Array.prototype.slice.call(arrayLike)
  • ES6 Array.from()
let obj = {
  a: 'a',
  b: 'b'
}
let arr = Array.from(obj)  // []

字符串

字符串和数组的确很相似,它们都是类数组,都有 length 属性以及 indexOf(..)(从 ES5
开始数组支持此方法)和 concat(..) 方法。
注:不管是数组,还是字符串,concat() 都不会改变原来的数组,而是返回一个新数组

JavaScript 中字符串是不可变的,而数组是可变的。并且 a[1] 在 JavaScript 中并非总是合
法语法,在老版本的 IE 中就不被允许(现在可以了)。 正确的方法应该是 a.charAt(1)。

var foo = 'foo'
foo[1]  // o
foo.charAt(1)  // o

字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符
串。而数组的成员函数都是在其原始值上进行操作。

// 转化为大写形式
var lowerCase = 'hello world'
lowerCase.toUpperCase()  // 'HELLO WORLD',不会改变原字符串,需要重新定义一个变量接收

许多数组函数用来处理字符串很方便。虽然字符串没有这些函数,但可以通过“借用”数
组的非变更方法来处理字符串:

// join map
Array.prototype.join.call()
Array.prototype.map.call(, function (ele, index) {})

问题:如何实现字符串的翻转?

数字 number => Number

JavaScript 只有一种数值类型: number(数字),包括“整数”和带小数的十进制数。

数字语法:

  • JavaScript 中的数字常量一般用十进制标识
  • 小数点前面的 0 可以省略 (css同样可以省略,可以有效减少文件体积)
  • 小数点后面的 0 可以省略

一些方法:

  • toFixed() -- 采取四舍五入的规则,保留几位小数(不改变原数值,返回一个新值)
var num = 42.45
num.toFixed(1)  // 42.5

var num = 42
num.toFixed(5)  // 42.00000 => 无效的语法
  • Number.isInteger() -- 判断一个数是否是整数,可以传入其他类型的值,返回 false
Number.isInteger(43)  // true
Number.isInteger('')  // false

// polyfill
if (Number.isInteger) {
  Number.isInteger = function (num) {
    // 如果使用 typescript 启用类型检查就不要作前面的 typeof 判断
    return typeof num === 'number' && num % 1 === 0
  }
}

特殊数值

undefined && null

undefined 类型只有一个值,即 undefined。 null 类型也只有一个值,即 null。它们的名
称既是类型也是值。
null 是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。然而
undefined 却是一个标识符,可以被当作变量来使用和赋值。

区别:

  • null 指空值( empty value),undefined 指没有值( missing value)
  • null 指曾赋过值,但是目前没有值,undefined 指从未赋值
  • 非严格模式下,可以把 undefined 当做标识符一样使用
undefined = true  // 不要这样做

'use strict'
undefined = true  // TypeError
null === 0  // false
null > 0  // false
null < 0  // false

undefined === 0  // false
undefined > 0  // false
undefined < 0  // false

// 似乎发现了什么不得了的事...
null == undefined  // true
// but
null === undefined  // false

void 运算符 -- 后面接任何值,返回 undefined

void 1  // undefined
void {}  // undefined
void []  // undefined
void 1+1  // NaN  为什么?
void '1'+'2'  // 'undefined2'   这就是原因!

特殊的数字

不是数字的数字 NaN

NaN 是一个“警戒值”( sentinel value,有特殊用途的常规值),用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”。

  • window.isNaN
window.isNaN(NaN)  // true
window.isNaN(1/{})  // true
window.isNaN({})  // true
window.isNaN([])  // true
// 缺陷,不管是 NaN 还是除数值以外的类型,都返回 true

更准确的说法:isNaN() 检查参数是否不是 NaN,也不是数字

  • ES6 Number.isNaN() -- 判断是否是 NaN
Number.isNaN(NaN)  // true
Number.isNaN(1/{})  // true
Number.isNaN({})  // false
Number.isNaN([])  // false
// polyfill
if (Number.isNaN) {
  // 配合 typeof 食用
  Number.isNaN = function (value) {
    return typeof value === 'number' && window.isNaN(value)
  }
  // NaN 不等于自身
  Number.isNaN = function (value) {
    return value !== value
  }
}

无穷数 Infinity

1/0  // Infinity
-1/0  // -Infinity
Infinity / -Infinity  // NaN

零值 0 && -0

0 === -0  // true

特殊的等式 ===

ES6 Object.is(a, b) => 判断两个值是否绝对相等

Object.is(0, -0)  // false
// polyfill
if (!Object.is) {
  Object.is = function (left, right) {
    if (left === 0){
    if (right === -0) {
      return false
    }
  } else if (left === -0) {
    if (right === 0) {
      return false
    }
  }
  }
  return left === right
}

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

值和引用

在许多编程语言中,赋值和参数传递可以通过值复制(value-copy)或者引用复制(reference-copy)来完成。
JavaScript 中没有指针,引用的工作机制也不尽相同。在 JavaScript 中变量不可能成为指向
另一个变量的引用。
JavaScript 引用指向的是值。如果一个值有 10 个引用,这些引用指向的都是同一个值, 它
们相互之间没有引用 / 指向关系。
JavaScript 对值和引用的赋值 / 传递在语法上没有区别,完全根据值的类型来决定。

  • 简单值(即标量基本类型值, scalar primitive) 总是通过值复制的方式来赋值 / 传递,包括null、 undefined、字符串、数字、布尔和 ES6 中的 symbol。
var a = 2
var b = a
b ++
a  // 2
b  // 3

var a = [1, 2, 3, 4]
var b = a
b.push(5)
/**
 * a和b只是指向值[...],并非持有该值
 * a和b通过地址指向值
 * 赋值的过程仅仅是引用地址的复制,而不是真实值的复制
 */
a  // [1, 2, 3, 4, 5]
b  // [1, 2, 3, 4, 5]
  • 复合值( compound value)——对象(包括数组和封装对象,参见第 3 章)和函数,则总是通过引用复制的方式来赋值 / 传递。
    基本类型的值,变量指向的是具体的值;引用类型的值,变量指向的是该值的地址,赋值给其他变量的时候,只是复制了地址过去,其他变量依然通过地址找到值,操作值的话也是通过地址找到这个值,所以操作的还是存储的值。

特殊情况

var a = [1, 2]
// 通过引用地址指向 [1, 2]
var b = a
// 给 b 重新赋值,不会对 a 造成影响
// 由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向?
b = [2, 3]

a  // [1, 2]
b  // [2, 3]

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352