js面试题集合

以下每个题都是各个知识点的经典面试题,有不理解的地方可以直接评论

一.变量提升

var foo=function bar(){}
console.log(typeof bar);
if(!('a' in window)){
	 var a=1;
}
console.log(a);
if('m' in window) {
	var m = m && 12
}
console.log(m);

var c=1;
function c(){
    console.log(c);
    var c=3;
}
console.log(c);
c(2);
var name='kaivan';
(function () {
    if(typeof name==='undefined'){
        var name='chen';
        console.log(name);
    }else {
        console.log(name);
    }
})();
if(false){
    var a=1;
    let b=2;
}
console.log(a);
console.log(b);
var a=1;
if(true){
    console.log(a);
    let a=2;
}
fn(123)
var a=456;
function fn(a){
    console.log(a);
}
let n = 10
if(!('n' in window)) {
	let n = n + 30
}
console.log(n);
var a = 0
function fun() {
	alert(a)
	var a = 10
}
fun()
alert(a)
var a=10;
function test() {
		a=100;
		console.log(a);
		console.log(this.a);
		var a;
		console.log(a);
}
test();
console.log(c);
function c(a) {
	console.log(a);
	var a=3;
	function a() {

	}
}
c(2);

function fn(a, c) {
	console.log(a)
	var a = 123
	console.log(a);
	console.log(c);
	function a() {}
	if(false) {
		var d = 678
	}
	console.log(d);
	console.log(b);
	var b = function() {}
	console.log(b);
	function c() {}
	console.log(c);
}
fn(1,2)

二.函数参数

知识点1: 函数实参与函数的arguments之间存在联系

  1. 严格模式下(use strict)函数实参与函数arguments并不存在联系,两者互不影响。
  2. 非严格模式下,函数实参与函数arguments相互影响。

知识点2: 函数的实参若为引用类型,那么参数在函数内部被修改后,外部的值也会随之改变。

知识点3: 函数里面的arguments并非一个真实意义上的数组,其实是一个有length属性的对象,也称类数组

let n = 10
let m = 20
~function(n, m) {
	let arg = arguments
	arg[0] = n || 100
	arg[1] = m || 200
	console.log(n, m); 
}(m)
console.log(n, m);

解析: 首先检查该代码执行环境,并无use strict,表示非严格模式,那么实参与arguments相互影响。这里的函数为立即执行函数,参数只传了一个,也就是说,实参为参数n,并且n与函数的arguments有联系。
执行let arg = arguments时,arg等于[20, undefined],n = 20;
执行arg[0] = n || 100时,因为n=20,所以arg[0] = 20;
执行arg[1] = m || 200时,因为m=undefined,所以arg[1] = 200,但是又因为参数m并非实参,所以与arguments并无联系,也就是说m还是undefined。
最后打印:
函数里面 console.log(n, m); => 20, undefined;
函数外面 console.log(n, m); => 10, 20;

let arr= [12, 23, 34, 45];
(function(paramsArr) {
	paramsArr.pop()
	paramsArr= ary.slice(0)
	paramsArr.shift()
	console.log(paramsArr);	
})(arr)
console.log(arr);

**解析:**这个问题需要用到知识点2,可以看到函数参数未一个数组,数组为引用类型,所以当他在内部被修改,外面的ary变量也随之改变。
执行paramsArr.pop()时,paramsArr变成[12, 23, 34],arr变成[12, 23, 34];
执行paramsArr= ary.slice(0)时,paramsArr相当于克隆出一个新的[12, 23, 34],与外部arr切断了联系,之后再对paramsArr进行操作就不会影响arr。
执行paramsArr.shift()时,paramsArr变成[23, 34],arr依旧是[12, 23, 34];
最后打印
paramsArr => [23, 34];
arr => [12, 23, 34];

window.onload = function() {
	var length = 10;

	function test() {
		console.log(this.length);
		console.log(this, 'this');
	}
	var obj = {
		length: 100,
		func: function(fn) {
			fn()
			arguments[0]()
		}
	}
	obj.func(test, [1, 2, 3], 4, 5, 6)
}

