分享:JavaScript常见面试题

JavaScript

1.1 简要描述JavaScript的数据类型?

JavaScript的数据类型可以分为原始类型和对象类型。

原始类型包括stringnumberboolean三种。其中,字符串时使用一对单引号或者一对双引号括起来的任意文本;而数字类型都采用64位浮点格式存储,不区分整数和小数;布尔(逻辑)类型只能有两个值:truefalse

复杂类型指其他对象,如ArrayDateObject等。

除此之外,JavaScript中海油两个特殊的原始值: null(空)和undefined(未定义),它们代表了各自特殊类型的唯一成员。

1.2 读代码,写结果

写出下列表达式的计算结果:         上述代码的结果分别为:

var a=[];

var b=a;

b[0]=1;

console.log(a[0]);                  1

console.log(b[0]);                  1

console.log(a===b);               true

将对象赋值给变量,仅仅数赋值的引用,对象本身并没有赋值一次,因此,变量a和变量b指向同一个数组。

1.3 简要描述null和undefined的区别

null :是JavaScript的关键字,用于描述空值,对其执行typeof操作,返回object,即为一个特殊的对象值,可以表示数字、字符串和对象时无值的。

undefined :是预定义的全局变量,其值为未定义,它是变量的一种取值,表示变量没有初始化。当查询对象属性、数组元素的值时,如果返回undefined则表示属性或者元素不存在;如果函数没有任何返回值,也返回undefined

需要注意的是,虽然nullundefined是不同的,但是因为都表示值的空缺,两者可以互换。因此,使用==任务二者是相等的,需要使用===来区分它们。

1.4 读代码,写结果

写出下列表达式的计算结果:   上述代码的结果分别为:

10+object    10object  //转换为字符串

7 * 428      //转换为字符

1 - xNaN  //无法转换为数值进行计算,因此返回NaN

1 + { }1[object object] //返回对象的toString()结果按照字符串相加

true + true//bool类型转换为数字类型

2 + null2//null转换为数值0

1.5 读代码,写结果

写出下列表达式的计算结果:   上述代码的结果分别为:

var a=2;

var obj={x:1,y:{z:2}};

Var n=[obj,3,[4,5]];

console.log(a<<2);8

console.log(obj[y].z);2

console.log(n[0].y[z]);2

console.log(n[2][1]);5

delete n[0];
console.log(n[0].x);此行代码错误输出Error

1.6 阅读如下代码

var x=10;

var y=20;

var z=x<y?x++:++y;

上述代码运行后,变量xyz的值是多少?

答案:上述代码运行后,变量想x的值为11;变量y的值为20;变量z的值为10

这是因为,运行第三行代码时,只执行?后的第一个语句,因此,y的值不发生变化,仍为20;并返回x的值赋值给变量z,因此z的值为10,然后将x的值增加1,变为11

1.7 什么是逻辑短路

逻辑短路时对于逻辑运算而言,是指仅计算逻辑表达式中的一部分便能缺点结果,而不对整个表达式进行计算的现象。

对于&&运算符,当第一个操作数为false时,将不会判断第二个操作数,吧、因为此时无论第二个操作数为何,最后的运算结果一定是false

对于 || 运算符,当第一个操作数为true时,将不会判断第二个操作数,因为此时无论第二个操作数为何,最后的运算结果一定是true

1.8 阅读如下代码

var empAge=20;

var empName;

if(empAge>20&&empName.length>0){

console.log(1);

}else{

console.log(2);

}

上述代码运行后,将产生有效输出,还是代码错误?

参考答案:上述代码运行,会输出2,而不会发生错误。

这是因为,if条件中的逻辑表达式的第一个条件(empAge>20)不满足,会返回false,此时将发生逻辑短路,而不会继续判断下一个条件。因此,即使下一个条件中的变量empName没有赋值,此时如果计算empName.length将发生错误;但是,因为发生了逻辑短路,不会计算此表达式,因此不会发生错误。

既然if条件中的逻辑表达式返回false,则运行else语句:输出2

1.9 解释一下JavaScript中的局部变量与全局变量区别

全局变量拥有全局作用域,在JavaScript代码的任何地方都可以访问;在函数内声明的变量只是在函数体内有定义,即为局部变量,其作用域是局部性的。

需要注意的是,在函数体内声明局部变量时,如果不使用var关键字,则将声明全局变量。

1.10 读代码,写结果

写出下列代码的输出结果:

var x=global;

function test(){

var x=local;

return x;

}

console.log(test());

参考答案:上述代码的输出结果为local。这是因为,在函数test()体内,局部变量的优先级高于同名的全局变量。因此,如果在函数体内声明的局部变量和全局变量重名,则以局部变量优先。因此,调用函数test()时,返回的是局部变量x,其值为local

