你不知道的JavaScript(中)

1 类型

1.1 js有七种内置类型

1 undefined 2 boolean 3 number 4 string 5 object 6 null 7 symbol

  • typeof undefined === "undefined"
  • typeof true === "boolean"; // true
  • typeof 42 === "number"; // true
  • typeof "42" === "string"; // true
  • typeof { life: 42 } === "object"; // true
  • typeof Symbol() === "symbol"; // true

但是null稍微特殊
typeof null === "object"; // true
所以如果检测一个值是否为null,需要
var a = null;
(!a && typeof a === "object"); // true

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

换个角度来理解就是,JavaScript 不做”类型强制“。
在对变量执行 typeof 操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类
型,因为 JavaScript 中的变量没有类型。

1.3 undefined && undeclared

undefined 是值的一种。undeclared 则表示变量还没有被声明过。
遗憾的是,JavaScript 却将它们混为一谈,在我们试图访问 "undeclared" 变量时这样报
错:ReferenceError: a is not defined,并且 typeof 对 undefined 和 undeclared 变量都返回
"undefined"。

typeof undefined == "undefined"
typeof undeclared == "undefined"

2 值

简单值(即标量基本类型值,scalar primitive)总是通过值复制的方式来赋值 / 传递,包括
null、undefined、字符串、数字、布尔和 ES6 中的 symbol。
复合值(compound value)——对象(包括数组和封装对象,参见第 3 章)和函数,则总 是通过引用复制的方式来赋值 / 传递。

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]的一个引用
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]

在上述代码中,a,b分别指向 值 的两个复本。a,b的改变互不影响。
c,d分别指向 值 的两个引用,而引用都指向同样的一个对象 [1,2,3],所以c,d的改变是对于所指对象的改变。

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],不是[4,5,6,7]

其中,a将 [1,2,3]的引用的复本,传给了变量x。变量x 指向 对象[1,2,3]的引用的复本,可以修改其值。
随后,变量x指向 更改为[4,5,6]的引用,这一操作并不会影响a的引用。

3 原生函数

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol()——ES6 中新加入的!

3.1

new String("abc") 创建的是字符串 "abc" 的封装对象,而非基本类型值 "abc"。

var a = new String( "abc" );
typeof a; // 是"object",不是"String"
a instanceof String; // true
Object.prototype.toString.call( a ); // "[object String]"

3.2 内部属性 [[Class]]

这个属性无法直接访问,
一般通过 Object.prototype.toString(..) 来查看。例如:

Object.prototype.toString.call( [1,2,3] ); // "[object Array]"
Object.prototype.toString.call( /regex-literal/i ); // "[object RegExp]"

4 强制类型转换

4.1 值类型转换

将值从一种类型转换为另一种类型通常称为类型转换(type casting),这是显式的情况;隐式的情况称为强制类型转换(coercion)。
也可以这样来区分:类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时(runtime)。
然而在 JavaScript 中通常将它们统称为强制类型转换,我个人则倾向于用“隐式强制类型
转换”(implicit coercion)和“显式强制类型转换”(explicit coercion)来区分。

例如:
var a = 42;
var b = a + ""; // 隐式强制类型转换
var c = String( a ); // 显式强制类型转换

4.2 抽象值操作

  1. toString
  2. toNumber
    其中 true 转换为 1,false 转换为 0。undefined 转换为 NaN,null 转换为 0。
    对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
    为了将值转换为相应的基本类型值,抽象操作 ToPrimitive会首先检查该值是否有 valueOf() 方法。
    如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString()的返回值(如果存在)来进行强制类型转换。
    如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
  3. toBoolean
    以下为假值:
    • undefined
    • null
    • false
    • +0、-0 和 NaN
    • ""

4.3 显式强制类型转换

  1. 字符串和数字之间的显式转换
    1. 运算符的一元形式
    var a = "123"
    var b = +a // 123  被转换为number
    
    2.奇特的 ~ 运算符
    var a = "Hello World";
    a.indexOf('H') // 0
    ~a.indexOf('H') // -1
    Boolean(~indexOf('H')) // true
    如果存在值,则indexOf为0或其余正数,那么~为负数,Boolean转换为true
    
    a.indexOf('123') // -1
    ~a.indexOf('H') // 0
    Boolean(~indexOf('H')) // false
    如果不存在值,则indexOf为-1,那么~为0,Boolean转换为false
    
    1. ~~字位截除
    var a = 3.14
    ~a // -4
    ~~ a // 3
    
    Math.floor( -49.6 ); // -50
    ~~-49.6; // -49
    
  2. 显式转换为布尔值
    显式强制类型转换为布尔值最常用的方法是 !! 而不是 Boolean

4.4 隐式强制类型转换

  1. 字符串和数字之间的隐式强制类型转换
var a = "42";
var b = "0";
var c = 42;
var d = 0;
a + b; // "420"
c + d; // 42

var a = [1,2];
var b = [3,4];
a + b; // 1,23,4

如果参与运算的对象是字符串,或者可以转换成字符串,则+进行字符串拼接操作。否则执行数字加法。
因此:a+b=“420”
当运算对象为对象时,调用ToPrimitive,调用valueOf 或者 toString,获取[[DefaultValue]]。
因此,数组[1,2]被转换为“1,2”“3,4”再进行字符串拼接。

var a = "3.14";
var b = a - 0;
b; // 3.14

- 是数字减法运算符,因此 a - 0 会将 a 强制类型转换为数字。
也可以使用 a * 1 和 a / 1,因为这两个运算符也只适用于数字,只不过这样的用法不太常见。
对象的 - 操作与 + 类似:
var a = [3];
var b = [1];
a - b; // 2
  1. 隐式强制类型转换为布尔值
    (1) if (..) 语句中的条件判断表达式。
    (2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
    (3) while (..) 和 do..while(..) 循环中的条件判断表达式。
    (4) ? : 中的条件判断表达式。
    (5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。

4.5 || &&

|| 和 && 首先会对第一个操作数执行条件判断,如果其不是布尔值就先进行 ToBoolean 强制类型转换,然后再执行条件判断。
对于 || 来说,如果条件判断结果为 true 就返回第一个操作数的值,如果为
false 就返回第二个操作数的值。

&& 则相反,如果条件判断结果为 true 就返回第二个操作数的值,如果为 false 就返回第一个操作数的值。
可以用a && foo() 代替 if(a) { foo() },简洁

var a = 42;
var b = null;
var c = "foo";
if (a && (b || c)) {
 console.log( "yep" );
}
在上述 if 中
1 b||c // “foo”
2 a && (b||c) // "foo"
3 if 隐式类型转换,将"foo"转为true

4.6 宽松相等和严格相等

== 允许在相等比较中进行强制类型转换,而 === 不允许。
== 和 === 都会检查操作数的类型。区别在于操作数类型不同时它们的处理方
式不同。

  1. 数字和字符串比较 字符串ToNumber
x = '42'
y = 1
x== y
首先将 ‘42’ 转为 42,转为number,再比较
返回false
  1. 布尔和其他类型比较 布尔值ToNumber
x = true
y = '42'
x == y
首先,true 转为 1,这样就是 1 == ‘42’
其次,‘42’ 转为 42,再比较
返回false
  1. 对象和非对象之间的相等比较
    (1) 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
    (2) 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
  2. 对象和对象的比较
    比较对象所指向的值,是否相等
  3. <=
在js中,a <= b
被转换为 !(a>b)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容