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);    
}   
原文地址:https://www.cnblogs.com/webLilingyun/p/5514951.html