1.11 什么是JavaScript中的函数作用域

JavaScript中的函数作用域是指:变量在声明它的函数体以及这个函数体嵌套的任意函数体内都有定义的。这意味着,在函数体内声明的所有变量在整个函数体内始终是可见的,这种特性也被称为“声明提前”,即函数内声明的所有变量(不涉及到赋值)都被提前至函数的顶部声明。

比如,查看如下代码:

function test(){

console.log(x);

var x=10;

console.log(x);

}

test();

上诉代码运行,将先输出undefined,再输出10.

这是因为,虽然变量x在第二行声明并赋值,丹其有效范围为整个函数体,因此,第一行代码输出时,表示变量x已经声明但是没有赋值,因此输出undefined;第三行代码运行时,因为变量x已经赋值为10,则输出10

1.12 读代码,写结果

写出下列代码的输出结果

function test(){

var sum=0;

for(var i=0;i<10;i++){

sum+=i;

}

console.log(sum);

console.log(i);

}

test();

上述代码中,输出sum的值为45;输出i的值为10

这是因为,在函数test()体内,循环计算完毕后,变量sum的值从0累加到10的和即为45;变量i虽然是在for循环中声明,但是在整个函数体内都有效(函数左右域),因此,循环完毕后,变量i的值为10

1.13 读代码,写结果

写出下列代码的输出结果:

var x=global;

function test(){

console.log(x);

var x=local;

console.log(x);

}

test();

上述代码中,先输出undefined,再输出local

函数test()体内声明了与全局变量同名的局部变量x,则将覆盖全局变量,即局部变量优先。因此,第一次输出变量x时,为输出局部变量x,此时变量x只有声明而没有赋值,因此输出undefined;第二次输出变量x时,局部变量x已经赋值,因此输出字符串local

1.14 简述arguments对象的作用

在函数代码中,使用特殊对象arguments可以访问函数的参数。即开发者在定义函数时,无需明确的为方法声明参数,也可以在方法体中使用arguments来访问参数。这是因为,arguments是一种特殊对象,在函数代码中,表示函数的参数数组。

正因为arguments表示参数组成的数组,因此,首先可以使用arguments.length检测函数的参数个数,其次,可以通过下标(arguments[index])来访问某个参数。这样可以用arguments对象判断传递给函数的参数个数并获取参数,适用于函数参数无法确定个数的情况下。

1.15 简要描述JavaScript中定义函数的几种方式

JavaScript中,有三种定义函数的方式:

函数语句:即使用function关键字显示定义函数。如:

function f(x){return x+1;}

函数定义表达式:也称为“函数直接量”。如:

Var f=function(x){return x+1;}

使用Function()构造函数定义。如:

var f=new Function(x,return x+1;);

1.16 读代码,写结果

写出下列代码的输出结果:

var f=function (x) {return x*x;}

console.log(f);

console.log(f(10));

上述代码运行时,先输出function(x) {return x*x;};再输出100

这是因为,变量f代表一个函数对象,因此直接输出变量时,将输出函数体对应的字符文本;f(10)表示调用变量f所对应的函数,返回100并输出。

1.17 阅读如下代码

function f(){

console.log(function);

}

function test(){

console.log(f);

f();

f=hello;

console,log(f);

f();

}

test();

上述代码运行,会先输出:function f(){console.log("function");};然后输出function;再输出hello;然后会输出异常信息:string is not a function

这是因为,定义函数时,函数名称作为一个全局变量,该变量指向函数对象。因此,执行函数test中的第一行代码时,将输出变量f所对应的函数对象,即输出函数体中代码的字符串形式;然后执行f()表示调用方法f,则输出字符串function;执行代码f=hello,意味着将变量f的值改为字符串,因此再输出变量f时,将输出字符串hello;而如果试图再执行f(),会引发错误。这是因为,此时,变量f不再是一个函数对象,而是一个普通字符串。

1.18 列举几个JavaScript中常用的全局函数,并描述其作用

JavaScript中常用的全局函数及作用如下:

parseInt:解析一个字符串并返回一个整数;

parseFloat:解析一个字符串并返回一个浮点数;

isNaN:检查某个值是否是数字,返回true或者false

encodeURI:把字符串作为URI进行编码;

decodeURI:对encodeURI()函数编码过的URI进行解码;

eval:计算某个字符串,以得到结果,或者用于执行其中的JavaScript代码。

1.19 阅读如下代码

function printArray(arr){

for(var i in arr){

if(arr[i]  instanceof  Array){

printArray(arr[i]);

}else{

document.write(arr[i]+ );

}

}

}

