《一名【合格】前端工程师的自检清单》—— JavaScript基础 之 变量和类型

前言

前几天,@ConardLi 发布了一篇名叫《一名【合格】前端工程师的自检清单》的文章,才发现自己的知识体系原来有如此多的漏洞。这里也感谢作者的分享。由此,我也萌发了对照列表,记录和学习一遍,让自己没那么迷茫。

一、JavaScript基础

1. JavaScript规定了几种语言类型 (7 种)

基本数据类型(6种):string, number, boolean, null, undefined, symbol
引用数据类型(*):Object (万物皆对象...)
复制代码

2. JavaScript对象的底层数据结构是什么

散列表(哈希表)
复制代码

3. Symbol类型在实际开发中的应用、可手动实现一个简单的Symbol

我已知使用的地方,组件属性(mixin 模式)、常量定义。
要手写必须先了解Symbol.
复制代码

Symbol

特点 实例
函数 Symbol()
不能通过 new 关键字调用函数 new Symbol() => TypeError
instanceof 指向为 false let a = Symbol('a');a instanceof Symbol => false
返回值类型为 "symbol" typeof Symbol() === 'symbol'
唯一 Symbol() != Symbol()
可传参,toString可查看 Symbol('foo').toString() === 'Symbol(foo)'
Symbol 不可以运算 'Im a' + Symbol('foo') => TypeError
Symbol 可显式转 Str 和 Bool, 不能转 Num String(Symbol('foo')) || Boolean(Symbol('foo'))
Symbol 属性不能用常规方法遍历 (for in)
Symbol.for([desc]) 设置唯一Symbol Symbol.for('foo') === Symbol.for('foo')
Symbol.keyFor([Symbol]) 查找Symbol 的key let a = Symbol.for('foo');Symbol.keyFor(a) === 'foo'

此外我们需要先看一下Symbol 的规范

Symbol ( [ description ] )

When Symbol is called with optional argument description, the following steps are taken:

  1. If NewTarget is not undefined, throw a TypeError exception. (不能 new)
  2. If description is undefined, let descString be undefined. ()
  3. Else, let descString be ToString(description).
  4. ReturnIfAbrupt(descString). (报错就返回)
  5. Return a new unique Symbol value whose [[Description]] value is descString. (返回一个唯一Symbol值,Description 的值就是 descString 的值)
(function (w) {
            // 10. 可以通过 Symbol.for 来设置全局唯一的 Symbol.  ( 核心: 做一个映射表即可 )
            let globalSymbolMap = {}
            
            // ok  1. 函数        ok3
            function MySymbol(description) {
                // ok  2. 无法使用 new 关键字
                if(this instanceof MySymbol)
                    throw new TypeError('MySymbol is not a constructor')

                // ok  3. instanceof 返回 false. 因此只能对象
                // err 4. 无法实现 typeof MySymbol() === 'symbol',
                // ok  5. 返回的对象不是同一个,当然不一样
                // ok  6. `Symbol('foo').toString() === 'Symbol(foo)'` 实现
                let symbol = Object.create({
                    toString() {
                        return 'MySymbol(' + ( this.__Description__ || '' )+ ')'
                    },
                    //ok  7. 运算会调用 valueOf , 覆写即可。
                    //ok  8. 可以显示转 String 和 Boolean, 不能转 Number (因为复写了 valueOf)
                    valueOf() {
                        throw new Error('Cannot convert a MySymbol value')
                    }
                })
                // err  9.无法做到无法被变遍历。 因为遍历对象是不确定的,对象的属性设置也是需要控制那个对象才可以。
                Object.defineProperties(symbol, {
                    '__Description__': {
                        value: description === undefined ? undefined : String(description),
                        writable: false,
                        enumerable: false,
                        configurable: false
                    }
                })

                return symbol
            }
            // 10 设置for
            Object.defineProperties(MySymbol, {
                for: {
                    value: function(desc) {
                        if (globalSymbolMap[desc])
                            return globalSymbolMap[desc]
                        globalSymbolMap[desc] = MySymbol()
                        return globalSymbolMap[desc]
                    },
                },
                // 11. 设置 keyFor
                keyFor: {
                    value: function(symbol) {
                        for(let key in globalSymbolMap)
                            if (symbol === globalSymbolMap[key])
                                return key
                    },
                }
            })

            w.MySymbol = MySymbol
        })(window)
复制代码

4. JavaScript中的变量在内存中的具体存储形式