解析: 这是非常有意思的一道题。运用了知识点3。
咋们直接看最后函数的执行obj.func(test, [1, 2, 3], 4, 5, 6),可以看到最后是执行了obj对象里面的func方法,而该方法接收一个参数,且将参数执行,也就是说test会被当成函数直接执行,而test我们定义的也确实是个函数,相当于在内部执行了test(),而该方法里面需要打印this,可以看到该方法并没有被挂到对象上调用,而是直接调用,那么tihs就应该是指向window。window下的length 属性返回在当前窗口中frames的数量(包括IFRAMES)。默认都是1。
所以fn()等于test(),最终打印1,window。

接着我们看arguments[0](),记住arguments并不是一个数组,而是一个有length属性的对象,所以这个可以简单看成arguments.0(),虽然代码并不能这么书写,但他确实就是这个含义。有的人可能还没看出来,我简单将值改变下a.b(),这样是不是一目了然,这就是简单的调用对象里面的方法,this自然就指向了对象,而这里也就指向了arguments,并且arguments里面还真有length属性,也就是参数的个数为5。
所以arguments[0]()可以看成arguments.0()注意只是看成,并不能这么书写,翻译下就是a.b(),this就等于arguments这个对象,length等于5。

function demo(obj) {
	obj.n = 2
	obj = {n: 3}
}
var obj = {n:1}
demo(obj)
console.log(obj);

**解析:**这道题相对简单,使用知识点2。
直接看函数执行demo(obj),这里将obj当做实参传入给函数,obj为引用类型,也就是说当obj在函数里面被改变,外部的obj同样被更改。
执行obj.n = 2时,外部obj随之改变为{obj: 2}。
执行obj = {n: 3}时,这其实并没有改变外部obj,而是直接将参数obj的内存地址指向了一个新的地址,而外部的地址不变。所以外部obj依旧是{n: 2}
最后打印出 {n: 2}

三.闭包

let test = (function(i) {
	return function() {
		alert(i *= 2)
	}
})(2)
test(5)
let i = 0
let fn = function(n) {
	i += 2
	return function(m) {
		i += (++n) + (m--)
		console.log(i);
	}
}
let f = fn(2)
f(3) 
fn(2)(3) 
f(4)  
console.log(i);
let n = 1
let x = {
	n: 2,
	y: (function() {
		n = n || 3
		return function(m) {
			m = m || 4
			this.n += m++
			n += ++m
			console.log(n);
		}
	})(window.n)
}
let z = x.y
x.y(5)  
z(6)
console.log(n, x.n);
let n = 10 
obj	 = {n: 20}
let fn = obj.fn = (function() {
	this.n ++ 
	n ++
	return function(m) {
		n += 10 + (++m) 
		this.n += n
		console.log(n);
	}
})(obj.n)
fn(10)  
obj.fn(10)
console.log(n, obj.n);
var n = 2
function a() {
	var n = 3
	function b(m) {
		alert(++n + m)
		console.log(n);
	}
	b(4)
	return b
}
var c = a()
c(6)
alert(n) 
let n = 2
fn = () => {
	this.n *= 3
	n ++
	return m => console.log((++n)+m);
}
var f = fn(4)
f(5) 
fn(4)(5) 
f(6)
console.log(n);

三.堆栈

let a = {n: 4}
let b = a
b.x = a = {n: 10}
console.log(a.x);
console.log(b.x);

四.构造函数

