zoukankan      html  css  js  c++  java
  • js笔试题系列之———基础类型与运算符

      前端技术的发展速度大家有目共睹,js的ECMA标准也不再是3的天下,但不管再怎么山雨欲来风满楼,基础语法还是得温故而知新。无论你是初学则还是多年js的编程者,都可以试着做做下面的测试题,我相信总还是会有些收获的。因为全部是自己总结和手打的,有纰漏错误之处请留言,谢谢。

    一:考察基本数据类型与运算符

    (1)未定义变量问题

    var a;
    console.log(typeof a); ==>undefined
    

      先以一个最常见也是最简单的测试案例开始,未定义的变量或者未赋值则为undefined

    (2)++/--运算符问题

    var a = '1a';
    console.log(a++); ==>NaN
    

      ++操作符将对a变量隐式转换为number类型,字符串'1a'无法正常转换为数字,所以返回NaN。

      这里可以总结出以下几点:

      1. 除了+操作符以外,-、*、/、%、++、--都将隐式转换参与运算的变量为number类型,如果能正常转换为数字则返回该数字,否则返回NaN;

      2. 能正常转换为数字的有如下几种情况:

        纯数字类字符串如'123'、'1e2'(转换为1*10的2次方等于100);

        null参与运算转换为0(null-4等于-4,null+null等于0);

        boolean类型的true和false分别可转换为1和0;

      3. 只有能够转换为数字的变量才能参与++或--运算,否则将报错,比如:  

    console.log(3++); ==>报错,常量不能直接运算++
    var a = 3;
    console.log(a++); ==>3
    

      其中有个特例:NaN++可以正常返回结果,仍然是NaN

    (3)+运算符之四则运算与字符合并

    console.log(2+'1'); ==>'21'
    console.log(2-'1'); ==>1
    console.log(1+NaN); ==>NaN
    console.log('1'+NaN); ==>'1NaN'
    

      1. +运算符有必要单独一提,因为除了+以外的其它算术运算符,都会对参与运算的变量或值默认隐式转换为number,但+因为在js中还肩负着字符串合并的重大任务,所以它有特殊'国情':

        1.1 当+的左右两边均是数字类型时,则执行算术运算,比如1+2返回3、NaN+1返回NaN;

        1.2 当+的左右两边均是字符串类型时,则执行字符串合并,比如'1'+'2'返回'12';

        1.3 当+的左右两边一个是数字、一个是字符串类型时候,则先将数字转换为字符串再合并,比如1+'1'返回'11';

      2. 在实际开发过程中,我们使用+运算符基本上都是处理字符串类型或者数字类型的,所以上面的三种情况能够应对大部分开发场景。但是当+运算符的左右两边出现了第三种数据类型时,情况就会显得复杂了(以下其它数据类型是指除了string和number的以外类型):

        2.1 其它数据类型+字符串类型

    console.log(null+'1'); ==>'null1'
    console.log(undefined+'1'); ==>'undefined1'
    console.log([1,2]+'1'); ==>'121'
    console.log((function(){})+'1'); ==>'function (){}1'
    console.log(({})+'1'); ==>'[object Object]1'
    

      执行办法:其它数据类型将被转换为字符串再合并,且对象类型将调用自身toString()方法转换结果。另外,其实对象类型+运算无论另外一个参与运算的值是不是字符串类型,都只能与它进行字符串合并操作,而不能是四则运算,下面会具体讲到。

        2.3 其它数据类型+数字类型

    console.log(null+1); ==>1
    console.log(undefined+1); ==>NaN
    console.log(true+1); ==>2
    console.log([1]+1); ==>'11'
    console.log((function(){})+1); ==>'function (){}1'
    console.log(({})+1); ==>'[object Object]1'
    

      执行办法:非对象类型将进行四则运算,而对象类型场景则仍然是字符串合并的操作。

        2.2 其它数据类型+其它数据类型

    console.log(null+null); ==>0
    console.log(undefined+undefined); ==>0
    console.log(true+true); ==>2
    console.log([1]+[2]); ==>'12'
    console.log((function(){})+(function(){})); ==>'function (){}function (){}'
    console.log(({})+({})); ==>'[object Object][object Object]'
    

      执行办法:非对象类型将进行四则运算,而对象类型场景则仍然是字符串合并的操作。

      所以,关于有其它类型参与+运算的场景,我们可以再稍总结下最终的结果:只要有对象类型参与+运算,则永远是做字符串合并;如果是null/undefined/boolean类型参与+运算,当另一个参与运算的值为字符串,则进行字符串合并,否则进行四则运算。

    思考题:alert({name:'mofei'})

    (4)+运算符之转换数字问题

    console.log(1+ +1); ==>2
    console.log(1e+1+1); ==>11
    

      这个测试仍然是+运算,但是并没有和上一个测试案例合并在一起而是单独出来,原因很简单:此+非彼+。

      +运算符实际上在js中有三种应用场景:转换为数字、四则运算加、字符串连接。在上一个测试案例中我们讲了后两种应用场景,而这里是则是对第一个应用场景的补充。关于转换为数字的理解也不难,我们经常用a+''的写法将一个变量转换为字符串类型,所以我们也可以利用+运算符将其它类型转换为数值类型,比如+null返回结果为0。所以在这个案例中,1+ +1等同与1+1,因为后面那个+1其实就是将1转换为number类型,仍然是1,而1e+1+1等效于1e1+1,也就是11。

    (5)除/取模运算符的极端场景问题

    console.log(10/0); ==>Infinity
    console.log(10%0); ==>NaN
    

      除0返回Infinity,对0取模(求除法运算的余数,对2取模常用在判断奇偶)返回NaN。

    (6)!运算符问题

    console.log(!!false); ==>false
    console.log(!!4); ==>true
    console.log(!!'false'); ==>true
    

      这里考察了取反运算符。双取反实际上就是将运算对象强制转换为boolean型,其中最后一个要注意'false'本身是个非空字符串,转换为布尔值为true。

      大部分情况下转布尔值都是返回true,除了以下几种情况:false本身、null、nudefined、空字符串''、数字0、数字NaN

    思考题:!!undefined 

    (7)typeof运算符问题

    console.log(typeof(0)); ==>number
    console.log(typeof(NaN)); ==>number console.log(typeof('0')); ==>string console.log(typeof('false')); ==>string console.log(typeof(false)); ==>boolean console.log(typeof(undefined)); ==>undefined console.log(typeof(null)); ==>object console.log(typeof([1,2])); ==>object console.log(typeof(function(){})); ==>function

      这里罗列了typeof可以返回的所有可能值:number、string、boolean、undefined、object、function

      可以总结的知识点是:

      1. 凡是带上引号的typeof就是string,而不需要管里面内容是什么,比如不要误以为typeof('undefined')结果就是undefined

      2. null、数组array、普通对象的typeof返回为object

      3. 函数本身也是对象,但是它的typeof返回为特殊的function

      4. 并不能依靠typeof全部分别出变量到底属于8种数据类型中的哪一种(比如数组和普通对象),但是可以直接区分基本数据类型中的四种类型:number、string、boolean、undefined,如果要全部区分类型可以结合其它方法共同判断(如instanceof、constructor),或者使用Object.prototype.toString.call(...)

     (8)宽松等于严格等问题

    console.log(null == undefined); ==>true
    console.log(false == ''); ==>true
    console.log(false === !true); ==>true
    console.log([] === []); ==>false
    

      关于等于运算符==:比较双方是否相等,这种比较是允许进行类型转换的,比如1 == '1'将返回true,至于它们是怎样进行类型转换可以参照《javascript权威指南》75页有非常详细的描述,这里不再阐述了。严格等运算符经常在对象的比较中被考察,我们要知道对象的比较是通过引用比较的,所以在这个测试案例中,它们虽然看上去很像,其实是两个不同的对象(这里也是数组),它们并没有引用同一个地址,所以并不严格等,对象严格等的情况如下: 

    var a = [];
    var b = a;
    console.log(a === b); ==>true
    

      b变量被赋值为a,a本质是对象,对象赋值为引用赋值,此时a和b公用一个地址,所以严格等成立。

      此外,关于==还有个比较经典的问题:

    console.log([] == ![]); ==>true
    

      因为!运算符优先级原因,将先执行![],所以这里等效于 [] == false,按照常识在boolean环境下空数组是转换为true的,但是实际上在==环境中,是通过转换为数字或字符串来比较的,当操作值有boolean类型时转换为数值比较,也就是[]转换为number类型为0,false转换为number类型为0,所以结果返回true。看上去这些繁琐的转换实在令人担忧,但实际也没有这么糟糕,毕竟这种看上去“非人性”的结果在实际开发场景中极少遇到,当你有一定的经验的时候,绝大部分宽松相等的结果你还是能够一眼识破的。  

     (9)或与问题

    console.log(1&&2); ==>2
    console.log(1||2); ==>1
    console.log(1&&a=2); ==>error
    console.log(1&&(a=2)); ==>2
    

      关于&&和||两个运算符,也是笔试中的常客。这里有几点需要注意:

      1. &&和||返回的是表达式的值,而并不是true或者false

      2. 从左到右执行,&&左侧的表达式返回值如果转换布尔型为true时,则将执行右侧的表达式;||左侧的表达式返回值如果转换布尔型为true时,则直接返回该表达式返回值且不再执行右侧表达式

      有了以上两点,前两个测试则比较容易理解了,而对于1&&a=2,实际等同于——(1&&a)=2——undefined=2,执行将报错;只要给a=2加上小括号优先执行则可以正常运行,其中a=2的返回值为2,所以最终表达式的值为2。

    (10)浮点数字不精确问题

    console.log(0.1*0.1); ==>0.010000000000000002
    

      在js中采用的是一种二进制表示法,可以精确的表示分数,比如1/21/81/1024。但是其它浮点值实际上只是真实值的一个近视表示,比如0.1,二进制浮点数表示法并不能精确的表示0.1这样简单的数字。所以,当遇到小数点的四则运算的时候需要特殊处理,最典型的场景就是支付了,比如1.1元每个,用户购买3个,则不能直接使用相乘结果,可以使用toFixed控制结果,或者以乘法为例可使用以下方法保证精确性: 

    //乘法处理
    function FloatMul(arg1,arg2)   {   
      var m=0,s1=arg1.toString(),s2=arg2.toString();   
      try{m+=s1.split(".")[1].length}catch(e){}   
      try{m+=s2.split(".")[1].length}catch(e){}   
      return  Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);    
    }   
    
  • 相关阅读:
    adfs环境安装
    joinquant网站
    test
    对C转换说明符的误解以及关于数组的一些知识
    正确求平方根的整数部分方法
    单链表的交换排序法
    链表的冒泡排序
    240页345题
    C语言中对数组名取地址
    单链表的基础操作练习
  • 原文地址:https://www.cnblogs.com/webLilingyun/p/5514951.html
Copyright © 2011-2022 走看看