JavaScript面试时候的坑洼沟洄——数据类型

时间:2021-06-30 08:05:08

前些日子写了篇关于最近找工作的一些感受的博客 找工作的一些感悟——前端小菜的成长,没想到得到了很多园友的共鸣,得到了很多鼓励,也有园友希望我分享一些笔试、面试的经验。我觉得分享一些笔试题没太多价值,对读者帮助不大,自己总结了一些笔试、面试常用的知识点,希望可以给想找工作的同学一些借鉴。

有兴趣同学可以看看前些日子总结的一些面试中经常被问到的问题的博客,目前主要写了关于CSS和JavaScript,会持续把一些经历分享出来

容易被忽略CSS特性

常用CSS优化总结——网络性能与语法性能建议

常见标签的默认属性值及相互作用——关于CSS reset的思考

CSS清浮动处理(Clear与BFC)

最简单的JavaScript模板引擎

简单JavaScript模版引擎优化

JavaScript 正则表达式上——基本语法

JavaScript正则表达式下——相关方法

常常让我们阴沟里翻船的基础知识

之前总结的都是一些知识面的,会就是会,不会也答不出来,但在JavaScript笔试过程中经常会遇到一些自己觉得明明很简单,但答案却让人莫名其妙的问题,更有一些题目都会让人目瞪口呆的问题,在笔试过程中出错的几乎都是这类问题。你肯定见过这样的题目

var f = function g(){ return 23; };
typeof g();//g is not defined

或者这样的题目

var foo = 1;
function bar() {
foo = 10;
return;
function foo() {}
}
bar();
console.log(foo);//1

很多类似的题目,让人头痛的很,答案和自己认为肯定的不一样(后续博客会有相关分析),吃过很多次亏后也尝试在网上找一些JavaScript Quiz来做,每次做的时候被虐的体无完肤,做完之后会觉得自己可以应付笔试了,但在下次笔试的时候又死在类似题目上,痛定思痛把常出错的JavaScript知识点梳理了一下后,正确率果真提高了不少,发现其实都是一些JavaScript基础的语法知识,如果我们在笔试的时候总在JavaScript坑洼沟洄里摔倒而不是知识面上,那么就有必要了解一下这些不起眼的基础知识了,所以正经介绍面试经历的博客我希望以基础知识开始。文中主要内容都是看了《JavaScript权威指南》后了解的,真心推荐找工作的同学耐住性子读读这本好书。

让我们从JavaScript类型开始

JavaScript数据类型很简单,有原始类型(primitive type,也就是大家口口相传的值类型)和对象类型(所谓的引用类型)两类

原始类型

number、string、boolean、null、undefined

对象类型

object、function、Date、Array等

也许你认为很简单,但如果没系统学习过,简单的数据类型在笔试、面试中也是很凶险的,先了解一下这几个类型的特点

  • string

    在很多编程语言中string类型都是引用类型,JavaScript中的string却是基本类型,在JavaScript中字符串是一组由16位值组成的不可变的有序序列,每个字符通常来自Unicode字符集(《JavaScript权威指南》)。在JavaScript中所有基础类型都不可以修改,这句话对于number等类型好理解,1变不成2,但是string "abc"不是可以变成"abcd"吗?其实所有我们认为修改字符串的方法只是返回了一个新的字符串。

  • number

    和大多数编程语言不同,JavaScript的number类型不区分整数和浮点数,所有数字都适用浮点数表示。

  • bool

    这个比较简单,该类型就是true和false两个值

  • null

    null对程序员来说并不陌生,表示未定义(声明)过的变量

  • undefined

    null表示“空”了,undefined是什么东东?我们知道像Java这样的强类型语言中如果我们声明一个变量而不初始化,系统会根据变量类型为其赋值该类型的默认值,但在JavaScript中我们声明变量靠的是var关键字(甚至可以不写),变量的类型是由其value决定的,为其赋值为数组,那么变量就是数组类型,为其赋值数字,变量就是number,但是如果我们不初始化呢?总不能说变量是null吧,毕竟这个变量已经得到声明,这时候我们就把该变量认为是undefined类型变量,并为其赋值undefined类型唯一值——undefined(不是"undefined")

包装对象

我们经常见到一些这样的代码

var s='test';
console.log(s.indexOf(e)); //1
console.log(s.length); //4

乍一看没什么奇怪的,但是不是说好的string是基本类型吗?基本类型的变量哪里来的方法和属性!暂且放过这个知识点,反正能这么用就是了,看个题

var s='test';
s.len=4;
console.log(s.len);//undefined

坑爹!怎么不是4又变成undefined了?只要引用了字符串属性,JavaScript就会通过调用 new String(s) 来创建一个临时对象,我们使用的indexOf方法和length属性正是来源于这个临时对象,每次使用都创建一次,然后销毁。这个临时对象就是包装对象,不只是string,number和boolean类型同样有包装对象。知道了这些知识看看上面的题目为什么结果是undefined

上面代码可以这样解析

