欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2019 JavaScript 面试题

程序员文章站 2022-06-09 18:58:24
...

JS基础

  • continue和 break有什么区别?
    答:break和continue都是用来控制循环结构的:
    break终止循环,跳出循环体执行循环后面的语句。
    continue跳过本次循环,执行下一次循环。
  • i++和++i的区别?
    答:i++ :先用i值后加1,
    ++i :先加1后用i值,
    计算:var n=5; 求 var num=n++ + ++n + n++ + ++n +n; //37
  • ** JavaScript都有哪些数据类型?**
    答:原始类型:数值型/字符串型/布尔型/undefined/null 引用类型:对象
  • 自调用函数是什么?用于什么地方?
    答:立即执行的函数。 (function(){ //函数体 })();
    用于创建一个局部作用域。
  • slice和splice有什么区别?
    答:slice截取子数组 ,从指定的数组中,截取几个连续的元素组成一个新数组
    splice允许从指定数组中,删除一部分元素,同时再添加另一部分元素
  • typeof返回的类型有哪些?
    答:number 、string 、boolean 、undefined 、object 、function
    栗子:var arr=[1,2,3,4,5];
    console.log(typeof(arr)); //object
    function myDemo(){
    return function test(){};
    }
    console.log(typeof(myDemo())); //function
  • 取 1~11之间的随机数 (即包括1不包括11)?
    答:Math.floor(Math.random()*10+1)
    parseInt (Math.random()*10+1)
  • 什么是变量声明提前?
    答:使用var关键字声明的变量,会将声明提升到所在作用域的最前边。。
  • push、pop、shift和unshift 区别?
    答:这两组同为对数组的操作,并且会改变数组的本身的长度及内容。
    不同的是 push()、pop() 是从数组的尾部进行增减,unshift()、shift() 是从数组的头部进行增减。。
  • 例举4种强制类型转换和3种隐式类型转换?
    答:强制转换:parseInt/parseFloat/Number/toString
    ↓隐式转换 ↓:
    字符串+数值 数值转字符串
    数值+布尔型 布尔型中true转为1,false转为0
    字符串+布尔型 布尔型转为字符串。
  • 函数声明与函数表达式的区别?
		//相同点:两者都可以创建函数。
  		//不同点:函数声明可以存在函数提升(前),函数表达式不存在函数提升(前)。
	  		//函数声明
				function myFunction(){
  					function innerFunction() {}
				}
		 	//以下为函数表达式
				var myFunc = function(){};
					myFunc(function(){
 					return function(){};
				} );
  • 请指出JavaScript宿主对象和原生对象的区别?
    答:宿主对象:指JavaScript解释器提供的对象,由解释器厂家自定义并提供实现,
    不同的解释器提供的扩展对象存在较大的 差异(DOM和BOM对象)。
    原生对象:JavaScript语言本身预定义的对象,在ECMAScript标准中定义,由所有的解释器厂家来提供具体实现
    (Array,Date,Math,Number,String,Boolean等)。
  • js中有哪些内置函数?
    答:Object, Array, Boolean, Number, String, Function, Date, Math, RegExp, Error, Global
  • 列举出获取日期相关函数?
    答:console.log(Date.now()); // 返回当前日期和时间’1970/01/01 00:00:00’之间的毫秒值
    var dt = new Date(); // 获取当前时间—年 月 日 时 分 秒
    console.log(dt.getTime()); //返回当前日期和时间’1970/01/01 00:00:00’之间的毫秒值
    console.log(dt.getFullYear()); // 年份
    console.log(dt.getMonth()+1); // 月份(0-11)
    console.log(dt.getDate()); // 日期(0/1-31)
    console.log(dt.getDay()); //星期(0-6)
    console.log(dt.getHours()); // 小时(0-23)
    console.log(dt.getMinutes()); // 分钟(0-59)
    console.log(dt.getMilliseconds); // 返回毫秒(0-999)
    console.log(dt.getSeconds()); // 秒(0-59)
  • Math相关函数
    答:Math.random() - 返回 0 ~ 1 之间的随机数
    Math.abs(x) - 返回数的绝对值
    Math.ceil(x) - 向上取整
    Math.floor(x) - 向下取整
    Math.round() 四舍五入
    Math.max() 和 Max.min() 获取一组数据中的最大值和最小值
    Math.PI 获取圆周率π 的值
    Math.pow() 获取一个值的多少次幂
    Math.sqrt() 对数值开方
    Math.pow(10,2) = 100;
    Math.sqrt(100) = 10;
  • null和undefined的区别?
    答:undefined是访问一个未初始化的变量时返回的值,
    null是访问一个尚不存在的对象时所返回的值。因此,可以把undefined看作是空的变量,而null看作是空的对象。
  • ==(两个等号)和===(三个等号)有什么不同?
    答:== 抽象相等,比较时,会先进行类型转换,然后再比较值;
    ===严格相等,判断两个值相等同时数据类型也得相同。
  • setTimeout和setInterval的区别是什么?
    答:二者都是用来设置定时操作的。
    setTimeout: 设置一个定时器,在定时器到期后执行一次函数或代码段
    setInterval: 设置一个定时器,以固定的时间间隔重复调用一个函数或者代码段
  • 请说出以下代码执行结果?
				for (var i = 0; i < 3; i++) {
     				setTimeout(function() {
         			console.log(i);
      			}, 0);
      				console.log(i);
 				}
				//答案:0 1 2 3 3 3,执行过程如下
				var i = 0;
				console.log(i); i++;
  				console.log(i); i++;
  				console.log(i);i++;
 				setTimeout(function() {
      				console.log(i);
 				}, 0);
 				setTimeout(function() {
      				console.log(i);
 				}, 0);
 				setTimeout(function() {
      				console.log(i);
 				}, 0);  //输出 0 1 2 3 3 3
  • 请说出(true+flase)>2+true的执行结果?
    答:false
  • 当前代码块输出结果是什么?
		var z=10; 
 		function foo(){console.log(z);}
		(function(funArg){var z=20;funArg();})(foo);
		//答案: 10,自调用函数。
  • setTimeout(function(){},10)表示什么意思?
    答:每隔10毫秒调用一次函数。
  • 程序中捕获异常的方法?
	try{
	
	}catch(e){
	
	}finally{
	}
  • 以下代码执行结果?
		var uname = 'jack'
		function change() {
    		alert(uname) // ?
    		var uname = 'lily'
    		alert(uname)  //?
		}
		change()
	//答案:undefined lily
  • 如何使用npm下载express模块?
    答案:npm install express
  • split和join的区别?
    答:split()将字符串按照指定的字符分割成一个数组,并返回
    join()将数组用指定的字符连接成一个字符串,并返回
  • 看下列代码会有什么样的输出?
		var foo = "11"+2-"1";  
		console.log(foo);
		console.log(typeof foo);
		//答案:111  number
  • foo = foo||bar ,这行代码是什么意思?为什么要这样写?
	//这种写法称之为短路表达式,相当于:
			var foo;
			if(foo){
    			foo=foo;
			}else{
    			foo=bar;
			}
	//常用于函数参数的空判断
  • 用js实现随机选取10–100之间的10个数字,存入一个数组,并排序?
			function getRandom(istart, iend){
        		var iChoice = iend - istart +1;
        		return Math.floor(Math.random() * iChoice+ istart);
			}
			var iArray = []; 
			for(var i=0; i<10; i++){
				var result= getRandom(10,100);
        		iArray.push(result);
			}
			iArray.sort();
  • 如何获取javascript三个数中的最大值和最小值?
    答:Math.max(a,b,c);//最大值
    Math.min(a,b,c)//最小值
  • 如何实现冒泡排序?
		var array = [5, 4, 3, 2, 1];
		var temp = 0;
		for (var i = 0; i <array.length; i++){
			for (var j = 0; j <array.length - i; j++){
				if (array[j] > array[j + 1]){
					temp = array[j + 1];
					array[j + 1] = array[j];
					array[j] = temp;
			}
		}
  • 判断以下程序的输出结果?
			var age=100;
    		function test(){
    		 	this.age=50;
     			return function(){
        			return this.age;
      			}
    		}
    		var m=new test();
    		alert(m()); 
    		var n=test();
    		alert(n()); 
			//答案:
			10050
构造函数一旦返回一个对象,就不再创建新对象
m获得的是function(){ return this.age; }
n=test(),this指向window。先将全局变量age变为50,又返回一个函数function(){ return this.age; }保存在变量n中
调用n时,this指向window。
  • 判断以下程序的输出结果?
	var name="The Window";
	var obj={
   		name:"My obj",
   		getName:function(){
     		return function(){
       		return this.name;
     		}
   		}
 	};
 	console.log(obj.getName()());
	//答案:the window
obj.getName() 返回一个函数对象function(){ return this.name; }
(function(){ return this.name; }()) 相当于匿名函数自调,this指向window
  • 判断以下程序的输出结果?
		var length=10;
		function fn(){
  			console.log(this.length);
		}
		var obj={
  			length:5,
  			method:function(fn){
    			fn();
    			arguments[0]();
  			} 
		};
		obj.method(fn,1)
		//答案:10 2
	fn() this指向window,所以输出10
	arguments[0]() 属于特殊情况,this->arguments,相当于arguments.0(), 所以,this指向arguments。
	所以length输出的是obj.method()的参数个数,为2.
  • 统计一个字符串中出现次数最多的字符是? 共出现多少次?
		var dict={};
		var c="", max=1;
		for(var i=0;i<str.length;i++){
  			var char=str[i];
  			if(dict[char]===undefined){
    			dict[char]=1;
  			}else{
    			dict[char]+=1;}
    		if(dict[char]>max){
      			max=dict[char];
      			c=char;
    		}
  		}
		console.log(c,max);
提前创建一个空对象,用于保存每个字母出现的次数。
提前创建变量,准备保存出现次数最多的字符和出现的次数。
然后,遍历字符串中每个字母,每遍历一个字母就判断结果对象中是否包含以当前字母为属性名的属性。
如果不包含以当前字母为属性名的属性,说明是首次遇见该字母,就向结果对象中强行添加以该字母为属性名的属性,值暂时为1。
如果结果对象中已经包含以当前字母为属性名的属性,说明不是第一次碰见该字母。则取出该字母名属性对应的次数+1。
只要当前字母出现的次数>之前变量中记录的最大次数,就用当前字母和出现次数,取而代之。
  • 判断以下程序的输出结果?
		for(var i=0;i<5;i++){
  			setTimeout(function(){
    			console.log(i);
  			},0)
		}
	console.log(i);
	//答案:5 5 5 5 5
函数定义时,函数内容是不执行的,所以i还是i,不会变成0,1,2,3,4
定时器中的回调函数只能再主程序执行完才能开始执行
当主程序执行完,循环变量i,已经被改为5了。
  • 判断以下程序的输出结果?
		window.color="red";
		let color="green";
		let obj={
  			color:"blue"
		};
		let sayColor=()=>{
  			return this.color;
		}
		console.log(sayColor.apply(obj));
		let a=10;
		console.log(window.a);
	//答案:red undefined
let相当于匿名函数自调,所以,let声明的变量,不会自动加入到window
剪头函数内外this通用,所以apply也无法替换sayColor函数内的this,所以this指向window,所以输出red
  • 判断以下程序的输出结果?
		var c=1;
		function c(c){
  			console.log(c);
  			var c=3;
		}
		c(2);
	//答案:报错: TypeError: c不是一个函数
function c(c){} 整体被声明提前,后又被c=1代替。所以,c最后不是一个函数,而是数字1
  • 判断以下程序的输出结果?
		function change(){
  			alert(typeof fn)
  			function fn(){ alert('hello') }
  			var fn;
		}
		change();
	//答案:function
function fn(){…}被整体声明提前了
var fn发现已经有fn变量了,就不再重复创建,所以,var fn没作用。
  • 判断以下程序的输出结果?
		a=3
		a.prop=4;
		alert(a+a.prop)
		//答案:NaN
a.prop=4,等效于new Number(a).prop=4, 但是new Number(a),使用后自动释放,4也不存在了
再次使用a.prop,又等效于新的new Number(a),所以没有prop属性,值为undefined。
数字+undefined, undefined隐式转为数字NaN,导致计算结果为NaN
  • 判断以下程序的输出结果?
	var o={
  		a:10,
  		b:{
    		a:12,
    		fn:function(){
      		var a=13;
      		console.log(this.a);
    		}
  		}
	}
	o.b.fn();
	//答案:12
this指.前的o.b对象,所以a为12
  • 判断以下程序的输出结果?
	var obj1 = {
		name: 'obj1', 
		fn: function() {
    		document.write(this.name);
		}
	};
	var obj2 = {name: 'obj2'};
	var obj3 = {name: 'obj3'};
	obj1.fn();
	var newFn = obj1.fn;
	newFn();
	newFn.call(obj2);
	obj3.fn = newFn;
	obj3.fn();
	//答案:obj1 空字符串 obj2 obj3
this指.前的obj1
因为newFn调用时,前边没有.,所以this->window,
call是强行替换newFn中的this为obj2
this指.前的obj3
  • 一个数组 par 中存放有多个人员的信息,每个人员的信息由年龄 age 和姓名 name 组成,如{age: 2, name: ‘xx’}。请写一段 JS 程序,对这个数组按年龄从小到大进行排序?
		function parSort(arr, propName) {
    		arr.sort(function(a, b) {
        			return a[propName]-b[propName];
    		});
		}
		parSort(arr, “age”)
1)数组的sort函数的参数,是一个比较器函数。比较器函数的形参a和b,指当前要排序的数组中的任意两个作比较的元素。
	如果作比较的a和b两个元素是简单的数字类型,则a直接和b相减,就可比较两数大小。但是,如果a和b都是对象类型的元素。
	要比较两个对象中某个属性的值得大小,就必须用a.属性-b.属性。如果属性名是灵活的,
	来自于变量,则必须用a[属性名变量]-b[属性名变量],就可比出两个对象的某个属性值得大小。
2)最后,数组是引用类型的对象,在函数内修改数组,等效于修改原数组。所以不用返回值。
  • 有字符串 var = ‘abc345efgabcab’,请写出 3 条 JS 语句分别实现如下 3 个功能?
    答:1)去掉字符串中的a、b、c 字符,形成结果:‘345efg’
    2)将字符串中的数字用中括号括起来,形成结果:‘abc[345]efgabcab’
    3)将字符串中的每个数字的值分别乘以 2,形成结果:‘abc6810efgabcab’
    答案:
    1)str.replace(/([a-c])/g, ‘’);
    2)str.replace(/(\d+)/g, ‘[$1]’);
    3)str.replace(/(\d)/g, function(num) {return num*2;});

    1)将字符串中的a,b,c三个字符都替换为空字符串
    2)找到字符串中多个连续的数字,分为一组,然后将这一组的内容,替换为用[]包裹。
    $1,可获得关键词中第一个()包裹的内容。
    3)找到字符串中每个数字,*2后,再放回原位置。

  • 判断以下程序的输出结果?

		var a=10;
 		var obj={
    		a:20,
    		intr:function(){
      			var a=30;
      			console.log(this.a);
    		}
 		}
 	obj.intr();
 	var intr=obj.intr;
 	intr();
 //答案:20 10
