JavaScript由哪三部分组成:
- EcmaScript(只是一个标准) + DOM + BOM
JavaScript三种引入方式
// 行内js(不推荐)
<div onclick="alert('点击了div')"></div>
// 内嵌js
<script>
console.log('heelo world')
</script>
// 外联js
<script src="xxx.js"></script>
//需要注意的一个问题,一个<script>标签可以既做外联,又做内嵌吗?
<script src="xxx.js">
// 这里面的代码将不会执行
console.log('hello world')
</script>
JavaScript的三个Hello World!
// 页面显示(这里其实我们就操作了DOM,document是一个DOM对象)
document.write('Hello World!')
// 控制台输出
console.log('Hello World!')
// 弹框显示(这里我们就操作了BOM,alert是浏览器的一个内置API方法)
alert('Hello World!')
JavaScript有哪些数据类型(不含ES6):
- 基本数据类型 number、string、boolean、undefined、null
- 引用数据类型 object、array、function...、Date...
null和undefined有什么区别
- undefined
- undefined表示一个未定义的值
- typeof undefined => 'undefined'
- Number(undefined) => NaN
- null
- 表示一个空值(未来可能是一个object)
- typeof null => 'object'
- Number(null) => 0
- 《JavaScript权威指南》里面关于这两个类型有一段说法
- null和undefined都没有属性和方法,所以,只用.或[]访问这两个值的属性或方法会导致TypeError
- 我们可以用undefined表示一种系统级别、意料之外或类似错误的没有值,可以用null表示程序级别、正常或意料之中的没有值
typeof 判断数据类型
JavaScript里永远不缺神奇
- typeof null => 'object'
- typeof NaN => Number
- typeof {} => 'object'
- typeof [] => 'object'
- typeof console.log => 'function'
- 之前我也是张嘴就来typeof判断引用数据类型返回object,那这个function是怎么解释呢?
- 原因是
typeof对函数做了特殊处理,单独返回"function",以便开发者更容易区分函数和其他对象。
类型强制转换
- 强制转换成number
- Number(): 转换不了‘123abc’,结果会是NaN
- parseInt(): 转换不了浮点数,parseInt(12px)=>12
- parseFloat(): 可以转换浮点型,也可以转换'12.3px'
- 强制转换为String
- String(): 可以将一切值转换为String
- toString(): 可以转换number,boolean,但是转换不了null和undefined
- toString()转换null和undefined会报错,是因为
toString是原型方法,这两个家伙没有原型 - 下面代码是我随便输出着玩的
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(NaN) // 'NaN'
// 对象的输出是'[object Object]'
String({}) // '[object Object]'
// 我原以为这个应该是'[object Array]'
String([]) // ''
String([1]) // '1'
/**
* 这下面的两行好像也要解释解释
* 我觉得是这个函数没有返回值(我认为的对)
**/
String(console.log()) // 'undefined'
String(console.log(1)) // 'undefined'
/**
* 在 JavaScript 中,当你看到类似 `function log() { [native code] }` 的输出时,
* 这表示 `log` 是一个内置的 native 函数
*(由 JavaScript 引擎原生实现,而不是用 JavaScript 代码编写的)。
* 类似的还有`Array.map`、`Object.keys` 等
**/
String(console.log) // 'function log() { [native code] }'
// console为什么能打点调用log,这就很明了了,因为console是内置对象
String(console) // '[object console]'
- 强制转换为布尔值
- Boolean(): 除了0,false,'',undefined,null,NaN,其他的全是true
- 试一试
Boolean([])
true
Boolean({})
true
- 《JavaScript权威指南》关于类型转换还有一些补充
- Number类定义的toString()方法还可以接受一个可选地参数,用于指定一个基数或底数。例如:n.toString(2)就意味着把n转换为2进制的
- toFixed()把树枝转换成字符串时可以指定小数点后的位数
- parseInt和parseFloat,如果第一个非空字符不是有效的数值字面量,它们会返回NaN
在正式代码中,避免依赖隐式转换,尽量显式处理类型。
关于数组转换成字符串的说法
| 表达式 | 结果 | 原因 |
|---|---|---|
String([]) | "" | 调用 Array.prototype.toString(),空数组返回空字符串 |
Object.prototype.toString.call([]) | "[object Array]" | 直接调用 Object 的 toString,返回类型标签 |
[].toString() | "" | 数组的 toString() 方法 |
String([1, 2, 3]) | "1,2,3" | 数组的 toString() 用逗号连接元素 |
数学运算符
这里边好像没有啥好说的吧
- 加号 + 遇到字符串就怂了
- 其他运算符可以做强制数值转换
1 + 2 = 3
1 + '2' = '12'
[] + [] = ''
{} + {} = NaN
{} + null = 0
[] + {} = '[object Object]'
{} + [] = 0
function a() {} + {} = NaN
function a() {} + [] = 0
null + undefined = NaN
undefined + [] = 'undefined'
{} + [] + [] = '0'
{} + [] + {} = '0[object Object]'
// 下面是一些 - 运算
[] - [] = 0
[] - [1] = -1
[] = {} = NaN
//如果 `{` 出现在行首或表达式开头,它会被解析为代码块(Block Statement),而不是对象字面量。
{} - [] = -0; {1} - null = -0
{} - null = -0
null - {} = NaN
- 关于上面的这些稀奇古怪的 '+', '-' 运算,大家有兴趣的话,自己问下AI吧
- 还有一个运算符%(取余运算符),来个小例子吧
// 将1000分钟转换成hh:mm形式
var mins = 1000;
// 求小时
var h = parseInt(mins / 60);
// 求分钟
var m = mins % 60;
console.log(h + ':' + m);
赋值运算符
赋值运算符好像没什么稀奇古怪的,写个小算法吧,就是
- 不借助第三变量的情况下,交换a, b两个变量的值(ES5及以前的标准)
// 不借助第三变量的情况下,交换a, b两个变量的值(**ES5及以前的标准**)
var a = 1;
var b = 3;
a = a + b; // 1 + 3 = 4
b = a - b; // 4 - 3 = 1
a = a - b; // 4 - 1 = 3
// 下面用下别的运算符
a += b;
b = a - b;
a -= b;
JavaScript规范定义了三种对象到原始值的基本算法
- 偏字符串: 该算法返回原始值,而且只要可能就返回字符串
- 偏数值: 该算法返回原始值,而且只要可能就返回数值
- 无偏好: 该算法不倾向于任何原始值类型,而是由类定义自己的转换规则。
- JavaScript内置对象除了Date类都实现了偏数值算法。Date类实现了偏字符串算法
逻辑运算符
1. 逻辑与 (&&)
- 语法:
expr1 && expr2 - 功能: 如果第一个表达式(expr1)可以转换为
true,则返回第二个表达式(expr2)的值;否则返回第一个表达式(expr1)的值 - 真值表:
| expr1 | expr2 | 结果 |
|---|---|---|
| true | true | true |
| true | false | false |
| false | true | false |
| false | false | false |
2. 逻辑或(||)
-
语法:
expr1 || expr2 -
功能: 如果第一个表达式(expr1)可以转换为
true,则返回第一个表达式的值;否则返回第二个表达式的值 -
真值表:
expr1 expr2 结果 true true true true false true false true true false false false
(3) 逻辑非 (!)
-
语法:
!expr -
功能: 返回表达式相反的逻辑值
-
真值表:
expr 结果 true false false true
(4)两个特殊用法
-
短路操作
5 || 0; // 返回 5 (因为5是真值,返回第一个操作数) null || 5; // 返回 5 (因为null是假值,返回第二个操作数) 5 && 0; // 返回 0 (因为5是真值,返回第二个操作数) null && 5 // 返回 null (因为null是假值,返回第一个操作数) -
强制转换为布尔值
!!5 // 返回true
(5)优先级
-
|| 和 && 放在一起使用的时候,&& 的优先级高于||
自增自减运算符
区别
- 前置自增(减):++n, --n, 这种是先自增(减),再赋值
- 后置自增(减):m++,m--,这种是先赋值,再执行自增(减)
- 下面看下例子吧:
n = 10;
res = ++n + n-- + n++ + --n + n++;
/**
* 第一个n++:11
* 第二个先运算,这个时候应该是res = 11 + 11;然后n--就是10
* 第三步: res = 22 + 10 然后 n++就是11,我是这一步算错了,算成n--了
* 第四步:先--n是10,res = 32 + 10
* 最后一步:先res = 42 + 10,然后n++ = 11
**/
console.log(n, res); // 7, 48 还是算错了,真实的结果是11,52
三目运算符
- 语法:
condition ? exprIfTrue : exprIfFalse - 功能:
- 首先计算
condition表达式的值 - 如果
condition为真值(truthy),则计算并返回exprIfTrue的结果 - 如果
condition为假值(falsy),则计算并返回exprIfFalse的结果
- 首先计算
- 注意: 三目运算符最多嵌套两层,别无限嵌套