js大致面试题

1、undefined和null有什么区别

undefined 声明变量后没有赋值,未定义

null 空对象,是js的历史遗留问题,算是一个占位符,当不确定这个值是什么类型时可以先给变量赋值为null

console.log(typeof undefined) //undefined

console.log(typeof null) //object
2、阻止事件冒泡和默认事件的方法
// 阻止事件冒泡:子元素执行事件时,阻止父元素执行
son.addEventListener('click', function (e) {
	alert('son被点击!!!')
	e.stopPropagation()
})
father.addEventListener('click', function () {
	alert('father被点击!!!')
})
// 阻止默认行为:在html中有些标签有默认行为,例如:a会默认跳转页面

// e.preventDefault 阻止默认行为  ie9以下不支持
a.onclick = function (e) {
	e.preventDefault() //标准写法
}
//ie9以下可以支持
a.attachEvent('onclick', function (e) {
	e.returnValue = false  
})
3、注册事件中的event.target和this的区别

e.target指向触发的元素对象(触发谁打印谁)ie9以下不支持

this指向绑定事件的元素对象

<father><son></son></father>
    
father.addEventListener('click', function (e) {
	e.target.style.backgroundColor = 'red' //点到谁谁背景颜色变
})
father.addEventListener('click', function () {
	this.style.backgroundColor = 'red' //不管点到谁只会father背景颜色变
})
4、== 和 === 有什么区别
// == 是指只要值相等就会返回true,会自动把两个值的数据类型转换为同一种,在进行比较值
console.log(18 == '18') //true
console.log(18 == '你好') //false
console.log('nihao' == '你好') //false
// === 是指值和数据类型全部一样时,才会返回true,否则返回false
console.log(18 === '18') //false
console.log('nihao' === 'hello') //false
console.log(18===18) //true
5、js中的this指向有那些
// 全局作用域,this指向window
console.log(this)
// 普通函数,this指向window
function fn(){
	console.log(this)
}
//普通函数嵌套调用
function fn1(){
	console.log(this) //window
}
function fn2(){
	console.log(this) //window
	fn1()
}
fn2()
// 对象里方法,this指向这个对象
var obj = {
	uname:'张三',
	say:function () {
		console.log(this)
	}
}
obj.say()
// 构造函数,this指向实例化对象
function Get(){
	console.log(this)
}
var get = new Get()
// 定时器,this指向window
setTimeout(function(){
	console.log(this)
})
// 注册事件,this指向事件源
var btn = document.querySelector('button')
btn.onclick = function(){
	console.log(this) //<button></button>
	setTimeout(function(){
		console.log(this) //window
	})
}
6、改变this指向的方法有哪些,有什么区别
var lisi = {names:'lisi'};
var zs = {names:'zhangsan'};
function f(age){
    console.log(this.names);
    console.log(age);
}

f(23) //undefined

// call()方法,call(this指向的对象,参数1,参数2,...)
f.call(zs,23) //zhangsan 23

// apply()方法,apply(this指向的对象,[参数1,参数2,...])
f.apply(zs,[23]) //zhangsan 23

// bind()方法,bind(this指向的对象,参数1,参数2,...),只改不调用
f.bind(zs,23)
f() //zhangsan 23

都是强制指定函数调用时this的指向

call和apply的作用一致,区别仅仅在函数实参传递的方式上

7、数组有哪些方法
数组增删
var arr = [2,3]
// push 在数组的末尾添加一个或多个元素
arr.push(4,5)
console.log(arr) //[2,3,4,5]
// unshift 在数组的最前面添加一个或多个元素
arr.push(0,1)
console.log(arr) //[0,1,2,3]
// pop 删除数组中的最后一个元素,一次只能删除一个
arr.pop()
console.log(arr) //[2]
// shift 删除数组中最前面的元素,一次只能删除一个
arr.shift()
console.log(arr) //[3]
数组翻转和排序
// reverse 翻转数组
arr.reverse()
console.log(arr) //[3,2]
// sort 数组排序
arr.sort(function(a,b){
	// return a-b //从小到大
	return b-a //从大到小
})
console.log(arr) //[3,2]

console.log(arr.sort()) //直接输出,默认按字母顺序排序,例如20会排在3前面
indexOf查询数组索引
var arr = [1,2,2,3]

// indexOf(元素) 从前往后通过元素查找索引,查到返回值是该数组中第一个该元素的索引,否则返回-1
console.log(arr.indexOf(2)) //1
console.log(arr.indexOf(5)) //-1