var data=[1,[20,32],[[301,302],[310,311]]];

printArray(data);

上述代码运行后,页面是输出:1 20 32 301 302 310 311

函数parintArray使用了地柜方式,逐一输出数组中的每个成员,中间以空格隔开。

1.20 编写函数,实现冒泡排序

使用JavaScript便也的冒泡排序函数如下所示:

function bubbleSort(arr){

for (var i=0;i<arr.length;i++){

for(var j=0;j<arr.length;j++){

if(arr[i]>arr[j+1]){

var temp=arr[j+1];

arr[j]=arr[j+1];

arr[j+1]=temp;

}

}

}

}

var arr=[12,4,9,21,43,3];

bubbleSort(arr);

console.log(arr);

上述代码运行时,将输出排序后的结果:[3,4,9,12,21,43]

1.21 编写代码,实现插入排序

插入排序是指,先假定将n个元素的数列分为有序和无序两个部分;然后将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。过程如下图所示:

 

使用JavaScript编写的插入排序函数如下所示:

function insertionSort(arr){

for(var i=1;i<arr.length;i++){

var k=arr[i];

var j;

for(j=i-1;j>=0&&k<arr[j];j--){

arr[j+1]=arr[j];

}

arr[j+1]=k;

}

}

var arr-[12,4,9,21,43,3];

insertionSort(arr);

console.log(arr);

上述代码运行时,将输出排序后的结果:[3,4,9,12,21,43]

1.22 编写函数,实现对身份证号码最后一位的验证

二代身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:

7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2

将这17位数字和系数相乘的结果相加

用加出来和除以11,看余数是多少?

余数只可能有0 1 2 3 4 5 6 7 8 9 1011个数字。每个数字所对应的最后一位身份证的号码为1 0 x 9 8 7 6 5 4 3 2。即如果余数是2,就会在身份证的第18位数字上出现罗马数字的X。如果余数是10,身份证的最后一位号码就是2

例如:某男性的身份证号码是34052419800101001X。验证其最后一位是否正确是,首先需要得出前17位的乘积和是189,然后用过189除以11得出的结果是17+2/11,也就是说其余数是2.最后通过对应规则就可以知道余数2对应的数字是x。所有,可以批判次身份证号码的最后一位是合格的。

编写验证方法如下: 

function verifyCode(id){

if(id.length!=18){ return false;}

var arr=[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];

var sum=0;

for(var i=0;i<arr.length;i++){

sum+=parseInt(id.charAt(i))*arr[i];

}

var c=sum%11;

var ch=[1,0,x,9,8,7,6,5,4,3,2];

var code=ch[c];

var last=id.charAt(17);

last=last==x?x:last;

return last==code;

}

var id=34052419800101001X;

console.log(verifyCode);

1.23 读代码,写结果

写出下列代码的输出结果:

var arr1=[10,20];

arr1.push(30);

arr1.push([40,50]);

var data=arr1.pop();

console.log(data);

上述代码的输出结果为[4.50]

数组的方法push()表示入栈,即在栈顶(数组尾端)添加指定的元素;方法pop()表示出栈,删除并返回栈顶(数组尾端)的元素。

代码中,第一次入栈为数字30;第二次入栈为数组[40,50],且该数组排在栈顶。因此,调用方法pop()时,将删除并返回栈顶元素[40,50,],这是一个数组,因此输出结果为[40,50]

1.24 什么是栈?在JavaScript中,如何模拟栈操作?

(stack)是一种运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。栈的操作如下图所示:

 

JavaScript中,可以使用数组及其相关操作来模拟栈操作。首先,使用数组存储一列元素,然后使用数组的push()方法在数组的尾部添加指定的元素,类似于在栈顶添加元素,即顶部入;然后使用数组的pop()删除并返回数组尾部的元素,类似于顶部出栈,即后入的元素先出。

1.25 读代码,写结果

写出下列代码的输出结果:

var arr1=[10,20,30,40];

arr1.push(50);

arr1.shift();

console.log(arr1);

上述代码的输出结果为[20,30,40,50]

数组的方法push()表示入栈,即在栈顶(数组尾端)添加指定的元素,因此,数字50将作为数组的最后一个元素;方法shift()表示删除并返回栈底(数组头部)的元素,因此,将从数组删除数值10.此时,输出数组,将输出剩余的4个数值,即[20,30,40,50]

1.26 什么是正则表达式?在JavaScript中,如何让应用z正则表达式?

正则表达式本身就是一个字符串,由一些普通字符和特殊字符组成的,用以描述一种特定的字符规则的表达式。

