第一篇 Javascript经典面试题+答案

1. javascript的数据类型有哪些?

基本数据类型:String、Number、Boolean、Null、Undefined、BigInt、Symbol。
引用数据类型:Object、Array、Function、Date等。

2. 如何判断javascript的数据类型?

  • typeof(返回表示数据类型的字符串):只能判断基本数据类型、Function和Object,并且判断Null是Object,Array和Date等也是Object
typeof ''  //'string'
typeof null //'object'
typeof [] // ‘object’
typeof function(){} //'function'
  • instanceof:判断实例A是不是B构造类型/引用类型,返回一个布尔值
[] instanceof Array //true
let num = 1
num instanceof Number //false
num = new Number(1)
num instanceof Number //true
  • Object.prototype.toString.call():所有类型均可判断
Object.prototype.toString.call(123) //'[object Number]'
Object.prototype.toString.call(true) //'[object Boolean]'
Object.prototype.toString.call([]) //'[object Array]'
Object.prototype.toString.call(new Date()) //'[object Date]'
  • constructor:根据对象的constructor判断
let arr = [1,2]
let date = new Date()
let f = function(){}
arr.constructor == Array  //true
date.constructor == Date //true
f.constructor == Function // true

3. 如何判断两个对象相等,如何判断空对象,如何判断对象有某个属性?

判断对象是否相等:
1、JSON.stringify(obj),将对象转成JSON,之后判断两者是否相等(只适合两个对象的属性顺序是一样的)。

let a = {name:1,age:2}
let b = {name:1,age:2}
JSON.stringify(a) === JSON.stringify(b) //true

2、先判断两个对象的长度是否一致(Obejct.getOwnPropertyNames(a).length),遍历对象判断A中的属性是否在B中也有和判断vlaue是否相等。

//简单写的一个函数
function equals(a,b){
	let ao = Object.getOwnPropertyNames(a);
	let bo = Object.getOwnPropertyNames(b);
	if(ao.length != bo.length) return false;
	for(key in a){
		if(!b.hasOwnProperty(key)) return false;
		if(a[key] != b[key]) return false; 
	}
	return true;
}

let a = {name:1,age:2}
let b = {age:2,name:1}
equals(a,b) //true

判断空对象:
1、转成字符串,再判断是否等于‘{}’。
2、使用Object.keys()返回对象的属性名的数组,判断它的length是否等于0,则为空对象。
3、使用Object.values()返回对象的属性值的数组,判断它的length是否等于0,则为空对象。
4、使用Object.getOwnPropertyNames()方法获取对象的属性名的数组,判断它的length是否等于0,则为空对象。
5、for in循环。

let a = {}
JSON.stringify(a) === '{}'  //true
Object.keys(a).length == 0  //true
Object.values(a).length == 0  //true
Object.getOwnPropertyNames(a).length==0. //true

function isEmptyObject(a){
	for(key in a){
		return false;
	}
	return true;
}
let a = {}
isEmptyObject(a);

判断对象是否有某个属性:
1、in :如果属性是对象的原型,也会返回true

let obj = {name:'swa'}
'name' in obj  //true
'toString' in obj  //true

2、Object.hasOwnProperty() :是否具有指定具有自身指定的属性,不是对象原型上的属性。如果对象是用Object.create()创建的话,无法判断。

let a = {name: 'aaa'}
Object.hasOwnProperty('name') //true
Object.hasOwnProperty('toString') //false

let obj = Object.create(null)
obj.p = 2
Object.hasOwnProperty('p') //false

3、Object.prototype.hasOwnProperty.call():可以解决用Object.create()创建对象无法判断的问题。

let a = {name: 'aaa'}
Object.prototype.hasOwnProperty.call(a,'name') //true
Object.prototype.hasOwnProperty.call(a,'toString') //false

let obj = Object.create(null)
obj.p = 2
Object.prototype.hasOwnProperty.call(obj,'p') //true

4、Object.hasOwn() :是ES2022提出的,用于取代Object.prototype.hasOwnProperty()方法。

let a = { name: 'qw'}
Object.hasOwn(a,'name') //true
Object.hasOwn(a,'toString') //false

let obj = Object.create(null)
obj.p = 2
Object.hasOwn(obj,'p') //true