//lastindexOf(元素) 从后往前通过元素查找索引......
console.log(arr.lastindexOf(2)) //2
forEach遍历数组

特点:forEach就是单纯的一个遍历数组,没有返回值

// forEach 内部是一个函数,array.forEach(function(item,index){})
var arr = [1,2,3,4]
arr.forEach((item,index)=>{
	console.log(item,index) //每个元素和元素的索引
})
filter过滤器
// filter 返回符合条件的元素并组成一个新数组,不会改变原数组,全部不符合条件也会返回空数组,array.filter((item,index,array[])=>{})
var arr = [1,2,3,6,7,8]
var arr1 = arr.filter(item=>item>5) //[6,7,8]
every遍历数组
// every 检查数组中的所有元素是否满足条件,全部满足返回true,否则返回false
var arr [1,2,3,6,7,8]
console.log(arr.every(itme=>item>5)) //false
console.log(arr.every(itme=>item<10)) //true
some遍历数组

特点:只要找到满足条件的第一个元素就停止遍历

// some 检查数组中的元素是否有满足条件,如果有返回true,如果没有则返回false
var arr = [1,2,3,6,7,8]
var flag = arr.some((itme)=>{
	console.log(item) //1,2,3,6
	return item>5
})
console.log(flag) //true
reduce累加器
// reduce array.reduce(function(上一次的值,这一次的值){},初始值(可不填)),返回累加的结果
var arr = [1,2,3,4,5]
// 没有初始值
console.log(arr.reduce((old,now)=>{return old += now})) //15
// 有初始值
console.log(arr.reduce((old,now)=>{return old += now},10)) //20
find查找元素、findIndex查找索引

特点:只要找到满足条件的第一个元素就停止遍历

var arr = [1,2,3,6,7,8]
// find 返回满足条件的第一个元素,否则返回undefined
console.log(arr.find(item=>item>5)) //6

// findIndex 返回符合条件的第一个元素索引,否则返回-1
console.log(arr.findIndex(item=>itme>5)) //3
// findLast
console.log(arr.findLast(item=>item<5)) //3

// findLastIndex 从后朝前查找,返回第一个满足条件的元素索引,否则返回-1
console.log(arr.findLastIndex(item=>itme<5)) //2
map修改数组元素
// map 对原数组一一映射,批量修改数组中的元素,返回新数组,不会改变原数组
var arr1 = [1,2,3]
var arr2 = [
	{
		name:'张三',
		age:12
	},
	{
		name:'李四',
		age:18
	}
]
console.log(arr1.map(item=>item*10)) //[10,20,30]
console.log(arr2.map(item=>item.age+1)) //[13,19]
fill替换数组元素
// fill 把数组内容替换掉,fill(替换的值,开始替换的位置(索引),结束替换的位置(索引,不包含此位置))
// 只写参数1,默认全部替换
var arr = [1,2,3]
console.log(arr.fill('o')) //['o','o','o']
console.log(arr.fill('o',1)) //[1,'o','o']
console.log(arr.fill('o',1,2)) //[1,'o',3]
concat合并数组
// concat array.concat(需要合并的数组),返回一个新数组
var arr1 = [1,2,3]
var arr2 = [4,5]
console.log(arr1.concat(arr2)) //[1,2,3,4,5]
join数组转字符串
// join(分隔符) 分隔符可以是特殊符号,如果不写分隔符默认是逗号,返回一个新字符串,不会改变原数组
var arr = [1,2,3]
console.log(arr.join()) //1,2,3
Array.isArray()判断是否为数组
// Array.isArray() 判断是否为数组,如果是数组返回true,反之false
console.log(Array.isArray([1,2,3])) //true
console.log(Array.isArray(1,2,3)) //false
includes判断数组是否包含某值
// includes 判断数组是否包含某值,有返回true,否则返回false
var arr = [1,2,3]
console.log(arr.includes(2)) //true
console.log(arr.includes(4)) //false
Array.from()把伪数组转换为真数组
// Array.from() 可以把伪数组转换为真数组
function f(){
	console.log(arguments) //伪数组
	console.log(Array.from(arguments)) //真数组
}
f(1,2,3,4)
Array.of可以把一组值转换为数组
console.log(Array.of(1,2,3)) //[1,2,3]
Array把一组数转为数组
console.log(Array(1,2,3)) //[1,2,3]
set数组去重
// 使用set方法创建的值是set类型(伪数组),可以去重,然后再通过Array.from或扩展运算符把set类型转为真数组
var arr = [1,2,2,3,3,4]
// var set = Array.from(new Set(arr))
var set = [...new Set(arr)]
console.log(set) //[1,2,3,4]
8、数组去重有哪些方法
var arr = [1,2,2,3,3,4]