正则表达式常用于在一段文本中搜索、匹配或替换特定形式的文本。如:词语出现频率统计、验证字符串是否符合邮箱格式、屏蔽一片帖子中的限制性词语等。许多程序设计语言都支持利用正则表达式进行字符串操作。

JavaScript中,正则表达式的应用分为两种:

1.结合string对象的replacesearchmatch()方法,实现对字符串的替换、查找和匹配;

2.定义正则表达式对象,实现对字符串的复杂匹配操作。

1.27 读代码,写结果

写出下列代码的输出结果:

var regxp=/\bdo\b/ig;

var data=he does told to Do do.;

console.log(data.search(regexp));

上述代码的输出结果为3

String search(regexp)方法,用于返回第一次出现匹配指定正则表达式的下标,若没有匹配则返回-1.

代码中,正则表达式式\bdo\b表示匹配完整的单词do,且不区分大小写。而变量data中,第一次出现单词do(不区分大小写)的位置是16

1.28 阅读如下代码

function add(num) {

try {

num = Number(num);

if (isNaN(num)) {

throw new Error('Arguments is NaN');

}

console.log('try block end');

} catch (e) {

console.log('catch block');

return;

} finally {

console.log('finally block');

}

console.log('function end');

}

add('10x');

这是因为,执行代码num = Number(num);时,因为传入的参数值为字符串“10x”

无法转换为number 类型,则产生错误,运行到catch语句块中,输出“catch bloc”

finally块始终会运行,因此继续输出“finally block”。程序发生异常后,将退出,因此不再执行其他语句。

1.29.简要描述JavaScript中的匿名函数

参考答案:匿名函数是指在定义时没有指定名字的函数,且定义后往往直接调用。如:function(num1, num2){console.log( num1 + num2 );}这种方式所定义的匿名函数,往往需要直接调用,如:(function (num1, num2) {console.log(num1 + num2);})(10,20);匿名函数常用于定义不需要重复使用的函数,用完即释放。另外,对于直接调用的匿名函数而言,可以看成是一个临时的命名空间,其区域内定义的所有变量,不会污染到全局命名空间。

1.30简要描述JavaScript 中的作用域链

参考答案:任何一段JavaScript代码都对应一个作用域链,作用域链中存放一系列对象,代码中声明的变量将作为对象的属性存放。

JavaScript的顶层代码中,作用域链由一个全局对象组成;当定义一个函数时,它保存一个作用域链,作用域链上有两个对象,一个是函数对象,一个是全局对象。每当一个函数被调用时,会创建一个活动对象(也叫上下文对象),函数中的局部变量将作为该对象的属性存放。当需要使用一个变量时,将从作用域链中逐个查找对象的属性。比如:要使用变量a,将先查找作用域中的第一个对象是否有属性a,如果有就使用;如果没有就查找作用域链中下一个对象的属性,以此类推。如果作用域链上没有任何一个对象含有属性x,则认为这段代码的作用域链上不存在x,将抛出引用错误异常。当函数调用完成后,如果没有其他引用指向为此次调用所创建的上下文对象,该对象将被回收。

1.31.阅读如下代码

var a = 100;

function f() {

var a = 200;

function g() {

return a;

}

return g;

}

console.log(f()());

上述代码运行后,输出结果为?

参考答案:上述代码运行,会输出200

上述代码意味着,先执行f(),得到该函数内嵌套的一个函数对象g,然后调用这个嵌套的函数。定义函数时,它保存一个作用域链,作用域链上有两个对象,一个是函数对象,一个是全局对象,此时,全局变量a是全局对象的属性,和函数对象无关。执行函数时,会创建一个活动对象,其中保存变量a作为函数的属性而存在。而函数g嵌套定义在函数f里,对其访问变量a时,它没有变量a,则继续往下查找函数f。找到函数的属性并返回。因此,输出结果为200。这种函数将变量包裹起来,外部代码可以通过内嵌函数g来访问函数内的局部变量的方式,也称为闭包。

1.32.简要描述你对闭包的理解

参考答案:

函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性称为闭包。这意味着函数变量可以隐藏于作用域链之内,看起来好像是函数将变量包裹了起来。这种方式常用于共享函数内的私有变量。

闭包有如下应用特征:

1、局部变量:在函数中定义有共享意义(如:缓存、计数器等)的局部变量(注:定义成全局变量会对外造成污染);

2、内嵌函数:在函数中声明有内嵌函数,内嵌函数对函数中的局部变量进行访问;

3、外部使用:函数向外返回此内嵌函数,外部可以通过此内嵌函数持有并访问声明在函数中的局部变量,而此变量在外部是通过其他途径无法访问的。

猜你喜欢

转载自blog.csdn.net/u013910042/article/details/50381940