function C1(name) {
	if(name) this.name = name
}
function C2() {
	this.name = name
}
function C3() {
	this.name = name || "join";
}
C1.prototype.name = 'Tom'
C2.prototype.name = 'Tom'
C3.prototype.name = 'Tom'
console.log(new C1().name + new C2().name + new C3().name)
function C1(name) {
	this.name = name || 'join'
}
function C2() {
	name ? this.name = name : null
}
function C3() {
	this.name = name && "join";
}
C1.prototype.name = 'Tom'
C2.prototype.name = 'Tom'
C3.prototype.name = 'Tom'
console.log(new C1().name + new C2().name + new C3().name)
function Foo() {
	getName = function() {
		console.log(1);
	}
	return this
}
Foo.getName = function() {
	console.log(2);
}
Foo.prototype.getName = function() {
	console.log(3);
}
var getName	 = function() {
	console.log(4);
}
function getName() {
	console.log(5);
}
Foo.getName()  
getName()  
Foo().getName() 
getName() 
new Foo.getName() 
new Foo().getName()
new new Foo().getName()
function A() {
	console.log(1);
}
function Func() {
	A = function() {
		console.log(2);
	}
	return this
}
Func.A = A
Func.prototype = {
	A: () => {
		console.log(3);
	}
}
A()
Func.A()
Func().A()
new Fun.A()
new Func().A()
new new Func().A()
function f() {
    return f;
}
console.log(new f() instanceof f);
function Foo() {
	getName = function () { console.log(1) }
	return this
}
Foo.getName = function () { console.log(2) }
Foo.prototype.getName = function () { console.log(3) }
var getName = function () { console.log(4) }
function getName() { console.log(5) }

//请写出以下输出结果:
Foo.getName()
getName() 
Foo().getName()
getName()
new Foo.getName() 
new Foo().getName() 
new new Foo().getName() 

五.原型

let Fn = function(x = 0, y = 0) {
	this.x = x
	this.y = y
	this.getX = function() {
		console.log(this.x);
	}
} 
Fn.prototype.getY = function() {
	console.log(this.y);
}
Fn.prototype = {
	setX: function(val) {
		this.x = val
	},
	getX: function() {
		console.log(this.x);
	}
}
let f1 = new Fn
let f2 = new Fn(1, 2)
console.log(f1);
f1.setX(3)
f1.getX() 
f1.__proto__.setX(4) 
f1.getX() 
f2.getX()  
f2.__proto__.getX()
f2.getY()

解析:首先看Fn构造函数原型对象最后变成了什么,先是手动的在Fn的原型对象上绑定的了一个getY函数,接着又直接把整个原型对象指向新的对象,也就是说前面绑定的getY函数并不会存在原型对象里。接着进行f1对象的创建,new Fnnew Fn()的效果其实一样的,也是是说我们相当于调用了new Fn(),创建了一个对象,对象包含两个默认为0的x, y属性和一个getX方法。接着又创建了一个f2对象,只不过x,y属性是根据传递的参数创建的。
console.log(f1):打印f1,f1里面有构造函数创建的三个属性{x: 0, y: 0, getX: function(){…}}
f1.setX(3):执行f1的setX方法,首先在对象本身上查找有无方法,没有找到后去原型链查找,找到后执行,修改了对象f1的X属性值。
f1.getX():打印出f1的x属性为3
f1.__proto__.setX(4) :f1的__proto__属性直接指向Fn实例的prototype对象,所以执行setX方法也就是执行Fn原型的setX方法。但是值得注意的是,该方法里面的this指向并非是f1实例,这里需要this指向相关的知识了,他执行的时候实际指向的是f1.__proto__,也就是Fn函数的原型对象。相当于在Fn的prototype对象里创建了x为4的属性。
f1.getX() :依旧打印出实例f1上的x属性3
f2.getX() :打印出f2的X属性1
f2.__proto__.getX():这里的指向跟f1.__proto__.setX(4)思路一致。所以this也是指向Fn构造函数的实例对象,之前已经创建了属性x为4,所以这里打印4
f2.getY():在实例与原型上皆找不到getY方法,所以报错。