5、Reflect.has() :如果属性是对象的原型,也会返回true。Reflect是一个内置的对象,它提供拦截操作javascript的方法,是ES6为了操作对象而提供新的API。

let a = {name: 'aaa'}
Reflect.has(a,'toString') //true
Reflect.has(a,'name') //true

let obj = Object.create(null)
obj.p = 2
Reflect.has(obj,'p')  //true

4. 强制类型转换和隐式类型转换

1、强制类型转换可通过String()、Number()、Boolean()函数

String(123) //'123'
Number('123') //123
Boolean(1) //true

2、隐式类型转换可通过 == 、运算符加减乘除、大于、小于等

  • 字符串加数字,数字会变为字符串
  • 数字减乘除、大于、小于字符串,字符串都会转为数字
  • 规定是undefined == null
undefined == null
null == 0 //false
null == false // false
undefined == 0 //false
'123' == 123 //true 字符串转数字
1 == true //true 布尔转数字
'0' == false // true 两者转数字
'1'+2 //12
'1'-2 //-1
'1'*2 //2
'6'/2 //3
'2'>1 //true
1<'6' //true

5. 创建函数有几种方式?

1、函数声明方式

function f(){}

2、函数表达式方式

var f = function(){}

3、箭头函数

var f =(a,b)=>{
}

6. == 与 ===的区别

1、== 如果两边类型不同,会进行隐式转换再比较
2、=== 是判断两者类型和值是否完全相同

'0' == 0 //true
'0' === 0 //false
undefined === null //false

7. undefined和null的区别

1、定义不同。undefined表示“未定义的值”,当声名了一个变量但没有给它赋值时,该变量的值就是undefined。null表示的是空值,当我们想表示一个变量不包含任何值的时候,可以将它设置为null。
2、用typeof判断数据类型的时候,判断undefined是undefined数据类型,判断null是object数据类型。
3、用Number()强制转换时,undefined是NaN,null是0
4、null是关键字,undefined不是关键字

8.数组降维

1、二维数组降维

  • 用concat()方法和扩展运算符
  • 用flat(1)
let arr=[1,2,[3,4],5];
[].concat(...arr); //[1,2,3,4,5]
arr.flat(1) //[1,2,3,4,5]

2、多维数组降维:使用flat(Infinity)方法

let arr=[1,2,[3,4],[5,[6,7]],8];
arr.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8]

9.什么是类数组(伪数组),如何转化为真实的数组?

伪数组: 伪数组是一个类似数组的对象,具有类似数组的索引属性和length属性,但是不是真正的数组,可以使用一些数组相关的方法,如for 等,但是一些数组特有的方法如push、pop等则不能直接使用。
常见的伪数组: arguments对象、HTMLColletion对象、NodeList对象。
转换为真实数组的方法:
1、Array.from()

function test(){
    return arguments
}
let f = test(1,2)
Array.from(f))  //[1,2]

2、Array.prototype.slice.call()

function test(){
    return arguments
}
Array.prototype.slice.call(test(1,2)) //[1,2]

10.如何遍历对象的属性?

1、for in:遍历自身和继承的可枚举属性(不含Symbol属性)

let obj = {name: 'a' , age:10 ,sex: 1}
Object.defineProperty(obj, 'sex', {
  enumerable: false,
});
for(key in obj ){
    console.log(key) //name age
}

2、Object.keys():返回一个对象自身(不含继承)的可枚举属性(不含Symbol属性)的数组

let obj = {name: 'a' , age:10 ,sex: 1}
Object.defineProperty(obj, 'sex', {
  enumerable: false,
});
Object.keys(obj) //'name', 'age']

3、Object.getOwnPropertyNames():返回一个对像所有的属性(包括可枚举和不可枚举属性)的数组(不含Symbol属性)

let obj = {name: 'a' , age:10 ,sex: 1}
Object.defineProperty(obj, 'sex', {
  enumerable: false,
});
Object.getOwnPropertyNames(obj) // ['name', 'age', 'sex']

4、Reflect.ownKeys:返回一个自身所有属性名的数组,包括是否枚举和Symbol属性。

