您的位置:首页 > Web前端 > JavaScript

《你不知道的JavaScript 中卷》

2017-01-15 21:50 113 查看


慢慢的,敢说自己懂 JS 了,坐等下卷

变量是没有类型的,只有值才有

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

类型是值的内部特征,它定义了值的行为。

所有的值都对应一个类型,JS 有 7 种内置类型

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


typeof 查看值的类型

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


有一个特殊的

typeof null === 'object'


这是个 BUG。

函数和数组也是对象

typeof function a(){} === 'function'


但函数(function)并不是一个内置类型,它是 object 的一个『子类型』。它有一个内部属性[[call]],该属性使其可以被调用,函数是『可调用对象』。

typeof [1, 2, 3] === 'object'


数组也是 object 的一个『子类型』。数组的元素按数字顺序来进行索引(普通对象是通过字符串键值)。

undefined 和 undeclared

var a;
a; // undefined
b; // ReferenceError: b is not defined


a
的值是
undefined
b
报错,但报错信息可能会误导人,
not defined
并不是
undefined
,而是
undeclared
,直接使用
undeclared
的变量会报错,然而,有一个特殊情况

var a;
typeof a; // "undefined"
typeof b; // "undefined"


typeof b
没有报错,而是返回字符串
undefined


访问不存在的对象属性也不会产生
ReferenceError
错误。

没有真正意义上的整数

JavaScript 只有一种数值类型:number。

没有真正意义上的整数

42.0 === 42; // true


数字前面的 0 可以省略

var a = 0.42;
var b = .42;


小数部分最后面的 0 也可以省略

var a = 42.0;
var b = 42.;


默认情况下大部分数字都以十进制显示,小数部分后面的 0 被省略

var a = 42.3000;
var b = 42.0;
a; // 42.3
b; // 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


数字常量也可以用
.
运算符,但
.
是一个有效的数字字符,会被优先识别为数字常量的一部分,然后才是对象属性访问运算符

42.toFixed(3); // SyntaxError,`.`被视为数字的一部分,所以没有属性访问运算符

// 下面的语法都有效
(42).toFixed(3);
0.42.toFixed(3);
42..toFixed(3); // 第一个`.`是数字的一部分,第二个`.`是属性访问运算符


十六进行

oxf3;
oXf3;


八进制

0363;


ES6 严格模式不再支持上面的八进制形式,而是

0o363;
0O363;


ES6 还有二进制

ob11110011;
oB11110011;


值复制(value-copy)和引用复制(reference-copy)

简单值(包括 null、undefined、字符串、数字、布尔和 symbol)总是通过值复制(value-copy)的方式来赋值/传递;

复合型(对象,包括数组、函数、封装对象)总是通过引用复制(reference-copy)的方式来赋值/传递。

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

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
持有 2 的一个副本,
b
持有 2 的另一个副本;

c
d
是指向 [1, 2, 3] 的两个不同的引用(不是持有)。

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]


其实,
值复制
就是复制值,
引用复制
就是复制引用。

没想到 parseInt 也有幺蛾子

parseInt(false, 16); // 250


parseInt 第一个参数要求是字符串,如果不是,则先转成字符串 ‘false’,按 16 进制解析为 fa = 250

|| 和 &&并不是返回判断结果

这个有点震惊,以前没有注意过,返回的是操作数中的其中一个

a || b 的意思是

a ? a : b


a && b 的意思是

a ? b : a


比闭包还疯狂的来了 ——宽松相等

看了下面的运行结果才能体会到有多疯狂

if ([0]) {console.log('true')} // true
if ([0] == false) {console.log('true')} // true


第一行可以理解,因为 [0] 转成布尔就是 true,但是第二行呢?

根源就在于宽松相等 == 会发生类型转换,转换的规则是

布尔转数字
字符串转数字
对象转数字(valueOf())或字符串(toString())
null == undefined
null !== undefined


所以,就可以理解第二行代码了,
[0] == false
中的
[0]
不是转成布尔 true,而是转成数字 0,右边的
false
转成数字 0,所以
[0] == false
的结果是 true。

但是有一个例外,也就是空字符串会转成数字 0

0 == ''; // true


和宽松相等一起疯狂的还有<、>、<=、>=

非字符串或数字会先转换成字符串或数字

var a = {b: 42};
var b = {b: 43};

a == b; // false
a > b; // false
a < b; // false

a <= b; // true
a >= b; //true


==
时并不发生转换,所以
a == b
返回 false;

>
<
时 a 和 b 都转换成字符串
[object Object]
,所以都返回 false;

问题是
a <= b
a >= b
为什么返回 true,因为这里有个奇葩的地方

<= 的意思不是"小于等于",而是"不大于",即 > 的结果取反
>= 同样


语句的返回值

var a = 3; // undefined
a = 3; // 3


所以,有下面这个样的赋值

var a = b = c = 3;


你以为的 else if 并不是 else if

if 只有一条语句时可以省略大括号

if (a) {

} else if (b) {

} else {

}


实际是

if (a) {

} else {
if (b) {

} else {

}
}


所以,你以为的 else if 并不是 else if

switch 中的比较是严格相等

var a = 42;
switch(a) {
case '42':
console.log('42!==\'42\'');
break;
case 42:
console.log('42===42');
break;
}
// 42===42
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: