javascript面试题

最近正准备面试的事情,自认为对js还算有一点理解,找一些面试题来测试测试自己。
本文的题目来源 https://leohxj.gitbooks.io/front-end-database/content/interview/interview-exercises-with-JavaScript.html
是我在网上随便搜的javascript面试题,做下来感觉还不错,所以推荐,并写下这篇文章。

题目一:
对原始对象的理解,
var a = 1;
a.a = 2;
console.log(a.a); //undefined
js使用var来定义变量,根据所赋值的情况,动态决定变量的类型。此处变量a的类型为Number类型,所有基本类型(String, Bool, Number, Null, Undefined),都是继承自Object类型,所以当变量a使用.操作符时可以调用toString等方法。但是给基本类型添加属性或方法时,第二句代码 a.a = 2,这里给变量a添加了属性a并赋值为2,当执行到第三句代码时,变量a中的属性a已经被销毁,所以调用a.a的结果是undefined。
考点:基本类型继承Object,所以基本类型的变量有方法和属性,但是基本类型不支持直接添加属性或方法,添加后的属性或方法会直接被销毁,生命周期只有一句代码的时间。

题目二:
对引用类型的理解,这道题目也把我弄糊涂了,
var a = {n:1};
var b = a;
a.x = a = {n:2};
alert(a.x) //undefined
alert(b.x) // [Object Object]
这道题目我们可能会想当然的以为a.x的值为{n:2}, b.x的值为undefined。结果恰恰相反,我们不妨把第三句代码改写一下,a = a.x = {n:2},相信如果这么写的话,得出的结果就和答案是一样的了,这个大家应该都能看得懂。那为什么第三句赋值顺序变了,结果却不变呢?原因在于.操作符在js中的优先级高于=操作符。所以当代码执行到第三句时,首先会执行.操作而不是=操作,为变量a声明一个属性x,而b和a都是指向同一个对象,所以给这个对象添加了一个属性x,等同于给b添加了一个属性x,然后给a赋值,变量a指向了另一个对象{n:2}。而给a.x赋值其实就是给刚才声明的属性x赋值,如果还是以为给变量a添加属性那就错了,解释器已经把a.x认为是一个变量了,因为刚才声明过了,所以现在只是赋值。所以结果很明显,a执行另外一个对象,该对象没有属性x,所以值为undefined。而b指向的对象因为添加了x属性,所以值为{n:2}。
考点:引用类型赋值我们做的很多,但是操作符的优先级对引用类型赋值的影响,在这道题目里体现的尤其淋漓尽致。

题目三:
对类型转换的理解,不要小看了类型转换
function foo1(a){
return a + ‘01’;
}
foo1(01); //“101”

function foo2(a){
return a + ‘010’;
}
foo2(010); //“8010”

console.log(0.1+0.2) //0.30000000000000004

var foo = ‘11’ + 2 - ‘1’;
console.log(foo); //111
console.log(typeof foo); //number
js对于不同类型的值进行运算的时候,有规定的转换规则。如果就字符串和数值类型进行加法运算,解释器会先将数值转换为字符串,然后进行字符串拼接。第四行代码foo1(01)执行后,首先数值01代表八进制,将其转换成十进制后变成1,然后1再转换成字符串”1”,最后字符串”1”和”01”拼接称为”101”。
如果就字符串和数值类型进行减法运算,解释器会将字符串转换成数值类型,然后进行数值运算。最后一行代码可以看出,经过减法运算之后的变量foo,其类型是number类型。
考点:不同类型之间的运算,会产生类型转换。如果字符串和数值类型进行加法运算,其值为字符串类型。如果字符串和数值类型进行减法运算,其值为数值类型。

题目四:
对基础代码的使用理解
(1)生存[x,y]范围内的随机数,此题没有绝对答案
function Random(x,y){
if(x >= y){
return ‘x 必须小于 y’;
}
var r = Math.random();
var ry = r * y;
if(ry < x){
return x + r;
}
return ry;
}
(2)已知数组 var stringArr = [‘This’, ‘is’, ‘Ali’, ‘Pay’], Alert出”This is Ali Pay”,此题考点在于对数组join方法的使用
stringArr.join(‘ ‘);
(3)已知有字符串 foo = “get-element-by-id”,写一个function将其转化成驼峰表示法”getElementById”,此题考点在于对数组split和substr方法的使用
function CamelHump(foo){
if(typeof foo !== ‘string’){
return ‘请输入字符串!’;
}
var strArr = foo.split(‘-‘);
var newStr = ‘’;
for(var i = 0; i < strArr.length; i++){
if(i == 0){
newStr += strArr[0];
}else{
var word = strArr[i];
word = word[0].toUpperCase() + word.substr(1,word.length - 1);
newStr += word;
}
}
return newStr;
}

(4)实现 var numberArray = [3,6,2,4,1,5]的倒序排序,此题考点在于数组sort方法可以接受匿名函数,匿名函数实现排序
numberArray.sort(function(num1, num2){
return num2 - num1;
})

(5)怎样添加、移除、移动、复制、创建和查找节点,此题我知道的不全,jquery使用多了,原始的对dom节点的操作就疏忽了
createElement() //创建一个新的节点,this指向document对象
appendChild() //添加一个创建的节点,this指向具体节点对象
removeChild() //移除一个添加的节点,this指向具体节点对象
insertBefore() //在特定的位置插入节点,this指向具体节点对象,此方法和移除方法联合使用,可以达到移动节点的效果
cloneChild() //复制一个已经存在的节点,this指向具体节点对象
getElementById() //通过元素的id查找,this指向document对象
getElementByClassName() //通过元素的class查找,this指向document对象