let obj = {name: 'a' , age:10 ,sex: 1,[Symbol()]:1}
Object.defineProperty(obj, 'sex', {
  enumerable: false,
});
Reflect.ownKeys(obj) //['name', 'age', 'sex', Symbol()]

11.如何给一个按钮绑定两个事件?

使用addEventListener()绑定事件
可以使用removeEventLister()解除事件

var btn = document.getElementById("btn");
btn.addEventListener("click", test1, false); //第三个参数是表示捕获还是冒泡,true:捕获 false:冒泡,默认是冒泡
btn.addEventListener("click",  test2, false);
function test1(){
}
function test2(){
}

12.什么是事件冒泡?如何阻止事件冒泡

当点击一个元素触发某种事件时,会由内到外直到父元素上依次触发同类的事件。
使用 event.stopPropagation() 阻止冒泡事件。
不是所有事件都能冒泡,以下事件不能冒泡:blur、focus、load、unload.

13.什么是事件捕获?

当点击一个元素触发某种事件时,会由外到内直到子元素上依次触发同类的事件
可以使用addEventLister(‘click’,function aa(){},true)方法的第三个参数设为true就是捕获

14.如何让事件先冒泡后捕获?

事件默认是先捕获后冒泡
使用事件委托:将单个事件监听器添加到父元素上,以处理子元素上的事件

15.什么是作用域、作用域链?如何延长?什么是暂时性死区?

- 作用域:变量与函数的可访问范围。
作用域分为全局作用域、局部作用域、块级作用域。
全局作用域:在整个文件内起作用,任何位置都可以访问。比如用var声明的全局变量具有全局作用域,全局变量只有关闭浏览器的时候才会销毁,比较占内存资源。

var a = 1;
console.log(a); //1

局部作用域:只能在函数内起作用。局部变量会在程序执行完成的时候立即销毁,节省资源。

function f(){
	var a = 1;
	console.log(a); //1
}
f();
console.log(a); // 报错Uncaught ReferenceError: a is not defined

块级作用域:任何一对花括号({})中的语句集都属于一个块,在这块区域中定义的变量,只能在这个区域中使用。let、const定义的变量会产生块级作用域

for(let i = 0;i<5;i++){
}
console.log(i); 
//Uncaught ReferenceError: i is not defined 报错,只能在{}范围内被访问,外面访问不到

- 作用域链:使用一个变量的时候,js引擎会尝试在当前作用域下查找,如果没找到,会往它的上层作用域查找,依次类推直到找到该变量。
如果找不到该变量会直接报错。

var sex = '女';
function person() {
    var name = 'Lily';
    function student() {
        var age = 18;
        console.log(name); // Lily
        console.log(sex); // 女 
    }
    student();
    console.log(age); // Uncaught ReferenceError: age is not defined
}
person();

- 暂时性死区:针对let、const(块级作用域)这两个关键字而产生的概念,在声明变量之前使用该变量,那么该变量是不可用的,也就被称为暂时性死区。

console.log(a); //Uncaught ReferenceError: a is not defined
let a = 2;  

16.变量提升是什么?与函数提升有什么区别?

  • 变量提升:是指变量的声明被提前到作用域的顶端。
console.log(a); //undefined
var a = 1;

变量提升只是声明被提升,不包括赋值,等同于下面这段代码:

var a;
console.log(a);
a = 1;
  • 函数提升:函数提升的优先级高于变量提升,不会被同名变量声明覆盖,但是会被同名声明赋值后覆盖。

1、函数声明:js在执行之前,会把函数提升在到最前面

f(); //123
function f() {
    console.log(123);
}

上面的代码等同于这段代码:

function f() {
    console.log(123);
}
f(); //123

2、函数表达式提升:可以理解为一个普通变量的提升

f(); 
var f = function() {
    console.log(123);
}

上面这段代码会报错:Uncaught TypeError: f is not a function,因为js执行之前,f会提升到最前面,值为undefined,不是一个函数,以函数的形式调用会报错。
等同与下面这段代码:

var f;
f();
f = function() {
    console.log(123);
}

(练习)函数提升的优先级高于变量提升,不会被同名变量声明覆盖,但是会被同名声明赋值后覆盖。

function a(){}
var a;
console.log(typeof(a)) //function
function a(){}
var a = 1;
console.log(typeof(a)) //Number
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值