// 方法一,断新数组里是否存在arr的每个元素,用indexOf查询,如果查询结果是-1则用push方法添加这个元素
var newArr = []
for(var i =0;i<arr.length;i++){
	if(newArr.indexOf(arr[i])==-1){
		newArr.push(arr[i])
	}
}
console.log(newArr) //[1,2,3,4]

// 方法二,用set方法
var set = Array.from(new Set(arr))
console.log(set) //[1,2,3,4]
9、ES6有哪些新特性

不一样的变量声明:const和let

模块字符串

var a = 1
var str = `a=${a}` 

xx.innerHTML = `
	<li>${a}</li>
	<br>
`

箭头函数

var add = function(a,b) {
	return a + b
}

var add = (a,b) => a+b

函数的参数默认值

function f(a=1) {
	console.log(a)
}
f() //1
f(2) //2

对象和数组解构

var [a,b,c] = [1,2,3]
console.log(a,b,c) //1,2,3

var [,b,c] = [1,2,3]
console.log(b,c) //2,3

var [a,b,c,d] = [1,2,3]
console.log(d) //undefined

var [a,b,c] = 'hello'
console.log(a,b,c) //h,e,l

// c=1为变量c默认值,如果赋值时值为空,则展示默认值,反之展示赋值的值
var [a,b,c=1] = [1,2,3]
console.log(c) //3

var student = {
	name: 'Sam',
	age: 22,
	sex: '男',
	data: {
		msg: '我是对象的对象'
	}
}
var {name,age,sex} = student
console.log(name,age,sex) //Sam,22,男

// 对象解构时修改解构出来的变量名,解构出来的变量名:修改成为的变量名
var {name:uname} = student
console.log(uname) //Sam

// 解构对象里层的属性
var {data:idata} = obj
console.log(idata) //{msg: '我是对象的对象'}
10、var let const的区别

var可以重复声明变量,let不可以重复声明,const不可以重复声明常量

const声明的是常量,声明的简单数据类型不可以修改,复杂数据类型的值可以修改

var可以预解析,let没有预解析

全局作用域下var声明的变量指向window,let没有指向

var声明的变量不会存在块级作用域,let存在块级作用域,const也存在

let在块级作用域下存在暂存性死区,const也存在暂存性死区

在不同的作用域下lei可以声明相同的变量名

var和let可以先声明再赋值,const声明必须一起赋值

11、浅拷贝有哪些方法

浅拷贝只能拷贝第一层的简单数据类型

对象浅拷贝:

object.assign 扩展运算符 …

object.assign(合并给谁,需要合并的对象,需要合并的对象,…)

特点:如果对象里有重复的属性时,以最后一个属性值为准

var obj = {
	name: '张三',
    age: 28,
    hobby: ['螺狮粉', '巧克力'],
    gold: {
    	a: '金'
	}
}
// object.assign
var newObj = {}
Object.assign(newObj,obj)

// 扩展运算符 ...
var newObj = {...obj}

console.log(newObj)
数组浅拷贝:

concat 扩展运算符 …

[].concat(需要合并的数组),返回新数组

var arr = ['张三', 18, { name: '111' }]
// concat
var newArr = []
var arr2 = newArr.concat(arr)

// 扩展运算符
var arr2 = [...arr]
12、如何判断是否是一个数组
Array.isArray()判断是否为数组
// Array.isArray() 判断是否为数组,如果是数组返回true,反之false
console.log(Array.isArray([1,2,3])) //true
console.log(Array.isArray(1,2,3)) //false
13、构造函数和原型对象 对象原型
prototype:原型对象

​ 每个构造函数都有一个prototype属性

​ prototype属性也叫对象

​ 经常会把公用的方法和属性存放在prototype身上

​ 只要写在原型对象上的方法或属性,谁都可以访问到

​ 场景:就是把相同的方法直接写在prototype里,