(6)将一个#ffffff类型的数据转换为rgb(255,255,255)形式,此题考点在于对正则表达式以及parseInt方法的使用
function Hex2RGB(hex){
if(hex.indexOf(‘#’) == -1 || hex.length != 7){
return ‘请输入十六进制格式的数据’;
}
var patt = /[\x61-\x66,\x41-\x46,\x23,\x30-\x39]/g;
var match = hex.match(patt);
if(match.length != 7){
return ‘请输入十六进制格式的数据’;
}
var rStr = hex.substr(1,2);
var gStr = hex.substr(3,2);
var bStr = hex.substr(5,2);
var rInt = parseInt(rStr, 16);
var gInt = parseInt(gStr, 16);
var bInt = parseInt(bStr, 16);
return ‘rgb(‘ + rInt + ‘,’ + gInt + ‘,’ + bInt + ‘)’;
}

题目五:
对正则表达式的理解,正则表达式也是我一直忽略的知识点
(1)去除字符串中的多余空格,如果使用\s作为匹配,有没有消除不了的情况? 此题考点在于对正则表达式\s的应用
正常情况下
function TrimSpace(str){
var patt = /\s/g;
return str.replace(patt, ‘’);
}
但是如果遇到全角的空格时,\s就不会匹配,起不到消除的作用了。

(2)写一个函数escapeHtml,将<,>,&,”进行转义,此题考点在于replace方法的第二个参数支持一个匿名函数,该匿名函数返回匹配的修改后的字符
function escapeHtml(html){
var patt = /[<>&”]/g
return html.replace(patt, function(match){
switch(match){
case ‘<’:
return ‘<’;
case ‘>’:
return ‘>’;
case ‘&’:
return ‘&’;
case ‘\”‘:
return ‘"’;
}
});
}

题目六:
实现一个函数clone,可以对js中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制,此题考点在于基本类型和引用类型的理解,递归算法的引入。
function clone(obj){
var copy;
if(obj == null || obj == undefined){
return obj;
}
if(typeof obj == ‘number’ || typeof obj == ‘string’ || typeof obj == ‘boolean’){
copy = obj;
}
if(typeof obj == ‘object’){
if(Array.isArray(obj)){
copy = [];
for(var item in obj){
if(typeof obj[item] == ‘object’){
copy.push(clone(obj[item]));
}else{
copy.push(obj[item]);
}
}
}else{
copy = {};
for(var prop in obj){
if(typeof obj[prop] == ‘object’){
copy[prop] = clone(obj[prop]);
}else{
copy[prop] = obj[prop];
}
}
}
}
return copy;
}

题目七:如何消除一个数组里重复的元素?此题考点在于对数组includes方法的使用。
function rmDuplicates(obj){
var newArr = [];
if(obj instanceof Array){
for(var item in obj){
if(!newArr.includes(obj[item])){
newArr.push(obj[item]);
}
}
}else{
return obj;
}
return newArr;
}
参考了一下网上的做法,它使用了数组的filter方法,来进行内容过滤。巧妙就巧妙在filter方法接受的匿名函数的参数elem指的是当前元素,pos指的是当前元素的位置,self指的是数组本身。代码 self.indexOf(elem) == pos 返回第一个与elem元素匹配的索引,就算后面还有其它元素和elem元素匹配,依然只选择第一个。
myArray.filter(function(elem, pos, self){
return self.indexOf(elem) == pos;
});
这种做法很巧妙,写起来也简便,但需要建立在对filter方法的理解与indexOf的理解之上。

题目八:编写一个js函数,输入指定类型的选择器(仅需支持id,class,tagName三种简单css选择器,无需兼容组合选择器)可以返回匹配的dom节点,需要考虑浏览器的兼容性和性能。本题考点在于浏览器的兼容性问题,通过id,class,tagName选择dom节点,不是所有浏览器都是一样的写法。还有如何将查询dom提升到性能层次,这些我都不知道。
function findDom(selector){
var dom;
if(selector.indexOf(‘#’) != -1){
dom = document.getElementById(selector.split(‘#’)[1]);
}else if(selector.indexOf(‘.’) != -1){
dom = document.getElementsByClassName(selector.split(‘.’)[1]);
}else{
dom = document.getElementsByTagName(selector);
}
return dom;
}

题目九:
理解一下sort排序的原理,此题考点在于对与数组的sort方法是如何进行排序的原理的探究。
对于未传入任何参数的sort方法而言,数组的排序基于ascii码的十进制数的大小来排。sort方法接受一个匿名函数,该匿名函数会将数组中的数两两进行对比,根据返回值的不同,决定最终的排序方式。

题目十:
apply和call方法的异同,此题考点,对于apply和call方法的区分,以及对二者的共同点的总结。
共同点:二者都能改变调用方法时的变量对象的值,也就是调用方法中this的值。而这也是这两个方法最最普遍以及最最核心的功能。所传入的变量对象,都是以第一个参数的形式,被传入方法中的。如果什么参数都不传,直接调用方法的话,默认使用apply或者call方法的变量对象。
不同点:二者的第二个以及第二个以后的参数都不一样。apply的第二个参数是以数组的形式,即如果有多个参数要传递,将这多个参数放到一个数组中,然后作为apply方法的第二个参数来进行调用。而call方法的第二个参数以及第二个以后的参数,分别按照要传几个参数,就传几个参数的原则,添加到call方法第二个参数的后面,进行调用。

avatar

chilihotpot

You Are The JavaScript In My HTML