# 编写高质量 JavaScript 代码

effactive-js

这篇文章会介绍编写 javaScript 中会用到的一些高质量代码建议。这是我在读《Effective JavaScript》 之后记下的笔记。

# 1. 判断 NaN

NaN 不等于本身,提供的 isNaN 方法无法判断是否为 NaN,需要我们重写。


isNaN(NaN)     // true
isNaN("foo")   // true
isNaN({})      // true

// 重写
const  isNaN = (v) =>  v !== v

# 2. 关于 toString 方法

Math.toSring() // [object Math]
JSON.toSring() // [object JSON]

"Java" + {toString:  function() {return  "Script"}} // JavaScript
const o = {
    toSting: function () {
        return "[object MyObject]"
    },
    valueOf: function () {
        return "Script"
    }
}

"Java" + o // JavaScript

由此可以看出,先调用 toStirng 方法,之后调用 valueOf 方法。

# 3. 基本类型优于对象

let  s = new  String("hello")

typeof  s        // object
typrof  "hello"  // string
s == "hello"     // false

# 4. 不要使用 == 运算符

首先要知道, == 存在隐式类型转换, === 不存在隐式类型转换。

null == undefined  // true
null === undefined // false

# 5. 适当使用 || 和 &&


function foo(x, y) {
    x = x || 0
    y = y || 0
}

let foo = null

// bad
let name = foo.name                    // 报错

// good
let name = foo && foo.name             // undefinde

// bast
let name = (foo && foo.name) || "bar"  // bar

# 6. 对于编码

为了在计算机中显示世界上所有的文字,为每一个字符分配了一个唯一整数,介于 0 ~ 1114111 之间,这就是 Unicode。

Unicode 编码中,16 位二进制数表示一个字符,JavaScript 字符串也是 16 位的二进制数,这就是变量可以取中文名的原因。

"h"
0x0068

# 7. 闭包

关于闭包记住三点:

(1) JavaScript 允许访问当前函数以外的变量;

function foo() {
    let count = 2

    function add(n) {
        return n + count
    }
    return add(2)
}

foo() // 4

(2) 即使已经运行结束,可以保存局部变量,在外部可以访问。

function foo(init) {
    let count = init

    function add(n) {
        count += n
        return n + count
    }
    return add
}

let bar = foo(5)
console.log(bar(2)) // 7
console.log(bar(2)) // 9
console.log(bar(2)) // 11

(3) 可更新外部变量的值

function foo() {
    let num = undefined
    return {
        set: (val) => (num = val),
        get: () => count,
    }
}
let bar = foo(5)
console.log(bar.get())    // undefined
console.log(bar.set(123)) // 123
console.log(bar.get())    // 123

# 8. 不要修改 arguments 对象

function foo(name, method) {
    let shift = [].shift()
    shift.call(arguments)
    shift.call(arguments)
    console.log(name, method) // 1 2
}

foo('bar', 'add', 1, 2)

这是由于 name 保存的是 arguments[0],我们修改了 arguments[0] 之后, name 也跟随变化,它是 arguments[0] 的引用。

# 9. 判断数组,对象是否为空

let arr = []

arr.length === 0 // true
arr.toString() === "" // true

判断对象是否为空:

let obj = {}
Object.keys(obj).length === 0 // true
JSON.stringify(obj) === "{}" // true

# 10. 判断数据类型

function  type(obj) {
    let  string = Object.prototype.toString
    var  map = {
        '[object Boolean]':  'boolean',
        '[object Number]':  'number',
        '[object String]':  'string',
        '[object Function]':  'function',
        '[object Array]':  'array',
        '[object Date]':  'date',
        '[object RegExp]':  'regExp',
        '[object Undefined]':  'undefined',
        '[object Null]':  'null',
        '[object Object]':  'object'
    }
    if (obj  instanceof  Element) {
        return  'element'
    }
    return  map[string.call(obj)]
}

参考资料:

更新时间: 12/26/2021, 1:44:08 PM