function Person(name) {
	this.name=name
	//this.say = function(){
	//	console.log('我是构造函数里的方法')		
	//}
}
Person.prototype.say = function(){
	console.log('我是构造函数里的方法')
}
console.log(Person.prototype) //{say: f}
__proto__ :对象原型

只要构造函数在prototype上存储方法或属性时,创建的对象都可以通过__proto__访问到

__proto__是实例化对象上的属性

以前的浏览器是直接显示__proto__ 非标准的写法

现在[[prototype]]就代表__proto__

function Person(name,age){
	this.name=name
	this.age=age
}
Person.prototype.say = function(){
	console.log('我是构造函数里的方法')
}
var peroson = new Person('张三',18)
console.log(peroson)
console.log(peroson.__proto__)
console.log(Person.prototype)
console.log(peroson.__proto__ === Person.prototype) //true
14、构造函数中的new做了什么

1.创建了空对象

2.this指向创建的这个对象

3.通过this给这个对象添加属性和方法

4.返回这个对象(相当于return)

15、什么是闭包和递归,有哪些缺点

闭包:内部函数访问外部函数的变量,无论内部函数调不调用,都会产生闭包

作用:1.外部函数可以访问内部函数的变量

​ 2.函数执行完后,变量依然存在内存中不会被销毁,延长变量的生命周期

递归:一个函数在内部自己调自己

缺点:内存溢出,当程序运行超出了内存,就会导致内存溢出,导致错误

16、js数据类型有哪些

简单数据类型:number string boolean undefined null symbol(独一无二) bigint(num)

​ 存储在栈里面

复杂数据类型:object(object、array、function)

​ 对象名存储在栈里面,属性和属性值存储在堆里面

​ 是栈里的url地址指向堆里面的值

17、箭头函数的this指向、箭头函数有哪些特点

箭头函数没有自己的this指向,他的this指向是通过上下文决定

var fn = () => {
	console.log(this) //window
}
fn()

特点:

// 箭头函数如果只有一个形参时,可以不写小括号()
var fn = a => {
	console.log(a) //10
}
fn(10)
// 如果函数内只有一段代码时,可以不写花括号,会自动return出来
var fn = a => console.log(a) //10
fn(10)
// 如果函数只有一个形参并且给了默认值,小括号不能省略
var fn = (a=1) => a
console.log(fn()) //1
// 箭头函数没有arguments属性
var fn = () => {
	console.log(arguments) //arguments is not defined
}
fn()
// rest属性,拿到的是以数组形式存在的实参值,是一个真数组
var fn = (a,b,...rest) => {
	console.log(a,b) //1,2
	console.log(rest) //[3,4,5,6]
}
fn(1,2,3,4,5,6)
// 不是所有的函数可以用箭头函数
var name = '张三'
var obj = {
	name: '李四'
	speak1: function(){
		console.log('我叫'+this.name) //我叫李四
	}
	speak2:() => {
		console.log('我叫'+this.name) //我叫张三
	}
}
obj.speak1()
obj.speak2()
18、js的运行机制是什么

同步任务:单线程

异步任务:注册事件、定时器、promise,在任务队列里

19、本地存储的方法及特点

本地存储:把数据存储在浏览器中,可以方便取改删

sessionStorage

sessionStorage.setItem(key,value) key是变量名,value是值,把数据存储在本地,也可以改变数据

生命周期是关闭浏览器窗口(浏览器窗口关闭后,数据才会被删除)

同一个窗口下数据可以共享

sessionStorage.getItem(key) 从本地读取数据

sessionStorage.removeItem(key) 删除本地存储的其中一个数据

sessionStorage.clear() 把本地存储的数据全部删除

localStorage

localStorage.setItem(key,value) key是变量名 value是值 把数据存储在本地,也可以改数据

命周期是永久性的存在(浏览器窗口关闭后,数据依然存在,除非手动删除)

同一个窗口下数据可以共享

localStorage.getItem(key) 从本地读取数据

localStorage.removeItem(key) 删除本地存储的其中一条数据

localStorage.clear() //把本地存储的数据全部删掉

20、什么是事件代理

事件代理:给父元素添加事件来处理子元素(冒泡)

