一个前端开发者的救赎之路——JS基础回顾(一)

115 阅读7分钟

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):

  1. 基本数据类型 number、string、boolean、undefined、null
  2. 引用数据类型 object、array、function...、Date...

null和undefined有什么区别

  1. undefined
    • undefined表示一个未定义的值
    • typeof undefined => 'undefined'
    • Number(undefined) => NaN
  2. null
    • 表示一个空值(未来可能是一个object)
    • typeof null => 'object'
    • Number(null) => 0
  3. 《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",以便开发者更容易区分函数和其他对象。

类型强制转换

  1. 强制转换成number
    • Number(): 转换不了‘123abc’,结果会是NaN
    • parseInt(): 转换不了浮点数,parseInt(12px)=>12
    • parseFloat(): 可以转换浮点型,也可以转换'12.3px'
  2. 强制转换为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]'
  1. 强制转换为布尔值
    • Boolean(): 除了0,false,'',undefined,null,NaN,其他的全是true
    • 试一试
Boolean([])
true
Boolean({})
true
  1. 《JavaScript权威指南》关于类型转换还有一些补充
    • Number类定义的toString()方法还可以接受一个可选地参数,用于指定一个基数或底数。例如:n.toString(2)就意味着把n转换为2进制的
    • toFixed()把树枝转换成字符串时可以指定小数点后的位数
    • parseInt和parseFloat,如果第一个非空字符不是有效的数值字面量,它们会返回NaN
  2. 在正式代码中,避免依赖隐式转换,尽量显式处理类型

关于数组转换成字符串的说法

表达式结果原因
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规范定义了三种对象到原始值的基本算法

  1. 偏字符串: 该算法返回原始值,而且只要可能就返回字符串
  2. 偏数值: 该算法返回原始值,而且只要可能就返回数值
  3. 无偏好: 该算法不倾向于任何原始值类型,而是由类定义自己的转换规则。
  4. JavaScript内置对象除了Date类都实现了偏数值算法。Date类实现了偏字符串算法

逻辑运算符

 1. 逻辑与 (&&)

  • 语法expr1 && expr2
  • 功能: 如果第一个表达式(expr1)可以转换为true,则返回第二个表达式(expr2)的值;否则返回第一个表达式(expr1)的值
  • 真值表:
expr1expr2结果
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

2. 逻辑或(||)

  • 语法expr1 || expr2

  • 功能: 如果第一个表达式(expr1)可以转换为true,则返回第一个表达式的值;否则返回第二个表达式的值

  • 真值表:

    expr1expr2结果
    truetruetrue
    truefalsetrue
    falsetruetrue
    falsefalsefalse

(3) 逻辑非 (!)

  • 语法!expr

  • 功能: 返回表达式相反的逻辑值

  • 真值表:

    expr结果
    truefalse
    falsetrue

(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
  • 功能
    1. 首先计算 condition 表达式的值
    2. 如果 condition 为真值(truthy),则计算并返回 exprIfTrue 的结果
    3. 如果 condition 为假值(falsy),则计算并返回 exprIfFalse 的结果
  • 注意: 三目运算符最多嵌套两层,别无限嵌套