【You Don't Know JS: Types & Grammar】Chapter 4-2 笔记

隐含地:Strings <--> Numbers

Example:
http://img2.58codes.com/2024/20112573G2ov0M4bJ2.jpg

结果分别为"420"(string)42(number),会导致这样的差异,一般的认知会认为,只要+运算子的其中任一边运算元为string,那就会进行string的串接。这部分是对的,但实际运作情况可能会比我们所想的还要複杂。

Example:
http://img2.58codes.com/2024/20112573VGtJcHAQbr.jpg

以上的2个运算元是array,不是string,但运算结果却是一个string,我们来分析这种情况是怎么产生的。

依据ES5的规格,若+运算子的其中一个运算元是object的话,首先会想办法把object转成基型值,而array是属于object,但无法使用valueOf( )方法产生基型值,所以它会改用toString( )方法。因此那2个array分别转成"1,2""3,4",串接就变成"1,23,4"

所以结论是,若+运算子的其中一个运算元是string(或是能转型为string)的话,那就会是进行串接动作,不然的话,就会是数值相加。

根据以上的论述,我们可以把number跟空字串(" ")相加,就能把number转型成string:
http://img2.58codes.com/2024/20112573wW3L2NZIZ0.jpg

+运算子的数值加法是具有可交换性的,2+33+2的结果是一样的。但作为string串接,就不是了,"a"+"b""b"+"a",结果会是不一样的string。但以上面的例子来说是具有可交换性的,a + """" + a都是让a变成string。

使用+运算子来达到转型的目的是很常见的手法,但有个细节需要特别注意。
Example:
http://img2.58codes.com/2024/20112573ltT4VpnGoM.jpg
a+""会直接呼叫valueOf( )方法,但String( )会呼叫toString( )方法,就会造成不同的结果。

一般来说,这种况情况不会造成困扰,但若我们自己定义某个物件的valueOf( )方法与toString( )方法,就要特别注意了。

string隐含地强制转型成number:
http://img2.58codes.com/2024/20112573Fb2R5QABDT.jpg

-运算子只能用来做数值的减法,所以a - 0中的a势必会转成number,a * 1a / 1也会产生相同的结果。

array的转型:
http://img2.58codes.com/2024/20112573xl0Ceafygf.jpg
上面的array会先转型成string,再转成number。

b = String( a )b = a + "",这2者都是合法的语法,但b = a + ""能见度较高。

隐含地: Boolean <--> Numbers

Example:
http://img2.58codes.com/2024/20112573XSAveVUWT9.jpg
上面的结果,只有在「所有的引数中,只有一个true或truthy」的情况下,才会为true,这显然不是一个很好的程式码,可读性差。若我们要处理的引数更多呢?

这时,我们换另一个方式,利用boolean转型为number的特性:

function onlyOne() {var sum = 0;for (var i=0; i < arguments.length; i++) {if (arguments[i]) {sum += arguments[i];}}return sum == 1;}var a = true;var b = false;onlyOne( b, a );     // trueonlyOne( b, a, b, b, b ); // trueonlyOne( b, b );     // falseonlyOne( b, a, b, b, b, a ); // false

关于arguments[i]可以参考这篇文章 call函式 & arguments物件

如果至少有一个引数的话,就会进入for迴圈。若arguments[i]的值为true(1),条件成立,sum加1;若第二次(以上)成立,sum会大于1,sum == 1的结果就会为false。换言之,只要有2个以上(含)的a,那结果就会为false。

另一个Example:

function onlyOne() {var sum = 0;for (var i=0; i < arguments.length; i++) {sum += Number( !!arguments[i] );}return sum === 1;}onlyOne( "42", 0 )  //true

利用!!arguments[i]会强制把值转换成true或false,再利用Number( )会把boolean转成0或1。

只要2个以上(含)成立,sum就不会是1,自然运算结果就为false。

相信透过上述的强制转型,可读性会比一堆 && 跟 || 来的高,并提高了可扩充性。

隐含地:* --> Boolean

隐含地强制转型是由于一个值的运算过程,迫使它必须转型才发生的事情。

会发生隐含地强制转型的情况:

if( )中的条件判定。for( )迴圈中第2个子句。while( )与do...while( )中的条件判断。? : 三元运算式的第1个子句。||(or) 与 &&(and)运算子。
var a = 42;var b = "abc";var c;var d = null;if (a) {console.log( "yep" );// yep}while (c) {console.log( "nope, never runs" );}c = d ? a : b;c;// "abc"if ((a && d) || c) {console.log( "yep" );// yep}

在以上的情境中,非boolean值都会隐含地强制转型成boolean值,以做出判断。

运算子 || 与 &&

||(or) 与 &&(and)运算子,实际上不会产生boolean值,而是2个运算元中的其中一个值。

换句话说,它们会选择其中一个运算元的值。

Example:
http://img2.58codes.com/2024/20112573sG7McVL7fp.jpg

|| 与 && 运算子会在第一个运算元进行boolean(非boolean值会转型)测试。

以 || 来说,若测试结果为true,那就会回传第1个运算元的值,反之,回传第2个。

以 && 来说,若测试结果为true,那就会回传第2个运算元的值,反之,回传第1个。

|| 与 && 运算式的值,永远都会是其中一个运算元的值,而非测试结果(boolean)。

思考另一个例子:
http://img2.58codes.com/2024/20112573KJPwpfPrUh.jpg
a || ba ? a : b的结果虽然相等,却存在着细微差异。

a ? a : b中,若a是一个较複杂的运算式,且运算结果为true的话,那a有可能会被估算2次。

a || b,a只会被估算一次,而该值会被用于测试中,若为true,也会被当作结果输出。

此种方式有个很常见的手法:

function foo(a,b) {a = a || "hello";b = b || "world";console.log( a + " " + b );}foo();// "hello world"foo( "yeah", "yeah!" );// "yeah yeah!"

a来说,若没有传入值,或是falsy值,a就会是备用的值'"hello"'。

但如果是

foo( "That's it!", "" ); // "That's it! world"

第二个值,即便我们传入"",依旧是flasy值,就会替换成"world"。

如若要更明确的测试,可以改用三元运算子。

关于&&的範例:

function foo() {console.log( a );}var a = 42;a && foo(); // 42

只有在a为true的情况下,才会执行foo( )方法,所以这种方式有时也会被称为「守护运算子」或是「短路」。

关于「短路」,会在第5章提到。

上面的方式,有另一种呈现,你或许看过:

if (a) {    foo(); }

不过,JS还是会採用捷径的方式来处理。

来看看另一种情境:

var a = 42;var b = null;var c = "foo";if (a && (b || c)) {console.log( "yep" );}

结果会产生yep。if叙述句判断式会将a && (b || c)的结果"foo",强制转型成true。

善用隐含地强制转型,可以让我们的程式码可读性与维护性更高。

或者,可以试试明确地强制转型:

if (!!a && (!!b || !!c)) {console.log( "yep" );}

哪种方式比较适合,心中自有答案。

参考来源:
http://img2.58codes.com/2024/201125739FY75WdXxA.jpg

此为You Don't Know JS系列的笔记。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章