var s='test';//创建字符串类型变量
s.len=4;//创建包装对象,为包装对象添加属性len
//引用完毕,销毁包装对象
console.log(s.len);//创建包装对象,查找其len属性,没有找到,返回undefined

这下明白了吧

类型转换

在笔试题中经常会遇到一些难题解决最后却死在阴沟里的题目,类型转换就经常充当阴沟,看个例子

var a=[0], b=a, b=[1];
console.log(a+b);

我们搞定了数组的问题,最后问题可以变为[0]+[1],一不小心就会写为1,但是这时候我们调用的是数组的toString方法,实际是'0'+'1'='01',这时候就可以看出类型转换知识的重要性了。

JavaScript的取值类型非常灵活,会根据需要自动转换类型,比如

1+'234'

JavaScript会自动把1转换为期望的字符串"1",这种转换时非常明显的,我们看一些平时可能会弄错的默认转换

转换为字符串 转换为数字 转换为布尔值
undefined "undefined" NaN false
null "null" 0 false
true "true" 1
false "false" 0
"" 0 false
"2.5" 2.5 true
"string" NaN true
0 "0" false
1 "1" true
NaN "NaN" false
Infinity "Infinity" true
[2] "2" 2 true

显式的类型转换(调用构造函数或者parseInt()函数等)我们很轻松可以发现,但JavaScript很多操作符都能引发隐式的类型转换

Number("3");//3
String(false);//false
Boolean([]);//true
Object(3);//new Number(3)
1+"234";//"1234"
5+"";//String(5)
+"5";//5,变成了数字 Number("5")
"5"-0;//5,也是数字

toString和valueOf

在一些情况下我们会把对象转换为基本类型,对于转换为布尔值规则很简单,所有的对象都会转换为true,然而我们最常用的是把对象转换为字符串或数字,这就比较麻烦了

对象转为字符串

对象转换为字符串过程大概是这样

  1. 如果对象具有toString方法则调用该方法,如果方法返回的是一个基本类型(有坑爹的toString方法不返回string类型的),JavaScript把这个值转换为字符串返回
  2. 如果对象没有toString方法,或者该方法返回的不是一个基本类型,那么就会调用valueOf方法,如果存在valueOf方法并且valueOf返回的是基本类型,那么将值转换为字符串输出
  3. 再如果就只能报错了

对象转为数字

对象转换为数字过程大概是这样

  1. 如果对象有valueOf方法,并且方法返回基本类型,则把值转换为数字返回
  2. 如果对象具有toString方法,且方法返回基本类型,则转换为数字返回
  3. 否则就报错

上面情况只是针对强制转换,也就是我们显示的调用String或者Number构造函数的时候的处理,在平常使用中,在”显示“相关操作中会优先调用toString方法,而在运算相关操作中会优先调用valueOf方法。

看个题目

var o = {
x: 8,
valueOf: function(){
return this.x + 2;
},
toString: function(){
return this.x;
}
};
console.log(String(o));//"8"
console.log(Number(o)); //10
console.log(o+1);//11,运算相关
alert(o);//"8",显现相关

注意返回的一个是字符串,一个是数字,了解了上面基本知识,你是不是答对了

判断数据类型

我们可以使用typeof运算符来判断数据类型

typeof undefined; //"undefined"
typeof null; "object"
typeof true; "boolean"
typeof 0; //"number"
typeof NaN; //"number"
typeof "string"; //"string"
typeof function(){}; //"function"
typeof []; //"object"
typeof new Date(); //"object"

有几个看起来比较蹊跷需要我们注意

  1. typeof是运算符,不是方法,也就是说和加减号一样用,不考虑优先级问题,没必要给操作数加括号,当然加了也没事儿,说实话可读性还挺高
  1. typeof返回值都是小写字符串
  1. null的类型不是null,而是"object"
  1. NaN这个不是数字的类型也是"number"
  1. function明明也是对象,但是typeof却给了"function"类型
  1. 其它对象都返回"object",很没有识别性

具体识别对象类型使用instanceof 操作符,这个记住一点儿就行,对于基本类型,instanceof 永远返回false

1 instanceof Number; //false
new Number(1) instanceof Number; //true

最后

本来就想写一些知识点来阐述一些面试题,越写内容越多,而且发现盘根错节,只好老老实实从最基础的谈起,有了这些基本知识接下来就能小步快跑了,接下来会更新一些“干货”内容,不再是干巴巴的理论知识,不过都得建立在前几篇基础上才行

  • JavaScript面试时候的坑洼沟洄——数据类型

  • JavaScript面试时候的坑洼沟洄——表达式与运算符

  • JavaScript面试时候的坑洼沟洄——逗号、冒号和括号

  • JavaScript面试时候的坑洼沟洄——预解析

PS.

让人望而生畏的JavaScript认真总结下来无非这些毫不起眼的基础知识,地基打好了,JavaScript的坑洼沟洄就都能够应付自如了。另外一直在寻找Mac上比较好用的博客客户端,感觉都不如Windows live Writer,惊闻博客园支持Markdown语法了,赶紧试试,开始时有些费力,不过熟悉了几个简单的语法后真的好方便。建议没有用过的同学尝试一下