father.addEventListener('click', function (e) {
	e.target.style.backgroundColor = 'red'
}
21、深拷贝和浅拷贝的特点

深拷贝可以拷贝复杂数据类型及每一层的复杂数据类型

浅拷贝只能拷贝复杂数据类型的第一层简单数据类型

22、防抖节流的特点

防抖:在单位时间内,频繁触发事件,只执行最后一次

节流:在单位时间内,频繁触发事件,只执行第一次

23、判断数据类型的方法及他们的特点

typeof运算符 可以判断简单数据类型,判断null和数组时会返回object

instanceof 主要是通过原型和原型链进行判断,无法判断基本数据类型,可以判断某个实例化对象是某个构造函数创建的

constructor 构造函数,可以判断所有数据类型,但是constructor会被修改指向问题,所以无法正确判断数据类型

Array.isArray()判断是否为数组

24、arguments的特点

arguments 函数的内置对象,每个函数自身都有一个arguments属性,可以通过arguments获取函数所有实参

是一个伪数组,它有数组的length属性,也有索引,但是没有数组的方法

可以通过Array.from()转换为真数组

25、innerHTML和innerText区别

innerText 获取文本内容(不包括html标签) 会去掉空格和换行,可以改变元素内容

innerHTML 获取html标签及文本(识别html标签)会保留空格和换行,可以改变元素内容

26、contiune/break/return区别

continue: 跳出本次循环

break: 结束整个循环

return: 可以终止代码向下执行,还可以结束整个循环,可以返回值

27、数组转字符串 字符串转数组

数组转字符串

// join(分隔符) 分隔符可以是特殊符号,如果不写分隔符默认是逗号,返回一个新字符串,不会改变原数组
var arr = [1,2,3]
console.log(arr.join()) //1,2,3

字符串转数组

// split(分隔符),字符串是用什么分隔的,分隔符就写什么
var str = '1,2,3'
console.log(str.split(',')) //[1,2,3]

var str1 = 'hello&world'
console.log(str1.split('&')) //[hello,world]
28、作用域,预解析

作用域:全局和局部

全局作用域:

​ script脚本以及引入的js文件都是全局作用域

​ 在任何位置都可以访问到全局作用域下的变量

​ 使用var声明的变量就是全局作用域(在全局作用域下声明)

局部作用域:

​ 函数内的变量就是局部作用域的变量

​ 局部作用域的变量只能在局部作用域下访问,全局作用域下访问不到

​ 局部作用域定义的变量名可以和全局作用域下定义的变量名一样,但不会出现覆盖

​ 在局部作用域下访问变量时是以就近原则访问,如果自己作用域下有这个变量则会拿自己的,如果没 有就会在全局作用域下查找

29、事件三要素

1.事件源(触发了谁):触发事件的元素

2.事件类型:click mousemove…

3.事件处理程序:事件触发后要执行的代码(执行函数、回调函数)

30、dom事件流

DOM的事件传播分为三个阶段:

  1. 捕获阶段:事件对象通过目标的祖先从窗口传播到目标的父对象。这个阶段称为捕获阶段。
  2. 目标阶段:事件对象到达触发事件对象的目标。这个阶段也被称为目标阶段。如果事件类型没有事件冒泡,则事件对象将在完成此阶段后停止。
  3. 冒泡阶段:事件对象以相反的顺序通过目标依次向祖先进行传播,从目标的父对象开始,到窗口结束。这个阶段也称为冒泡阶段。

事件在整个事件流的传播过程中有两个属性需要注意:

  • currentTarget:在整个事件流是变化的,表示事件到达的目标元素
  • target:在整个事件流是不变的,表示触发事件的元素

事件委托:

事件的委托利用事件冒泡的原理,把子元素的事件响应处理函数委托至父元素处理。其优点如下

  1. 减少事件的绑定,减少占用内存,减少dom的引用
  2. 新增的子元素可以动态的添加绑定事件

阻止事件传播的相关方法:

// 阻止事件冒泡:子元素执行事件时,阻止父元素执行
son.addEventListener('click', function (e) {
	alert('son被点击!!!')
	e.stopPropagation()
})
father.addEventListener('click', function () {
	alert('father被点击!!!')
})
// 阻止默认行为:在html中有些标签有默认行为,例如:a会默认跳转页面

// e.preventDefault 阻止默认行为  ie9以下不支持
a.onclick = function (e) {
	e.preventDefault() //标准写法
}
a.attachEvent('onclick', function (e) {
	e.returnValue = false  //ie9以下可以支持
})
31、BOM对象

ECMAScript 把浏览器对象模型(BOM)描述为JavaScript的核心

  • window:BOM 的核心
  • location:获取页面信息
  • navigation:标识浏览器
  • history:操作浏览器历史
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值