<small id='OvhZEpB'></small> <noframes id='DCUzP8Yjuc'>

  • <tfoot id='pnWuYzK'></tfoot>

      <legend id='f4ZRi9UrpL'><style id='zsogQb7X3'><dir id='R9kNj'><q id='bP2rH9'></q></dir></style></legend>
      <i id='RSqHe2'><tr id='9oDb'><dt id='NrgUEQHvZ5'><q id='92Ma4'><span id='TEdKq6'><b id='eHiq2'><form id='FqmjJ'><ins id='upgHBz4o'></ins><ul id='8sR1WlJ'></ul><sub id='RLMzUX'></sub></form><legend id='C9RX'></legend><bdo id='YTJr'><pre id='z08bPH'><center id='WRZmzFkwe'></center></pre></bdo></b><th id='ZDEhFcWj6'></th></span></q></dt></tr></i><div id='IOfa8'><tfoot id='0XD1GAfd'></tfoot><dl id='dOQfr'><fieldset id='JaRKZ05'></fieldset></dl></div>

          <bdo id='SQm7'></bdo><ul id='YeaN'></ul>

          1. <li id='V5vN'></li>
            登陆

            JavaScript中的“黑话”

            admin 2019-11-20 259人围观 ,发现0个评论

            作者:vv13https://segmentfault.com/a/1190000016595592


            因为球是圆的,所以不论发生什么都有可能,对这点我是深信不疑的,但最近我总是在怀疑,JavaScript也是圆的!

            什么是“黑话”

            黑话,本指旧时江湖帮会人物的暗语、暗号,往往见于小说,后指流行于某一特殊行业中,非局外人所能了解的语言。而本文涉及到的“黑话”,其实是一些利用语言的特征使用的一些不常见的奇淫技巧,JavaScript的语法是十分简单灵活的,在项目中建议大家遵从ESLint规范编写可维护性的代码,各路神仙们也应该进行自我约束,毕竟“黑话”也并不全是什么好的东西,如果很多话可以直接讲,何必拐弯抹角的去说呢?

            “算术”

            算术中的位运算已被作者列为禁术,因此希望你在工程中使用位运算时,请确保你有充足的理由使用,并在需要时写好Hack注释。

            !与!!

            !为逻辑非操作符,可以应用于ECMAScript中的任何值,无论这个值是什么类型,它会被强制转化为一个布尔值变量,再对其值取反。

            !!只是单纯的将操作数执行两次逻辑非,它能将任意类型的值转化为相应的布尔值,它包含的步骤为:

            • 将一个值转化为布尔值;
            • 将其取反;
            • 再次取反。

            假设你需要通过一个布尔型变量表示是否有id值,以下写法推荐你使用最后一种方式来进行转化:

            const
            enable1
            =

            !!
            id

            const
            enable2
            =
            id
            ?

            true

            :

            false
            ;
            const
            enable3
            =

            Boolean
            (
            id
            );

            ~ 与 ~~

            ~表示按位取反,~5的运行步骤为:

            • 转为一个字节的二进制表示:00000101,
            • 按位取反:11111010
            • 取其反码:10000101
            • 取其补码:10000110
            • 转化为十进制:-6

            至于原码、反码、补码原理请看原理篇。

            ~~它代表双非按位取反运算符,如果你想使用比Math.floor()更快的方法,那就是它了。需要JavaScript中的“黑话”注意,对于正数,它向下取整;对于负数,向上取整;非数字取值为0,它具体的表现形式为:

            ~~
            null
            ;

            // => 0
            ~~
            undefined
            ;

            // => 0
            ~~
            Infinity
            ;

            // => 0
            --
            NaN
            ;

            // => 0
            ~~
            0
            ;

            // => 0
            ~~{};

            // => 0
            ~~[];

            // => 0
            ~~(
            1
            /
            0
            );

            // => 0
            ~~
            false
            ;

            // => 0
            ~~
            true
            ;

            // => 1
            ~~
            1.9
            ;

            // => 1
            ~~-
            1.9
            ;

            // => -1

            +

            在变量值前使用+的本意是将变量转换为数字,在一个函数接受数字类型的参数时特别有用:

            +
            '1'

            // 1
            +
            '-1'

            // '-1
            +[]

            // 0
            +{}

            // NaN

            根据观察,+a与a * 1结果类似。除此之外,使用+也可以作为立即执行函数:+function() {}(),等效于(function(){})()。

            字符串与数字相加时会将数值默认转为字符串,因此有了一下将数字转为字符串的快捷方法:'' + 1。

            & 与 &&

            如何你是从类C语言过来的话,请抛弃之前的刻板印象:&可以充当逻辑操作符号。在JavaScript中,&只能进行位运算。

            &,它表示按位与,此运算符需要两个数字并返回一个数字。如果它们不是数字,则会转换为数字。如果执行7 & 3, 则会经过以下步骤:

            • 先转换为2进制:111 & 11
            • 比较结果为:011
            • 将二进制转回十进制,因此:7 & 3 = 3

            它也可用于基偶数判断:const isOdd = num => !!(num & 1);

            &&,表示逻辑与,通常用于if条件判断,可跟你想象的不太一样,&&并不是单纯的返回true或者false,而是依据:

            • 若第一个表达式为false,则返回第一个表达式;
            • 若第一个表达式为true,返回第二个表达式。

            在这里举几个例子:

            0

            &&

            false

            0

            (
            both are
            false
            -
            y
            ,
            but
            0

            is
            the first
            )
            true

            &&

            false

            false

            (
            second one
            is

            false
            -
            y
            )
            true

            &&

            true

            true

            (
            both are
            true
            -
            y
            )
            true

            &&

            20

            20

            (
            both are
            true
            -
            y
            )

            &&可以连接多个操作符,如:a && b && c && d,返回值的规则与上面一样。除此以外,它还经常被作为短路逻辑使用:若前面表达式不是truthy,则不会继续执行之后的表达式。如在取一个对象的属性,我们需要先判断是否为空才能进行取值,否则会抛出Uncaught TypeError,这种情况下一般我们也会通过逻辑或,给与表达式一个默认值:

            const
            value
            =
            obj
            &&
            obj
            .
            value
            ||

            false

            我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我的头条号并在后台私信我:前端,即可免费获取。

            当JavaScript压缩工具遇到if判断时,也会使用&&短路逻辑从而节省内存空间:

            // before
            if

            (
            test
            )

            {
            alert
            (
            'hello'
            )

            }
            // after
            test
            &&
            alert
            (
            'hello'
            )

            | 与 ||

            它们与&和&&使用方法很相似,不同的是它们表示的是逻辑或,因此使用|会进行按位或运算,而||会返回第一个Truthy值。

            使用||进行默认值赋值在JavaScript中十分常见,这样可以省略很多不必要的if语句,比如:

            // before
            let
            res
            ;
            if

            (
            a
            )

            {
            res
            =
            a
            ;
            }

            else

            if

            (
            b
            )

            {
            res
            =
            b
            ;
            }

            else

            if

            (
            c
            )

            {
            res
            =
            c
            ;
            }

            else

            {
            res
            =

            1
            ;
            }
            // after
            const
            res
            =
            a
            ||
            b
            ||
            c
            ||

            1
            ;

            == 与 ===

            ==为相等运算符,操作符会先将左右两边的操作数强制转型,转换为相同的操作数,再进行相等性比较。

            ===为全等运算符,它除了在比较时不会将操作数强制转型,其余相等判断与==一致。

            简单而言, ==用于判断值是否相等, ===判断值与类型是否都相等,因此使用全等运算符判断操作数会更准确,新手也在学习JavaScript接收到的前几条Tips就是避免使用相等运算符,真的是这样吗?没错,这样能确保在你不彻底熟悉语言的情况下,尽可能的去避免犯错,但是我们也应该清楚在哪些情况下应该使用相等运算符,规则往往只针对于新手,而对聪明的你来说,最重要的是要清楚自己在做什么。

            相等操作符对于不同类型的值,进行的比较如下图所示:



            针对于undefined与null:undefined与null互等,与其余任意对象都不相等,因此在某些lib里,你可能会看到如下写法:

            if

            (
            VAR
            ==

            undefined
            )

            {}
            if

            (
            VAR
            ==

            null
            )

            {}

            它等效于:

            if

            (
            VAR
            ===

            undefined

            ||
            VAR
            ===

            null
            )

            {}

            对于 '', false, 0而言,他们都属于Falsy类型,通过Boolean对象都会转换为假值,而通过==判断三者的关系,他们总是相等的,因为在比较值时它们会因为类型不同而都被转换为false值:

            console
            .
            log
            ((
            false

            ==

            0
            )

            &&

            (
            0

            ==

            ''
            )

            &&

            (
            ''

            ==

            false
            ))

            // true

            或者有时候我们希望利用强转特性比较字符串与数字:

            console
            .
            log
            (
            11

            ==

            '11'
            )

            // true
            console
            .
            log
            (
            11

            ===

            '11'
            )

            // false

            ^

            按位异或运算符,对比每一个比特位,当比特位不相同时则返回1,否则返回0。很少人在Web开发中使用此运算符吧,除了传说中的一种场景:交换值。

            若要交换a与b的值,如果可以的话推荐你使用:

            [
            a
            ,
            b
            ]

            =

            [
            b
            ,
            a
            ];

            或者新建一个c,用于存储临时变量,如果你遇到有人这样书写:

            // 异或运算,相同位取0,不同位取1,a ^ b ^ b = a, a ^ a ^ b = b
            a
            =
            a
            ^
            b
            b
            =
            a
            ^
            b
            a
            =
            a
            ^
            b

            这样通过异或运算进行交换两个数字型变量,请原谅他并忽视它,他只可能是一个醉心于魔法的初心者,并祝愿他早日发现,简洁易读的函数才是最佳实践。

            数值表示法

            3e9

            科学计数法是一种数学术语,将一个数表示为a乘以10的n次方,如光速30万公里每秒,在计算中通常将米做单位,则记为:300000000m/s,而在JavaScript中我们可使用科学计数法 3e9表示。

            在这里举几个科学计数法的示例:

            1e5
            ;

            // 100000
            2e-4
            ;

            // 0.0002
            -
            3e3
            ;

            // -3000

            Number对象有toExponential(fractionDigits)方法以科学计数法返回该数值的字符串表示形式,参数fractionDigits可选,用于用来指定小数点后有几位数字,例如:(179000).toExponential(); // "1.79e+5"。

            以下情况JavaScript会自动将数值转为科学计数法表示:

            • 小数点前的数字多于21位。
            • 小数点后的零多于5个。

            .5px

            通常某些人习惯省略0.开头的数字,常见于数值计算、css属性中,比如0.5px可直接写为.5px,0.2 * 0.3可写为:.2 * .3

            0x、0o和0b

            在十进制的世界里呆久了,请不要忘记还有其他进制的存在,在计算机中它们是同地位的。JavaScript提供了以下进制的表示方法:

            • 二进制:只用0和1两个数字,前缀为0b,十进制13可表示为0b1101
            • 八进制:只用0到7八个数字,前缀为0o、0,十进制13可表示为0o15、015
            • 十六进制:只用0到9的十个数字,和a到f六个字母,前缀为0x,十进制13可表示为0xd

            默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制再进行运算。从十进制转其他进制请查阅toString方法,从其他进制转十进制请查阅parseInt方法,从其他进制转其他进制请先转为十进制再转为其他方法。

            “话术”

            Array.prototype.sort

            Array.prototype.sort()默认根据字符串的Unicode编码进行排序,具体算法取决于实现的浏览器,在v8引擎中,若数组长度小于10则使用从插入排序,大于10使用的是快排。

            而sort支持传入一个compareFunction(a, b)的参数,其中a、b为数组中进行比较的两个非空对象(所有空对象将会排在数组的最后),具体比较规则为:

            • 返回值小于0,a排在b的左边
            • 返回值等于0,a和b的位置不变
            • 返回值大于0,a排在b的右边

            因此利用sort即可写一个打乱数组的方法:

            [
            1
            ,
            2
            ,
            3
            ,
            4
            ].
            sort
            (()

            =>

            .
            5

            -

            Math
            .
            random
            ())

            但是以上的实现并不是完全随机的,究其原因,还是因为排序算法的不稳定性,导致一些元素没有机会进行比较,具体请参考问题,在抽奖程序中若要实现完全随机,请使用 Fisher–Yates shuffle 算法,以下是简单实现:

            function
            shuffle
            (
            arrs
            )

            {

            for

            (
            let
            i
            =
            arrs
            .
            length
            -

            1
            ;
            i
            >

            0
            ;
            i
            -=

            1
            )

            {

            const
            random
            =

            Math
            .
            floor
            (
            Math
            .
            random
            ()

            *

            (
            i
            +

            1
            ));

            [
            arrs
            [
            random
            ],
            arrs
            [
            i
            ]]

            =

            [
            arrs
            [
            i
            ],
            arrs
            [
            random
            ]];

            }
            }

            Array.prototype.concat.apply

            apply接收数组类型的参数来调用函数,而concat接收字符串或数组的多个参数,因此可使用此技巧将二维数组直接展平:

            Array
            .
            prototype
            .
            concat
            .
            apply
            ([],

            [
            1
            ,

            [
            2
            ,
            3
            ],

            [
            4
            ]])

            而通过此方法也可以写一个深层次遍历的方法:

            function
            flattenDeep
            (
            arrs
            )

            {

            let
            result
            =

            Array
            .
            prototype
            .
            concat
            .
            apply
            ([],
            arrs
            );

            while

            (
            result
            .
            some
            (
            item
            =>
            item
            instanceof

            Array
            ))

            {
            result
            =

            Array
            .
            prototype
            .
            concat
            .
            apply
            ([],
            result
            );

            }

            return
            result
            ;
            }

            经过测试,效率与lodash对比如下:

            对上述方法中的Array.prototype.concat.apply([], target)亦可以写成:[].concat(...target)。

            Array.prototype.push.apply

            在es5中,若想要对数组进行拼接操作,我们习惯于使用数组中的concat方法:

            let
            arrs
            =

            [
            1
            ,

            2
            ,

            3
            ];
            arrs
            =
            arrs
            .
            concat
            ([
            4
            ,
            5
            ,
            6
            ]);

            但还有酷的方法,利用apply方法的数组传参特性,可以更简洁的美国黄片执行拼接操作:

            const
            arrs
            =

            [
            1
            ,

            2
            ,

            3
            ];
            arrs
            .
            push
            .
            apply
            (
            arrs
            ,

            [
            4
            ,

            5
            ,

            6
            ]);

            Array.prototype.length

            它通常用于返回数组的长度,但是也是一个包含有复杂行为的属性,首先需要说明的是,它并不是用于统计数组中元素的数量,而是代表数组中最高索引的值:

            const
            arrs
            =

            [];
            arrs
            [
            5
            ]

            =

            1
            ;
            console
            .
            log
            (
            arrs
            .
            length
            );

            // 6

            另外,length长度随着数组的变化而变化,但是这种变化仅限于:子元素最高索引值的变化,假如使用delete方法删除最高元素,length是不会变化的,因为最高索引值也没变:

            const
            arrs
            =

            [
            1
            ,

            2
            ,

            3
            ];
            delete
            arrs
            [
            2
            ];

            // 长度依然为3

            length还有一个重要的特性,那就是允许你修改它的值,若修改值小于数组本身的最大索引,则会对数组进行部分截取:

            const
            arrs
            =

            [
            1
            ,

            2
            ,

            3
            ,

            4
            ];
            arrs
            .
            length
            =

            2
            ;

            // arrs = [1, 2]
            arrs
            .
            length
            =

            0
            ;

            // arrs = []

            若赋予的值大于当前最大索引,则会得到一个稀疏数组:

            const
            arrs
            =

            [
            1
            ,

            2
            ];
            arrs
            .
            length
            =

            5
            ;

            // arrs = [1, 2,,,,]

            若将值赋为0,则执行了清空数组的操作:

            const
            arrs
            =

            [
            1
            ,

            2
            ,

            3
            ,

            4
            ];
            arrs
            .
            length
            =

            0
            ;

            // arrs = []

            使用此方法会将数组中的所有索引都删除掉,因此也会影响其他引用此数组的值,这点跟使用arrs = []有很大的区别:

            let
            a
            =

            [
            1
            ,
            2
            ,
            3
            ];
            let
            b
            =

            [
            1
            ,
            2
            ,
            3
            ];
            let
            a1
            =
            a
            ;
            let
            b1
            =
            b
            ;
            a
            =

            [];
            b
            .
            length
            =

            0
            ;
            console
            .
            log
            (
            a
            ,
            b
            ,
            a1
            ,
            b1
            );

            // [], [], [1, 2, 3], []

            在对length进行修改的时候,还需要注意:

            • 值需要为正整数
            • 传递字符串会被尝试转为数字类型

            Object.prototype.toString.call

            每个对象都有一个toString(),用于将对象以字符串方式引用时自动调用,如果此方法未被覆盖,toString则会返回[object type],因此Object.prototype.toString.call只是为了调用原生对象上未被覆盖的方法,call将作用域指向需要判断的对象,这样一来就可以通过原生的toString方法打印对象的类型字符串:Object.prototype.toString.call([]) => "[object Array]" ,利用这个特性,可以较为精确的实现类型判断。

            在ES3中,获取到的type为内部属性[[Class]]属性,它可以用来判断一个原生属性属于哪一种内置的值;在ES5中新增了两条规则:若this值为null、undefined分别返回:[object Null]、[object Undefined];在ES6中不存在[[Class]]了,取而代之的是一种内部属性:[[NativeBrand]],它是一种标记值,用于区分原生对象的属性,具体的判断规则为:

            19.1
            .
            3.6Object
            .
            prototype
            .
            toString
            (

            )
            When
            the toString method
            is
            called
            ,
            the following steps are taken
            :
            If
            the
            this
            value
            is

            undefined
            ,

            return

            "[object Undefined]"
            .
            If
            the
            this
            value
            is

            null
            ,

            return

            "[object Null]"
            .
            Let
            O be
            !

            ToObject
            (
            this
            value
            ).
            Let
            isArray be
            ?

            IsArray
            (
            O
            ).
            If
            isArray
            is

            true
            ,

            let
            builtinTag be
            "Array"
            .
            Else

            if
            O
            is
            a
            String
            exotic
            object
            ,

            let
            builtinTag be
            "String"
            .
            Else

            if
            O has a
            [[
            ParameterMap
            ]]

            internal
            slot
            ,

            let
            builtinTag be
            "Arguments"
            .
            Else

            if
            O has a
            [[
            Call
            ]]

            internal
            method
            ,

            let
            builtinTag be
            "Function"
            .
            Else

            if
            O has an
            [[
            ErrorData
            ]]

            internal
            slot
            ,

            let
            builtinTag be
            "Error"
            .
            Else

            if
            O has a
            [[
            BooleanData
            ]]

            internal
            slot
            ,

            let
            builtinTag be
            "Boolean"
            .
            Else

            if
            O has a
            [[
            NumberData
            ]]

            internal
            slot
            ,

            let
            builtinTag be
            "Number"
            .
            Else

            if
            O has a
            [[
            DateValue
            ]]

            internal
            slot
            ,

            let
            builtinTag be
            "Date"
            .
            Else

            if
            O has a
            [[
            RegExpMatcher
            ]]

            internal
            slot
            ,

            let
            builtinTag be
            "RegExp"
            .
            Else
            ,

            let
            builtinTag be
            "Object"
            .
            Let
            tag be
            ?

            Get
            (
            O
            ,

            @
            @toStringTag
            ).
            If

            Type
            (
            tag
            )

            is

            not

            String
            ,

            set
            tag to builtinTag
            .
            Return
            the
            string
            -
            concatenation of
            "[object "
            ,
            tag
            ,

            and

            "]"
            .
            This

            function

            is
            the
            %
            ObjProto_toString
            %
            intrinsic
            object
            .
            NOTE
            Historically
            ,

            this

            function
            was occasionally used to access the
            String
            value of the
            [[
            Class
            ]]

            internal
            slot that was used
            in
            previous editions of
            this
            specification
            as
            a nominal type tag
            for
            various built
            -
            in
            objects
            .

            The
            above definition of toString preserves compatibility
            for
            legacy code that uses toString
            as
            a test
            for
            those specific kinds of built
            -
            in
            objects
            .

            It
            does
            not
            provide a reliable type testing mechanism
            for
            other kinds of built
            -
            in

            or
            program
            defined
            objects
            .

            In
            addition
            ,
            programs can
            use

            @
            @toStringTag

            in
            ways that will invalidate the reliability of such legacy type tests
            .

            Object.create(null)

            用于创建无“副作用”的对象,也就是说,它创建的是一个空对象,不包含原型链与其他属性。若使用const map = {}创建出来的对象相当于Object.create(Object.prototype),它继承了对象的原型链。

            JSON.parse(JSON.stringify(Obj))

            很常用的一种深拷贝对象的方式,将对象进行JSON字符串格式化再进行解析,即可获得一个新的对象,要注意它的性能不是特别好,而且无法处理闭环的引用,比如:

            const
            obj
            =

            {
            a
            :

            1
            };
            obj
            .
            b
            =
            obj
            ;
            JSON
            .
            parse
            (
            JSON
            .
            stringify
            (
            obj
            ))

            // UncauJavaScript中的“黑话”ght TypeError: Converting circular structure to JSON

            这样通过JSON解析的方式其实性能并不高,若对象可通过浅拷贝复制请一定使用浅拷贝的方式,不管你使用{...obj}还是Object.assign({}, obj)的方式,而如果对性能有要求的情况下,请不要再造轮子了,直接使用npm:clone这个包或是别的吧。

            “理论”

            Truthy与FalsyJavaScript中的“黑话”

            对每一个类型的值来讲,它每一个对象都有一个布尔型的值,Falsy表示在Boolean对象中表现为false的值,在条件判断与循环中,JavaScript会将任意类型强制转化为Boolean对象。以下这些对象在遇到if语句时都表现为Falsy:

            if

            (
            false
            )
            if

            (
            null
            )
            if

            (
            undefined
            )
            if

            (
            0
            )
            if

            (
            NaN
            )
            if

            (
            ''
            )
            if

            (
            ""
            )
            if

            (
            document
            .
            all
            )

            document.all属于历史遗留原因,所以为false,它违背了JavaScript的规范,可以不管它,而NaN这个变量,千万不要用全等或相等对其进行判断,因为它发起疯来连自己都打:

            console
            .
            log
            (
            NaN

            ===

            0
            )

            // false
            console
            .
            log
            (
            NaN

            ===

            NaN
            )

            // false
            console
            .
            log
            (
            NaN

            ==

            NaN
            )

            // false

            但是我们可以使用Object.is方法进行判断值是否为NaN,它是ES6新加入的语法,用于比较两个值是否相同,它可以视为比全等判断符更为严格的判断方法,但是不可混为一谈:

            Object
            .
            is
            (
            NaN
            ,

            NaN
            )

            // true
            Object
            .
            is
            (+
            0
            ,

            -
            0
            )

            // false

            而除了Falsy值,所有值都是Truthy值,在Boolean上下文中表现为true。

            原码, 反码, 补码

            在JavaScript进行位运算时,采用32位有符号整型,即数字5有以下表示方式:

            • 原码:00000000 00000000 00000000 00000101
            • 反码:00000000 00000000 00000000 00000101
            • 补码:00000000 00000000 00000000 00000101

            而数字-5的表示方式为:

            • 原码:10000000 00000000 00000000 00000101
            • 反码:11111111 11111111 11111111 11111010
            • 补码:11111111 11111111 11111111 11111011

            综上所述,有以下规律:

            • 正数的原码、反码、补码都是它本身
            • 负数的反码:在其原码的基础上, 符号位不变,其余各个位取反
            • 负数的补码:负数的反码 + 1

            那么它们到底有什么用呢?其实位运算就是用计算机底层电路所有运算的基础,为了让计算机的运算更加简单,而不用去辨别符号位,所有值都采用加法运算,因此,人们设计了原码,通过符号位来标识数字的正负:

            1

            =

            0000

            0001
            -
            1

            =

            1000

            0001

            假如计算机要对两个数相加:1 + (-1),使用原码相加的运算结果为:10000010,很明显-2并不是我们想要的结果,因此出现了反码,若使用反码进行运算会有什么结果呢,让我们来看一下:

            1
            [反码]

            +

            (-
            1
            )[反码]

            =

            0000

            0001

            +

            1111

            1110

            =

            11111111
            [反码]

            =

            10000000
            [原码]

            此时运算结果是正确的,可是这样还存在一个问题,有两个值可以表示0:1000 0000、0000 0000,对于计算机来说,0带符号是没有任何意义的,人们为了优化0的存在,设计出了补码:

            1
            [补码]

            +

            (-
            1
            )[补码]

            =

            0000

            0001

            +

            1111

            1111

            =

            00000000
            [原码]

            这样一来,-0的问题就可以解决了。

            参考资料

            https://modernweb.com/45-useful-javascript-tips-tricks-and-best-practices/

            https://dmitripavlutin.com/the-magic-behind-array-length-property/

            https://medium.freecodecamp.org/9-neat-javascript-tricks-e2742f2735c3

            https://stackoverflow.com/questions/7310109/whats-the-difference-between-and-in-javascript

            http://javascript.ruanyifeng.com/grammar/number.html

            请关注微信公众号
            微信二维码
            不容错过
            Powered By Z-BlogPHP