function fun() {
	this.a = 10
	this.b = function() {
		alert(this.a)
	}
}
fun.prototype = {
	b: function() {
		this.a = 20
		alert(this.a)
	},
	c: function() {
		this.a = 30
		alert(a)
	}
}
var my_fun = new fun()
my_fun.b()
my_fun.c()
function A() {}
A.prototype.n=1;
var b=new A();
A.prototype={
    n:2,
    m:3,
}
var c=new A();
console.log(b.n,b.m);
console.log(c.n,c.m)

六.数据类型

var str = 'abc123',
num = parseFloat(str)
if(num === NaN) {
	alert(NaN)
}else if(num === 123) {
	alert(123)
}else if(typeof num === 'number') {
	alert('number')
}else {
	alert('str')
}
let a = {}, b = '0', c = 0
a[b] = 'fufu'
a[c] = 'dandan'
console.log(a[b]);

let a = {}, b = Symbol('1'), c = Symbol('1')
a[b] = 'fufu'
a[c] = 'dandan'
console.log(a[b]);

let a = {}, b = {n: '1'}, c = {m: '2'}
a[b] = 'fufu'
a[c] = 'dandan'
console.log(a[b]);
console.log(1 + '2' + '2');
console.log(1 + +'2'+ '2');
console.log(+ '1' - +'1'+'2');
console.log('A' - 'B' + '2');
console.log('A' - 'B' + 2)
Object.prototype.bar=1;
var foo={
    goo:undefined
};
console.log(foo.bar);
console.log('bar' in foo); 
console.log(foo.hasOwnProperty('bar'));
console.log(foo.hasOwnProperty('goo'));
var a;
var b='undefined';
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);
console.log(1 + NaN)
console.log("1" + 3)
console.log(1 + undefined)
console.log(1 + null)
console.log(1 + {})
console.log(1 + [])
console.log([] + {})

七.this指向

var point = {
	x: 20,
	y: 20,
	moveTo: function(x, y) {
		var moveX = function(x) {
			this.x = x
		}
		var moveY = function(y) {
			this.y = y
		}
		moveX(x)
		moveY(y)
	}
}
point.moveTo(100, 200)	
console.log(point.x, point.y);
var fullName = 'language'
var obj = {
	fillName: 'js',
	prop: {
		getFullName: function() {
			return this.fullName
		}
	}
}
console.log(obj.prop.getFullName()); 
var test = obj.prop.getFullName
console.log(test()); 
window.val = 1
let json = {
	val: 10,
	dbl: function() {
		this.val *= 2
	}
}
json.dbl()
let dbl = json.dbl
dbl()
json.dbl.call(window)
alert(window.val + json.val)
(function() {
	let val = 1
	let json = {
		val: 10,
		dbl: function() {
			console.log(val);
			val *= 2
		}
	}
	json.dbl()
	alert(json.val + val)
})()
var name = 222
var a = {
	name: 111,
	say: function() {
		console.log(this.name);
	}
}
var fun = a.say
fun()  
a.say() 
var b = {
	name: 333,
	say: function(fun) {
		fun()
	}
}
b.say(a.say) 
b.say = a.say
b.say() 

八.call/apply/bind

let fn1 = function(){alert(1)},
fn2 = function(){alert(2)}
fn1.call(fn2)
fn1.call.call(fn2)
//https://www.shangmayuan.com/a/783cd2dc85dd4510b2587801.html

同步异步

new Promise((resolve) => {
  console.log(1)
  resolve()
}).then(() => {
  new Promise((resolve) => {
    console.log(2)
    resolve()
  }).then(() => {
    console.log(4)
  })
}).then(() => {
  console.log(3)
})

其他

1.toString()  
1..toString()  
1.0.toString()  
1 .toString()   
1+2.toString()
1+2 .toString()
var arr = []
arr[0] = 1
arr['0'] = 2
console.log(arr[0] + arr['0'])

解析:先说答案:4;js里面的数组说到底其实就是对象而已,而对象的属性只能为字符串或者Symbol类型,即使传入的不是字符串也会被强制转换为字符串类型,所以这里的arr[0]其实是等于arr['0']

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值