obj.intr(),this指.前的obj,所以输出20
intr(), this指window,所以输出10
  • 判断以下程序的输出结果?
		function fun(){
  			for(var i=0,arr=[];i<3;i++){
    			arr[i]=function(){
      				console.log(i);
    			}
  			}
  			return arr;
		}
	var funs=fun();
		funs[0]();
		funs[1]();
		funs[2]();
	答案:3 3 3
  • 定义函数实现深克隆一个对象?
		var lilei={
    		sname:"Li Lei",
    		score:null,
    		friends:["jack","rose"],
    		address:{
      			prov:"北京",
      			city:"北京",
      			area:"海淀",
      			street:"万寿路"
    		},
    		sage:11
  		}
  	function clone(obj){
    	if(obj===null){
      		return null;
    	}else if({}.toString.call(obj)==="[object Array]"){
      		var newArr=[];
      		newArr=obj.slice();
      		return newArr;
    	}
    	var newObj={};
    	//遍历原obj的每个属性
    	for(var key in obj){
      		//如果原对象中当前属性值是原始类型
      		if(typeof obj[key]!=="object"){
      			//在新对象中添加和原对象中同名的属性
      			newObj[key]=obj[key];
      			//原始类型复制,就是复制副本
      		}else{//否则,当前属性不是原始类型的值,再次调用clone函数,继续复制当前属性值
        		newObj[key]=clone(obj[key])
      		}
    	}
    	return newObj;
  	}
  	console.log(lilei);
  	var lilei2=clone(lilei);
  	console.log(lilei2);
  	console.log(lilei==lilei2);//true
  	lilei2.address.area="朝阳";
  	console.log(lilei.address);
  • 介绍 JavaScript 的原型,原型链?有什么特点?
    答:原型:JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是该对象的原型
    JavaScript 的函数对象,除了原型 [proto] 之外,还预置了 prototype 属性
    当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [proto]。
    原型链:当一个对象调用的属性/方法自身不存在时,就会去自己 [proto] 关联的前辈 prototype 对象上去找
    如果没找到,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。
    从而形成了所谓的“原型链”
    原型特点:
    JavaScript 对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
  • 谈谈Javascript 垃圾回收方法?
    答:标记清除(mark and sweep)
    这是 JavaScript 最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”
    (1)垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量及引用计数(reference counting)
    (2)在低版本 IE 中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加 1,如果该变量的值变成了另外一个,则这个值得引用次数减 1,当这个值的引用次数变为 0 的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为 0 的值占用的空间
  • 说说严格模式的限制
    答:严格模式主要有以下限制:
    变量必须声明后再使用
    函数的参数不能有同名属性,否则报错
    不能使用 with 语句
    不能对只读属性赋值,否则报错
    不能使用前缀 0 表示八进制数,否则报错
    不能删除不可删除的属性,否则报错
    不能删除变量 delete prop,会报错,只能删除属性 delete global[prop]
    eval 不会在它的外层作用域引入变量
    eval 和 arguments 不能被重新赋值
    arguments 不会自动反映函数参数的变化
    不能使用 arguments.callee
    不能使用 arguments.caller
    禁止 this 指向全局对象
    不能使用 fn.caller 和 fn.arguments 获取函数调用的堆栈
    增加了保留字(比如 protected、static 和 interface)
  • 使用正则表达式验证邮箱格式?
    答:var reg = /^(\w)+(.\w+)*@(\w)+((.\w{2,3}){1,3})$/;
    var email = “[email protected]”;
    console.log(reg.test(email)); // true
  • 使用typeof bar ===“object”来确定bar是否是一个对象时有什么潜在的缺陷?这个陷阱如何避免?
    答:尽管typeof bar ===“object”是检查bar是否是对象的可靠方法,但JavaScript中令人惊讶的问题null也被认为是一个对象!
    因此,对于大多数开发人员来说,下面的代码会将true(而不是false)打印到控制台:
    var bar = null;
    console.log(typeof bar === “object”); // logs true!
    只要知道这一点,就可以通过检查bar是否为空来轻松避免该问题:

console.log((bar !== null) && (typeof bar === “object”)); // logs false
为了让我们的答案更加的完整,还有两件事值得注意: 首先,如果bar是一个函数,上面的解决方案将返回false。在大多数情况下,这是所期望的行为,但是在您希望函数返回true的情况下,您可以将上述解决方案修改为:

console.log((bar !== null) && ((typeof bar === “object”) || (typeof bar === “function”)));
其次,如果bar是数组,则上述解决方案将返回true(例如,如果var bar = [];)。在大多数情况下,这是所希望的行为,因为数组确实是对象,但是在您想要对数组也是false的情况下,可以将上述解决方案修改为:

console.log((bar !== null) && (typeof bar === “object”) && (toString.call(bar) !== “[object Array]”));
但是,还有一个替代方法对空值,数组和函数返回false,但对于对象则为true:

console.log((bar !== null) && (bar.constructor === Object));
或者,如果您使用jQuery:

console.log((bar !== null) && (typeof bar === “object”) && (! $.isArray(bar)));
ES5使得数组的情况非常简单,包括它自己的空检查:

console.log(Array.isArray(bar));

  • 以下代码的输出是什么?解释你的答案?
		var a={},
    	b={key:'b'},
    	c={key:'c'};

		a[b]=123;
		a[c]=456;

		console.log(a[b]);
	答案:456
原因如下:设置对象属性时,JavaScript会隐式地将参数值串联起来。在这种情况下,由于b和c都是对象,它们都将被转换为“[object Object]”。
因此,a [b]和a [c]都等价于[“[object Object]”],并且可以互换使用。因此,设置或引用[c]与设置或引用[b]完全相同。