基本数据类型 和 引用数据类型。

内存中会被开辟两块地方,一个是栈区,一个是堆区。基本数据类型的值会放在栈,引用数据类型的值会放在堆,它在堆的地址会放在栈。

// 自己随便画的,大家不要喷我。。。。。
复制代码

5. 基本类型对应的内置对象,以及他们之间的装箱拆箱操作

之前有说过基本数据类型有6种。其中,Symbol 较为特殊。他必须通过 Symbol() 获取,因为没有拆箱和装箱。
复制代码
  • null => Null
  • undefined => Undefined

上面两个类型下都只有一个值,也没方法,就不及与讨论。

  • number => Number
  • string => String
  • boolean => Boolean

拆箱操作:valueOf()或者toString()

装箱操作:调用其他操作对当前数据进行操作的方法.(例如,String.toFixed , String.substring )

6. 理解值类型和引用类型

根据第5题,值类型的数据直接存放在栈。引用类型在栈中存放了真实数据的地址
复制代码

7. null和undefined的区别

表象:
    null: 是关键字,typeof null 是 object。
    undefined:是全局变量,为了用于区分空值和未定义而引入的。
复制代码

根据 js权威指南中的描述:

null 和 undefined 都表示“值的空缺”

你可以认为undefined是表示系统级的、出乎意料的或类似错误的值的空缺,而null是表示程序级的、正常的或在意料之中的值的空缺。

8. 至少可以说出三种判断JavaScript数据类型的方式,以及他们的优缺点,如何准确的判断数组类型

  • typeof
    • 优点:简单....(也不知道算不算)
    • 缺点:区分不了 null 和 object 和 array,
  • instanceof (判断变量是否为 某对象的实例)
    • 优点:null instanceof Object === false; [] instanceof Array === true;
    • 缺点:区分不了基本数据类型
  • Object.prototype.toString.call(data) 其中,data 为入参
    • 优点:可以分辨大部分类型
    • 缺点:引用数据类型不能辨别具体得一些区别.(例如, 自定义的 Person 函数,返回的是 [object Object])

9. 可能发生隐式类型转换的场景以及转换原则,应如何避免或巧妙应用

下图是《Javascript 权威指南》关于数据转换的表

个人总结就是

  • string + 其他类型,加号就是做字符串拼接。其他数字类型就会转换成 string类型再相加。

    • "string" + 1 => "string1"
    • "string" + true => "stringtrue"
    • "string" + null => "stringnull"
    • "string" + undefined => "stringundefined"
    • "string" + [] => "string"
    • "string" + {} => "string[object object]"
  • number: 一般用一下类型,都会转Number.

    1. +/- 在前
    2. [+ - * / %] (算术运算符)
    3. [> < >= <= == != === !===] (关系运算符)

    如下:

    • +"1" => 1
    • -true => -1
    • 1 + true => 2
    • 1 + ["9"] => 19
    • 1 + [9] => 19
    • +[9] + 1 => 10
    • 1 + null => 1
    • 1 + {} => 1[object Object]

    关系运算符

    • "2" > 10 => false // 转数字比较
    • "2" > "10" => true // 比的是 ASCII码
    • NaN == NaN => false
    • undefined == null => false

    看到有一些史诗级坑的例子

    • [] == 0 //true
    • ![] == 0 // true
    • [] == ![] // true
    • [] == [] // false
    • {} == !{} // false
    • {} == {} // false

10.出现小数精度丢失的原因,JavaScript可以存储的最大数字、最大安全数字,JavaScript处理大数字的方法、避免精度丢失的方法

  • 背景: JS 遵循的是 IEEE 754 规范,采用双精度存储,占用 64 bit,也就是8位。虽然很多看似有穷的数据,对于计算机来说确实无穷的。如,大整数,浮点数。计算机只有0和1,所以十进制里面的四舍五入,在计算机里面就会变成 “0舍1入”了。

  • js 里面最大的数字是 2^53。原因:64位,1位表示正负,11位表示指数,52位表示尾数。52 + 1 = 53

  • js 里面最大的安全数字是 2^53 - 1

  • 在我个人工作中,如若有大数字和浮点精度要求较高都是用 String存入。

其他

文章有误之处,敬请指正,以免误导大家~

参考文献

转载于:https://juejin.im/post/5cc94723f265da034c7036e6

猜你喜欢

转载自blog.csdn.net/weixin_34409822/article/details/91478803
今日推荐