js面试题
- 1.如何判断js的数据类型
- 2.强制类型转换跟隐式类型转换
- 3.创建函数的几种方式
- 4. 创建对象
- 5. == 跟 === 的区别
- 6. null和undefined的区别
- 7.什么情况下会返回undefined
- 8.如何区分数组和对象
- 9.多维数字降维
- 10.怎么获取当前日期
- 11.什么是类数组(伪数组),如何将其转化为真实的数组
- 12.如何遍历对象的属性
- 13.dom节点操作
- 14. 阻止默认行为
- 15.事件补获跟冒泡
- 16.事件委托
- 17.setTimeout与setInterval的用法及区别
- 18.document.write()与innerHTML的区别
- 19.this指向问题
- 20.元素拖动如何实现,原理是什么?
- 21.map()跟forEach的区别
- 22.重绘跟回流?如何最小化重绘跟回流
- 23.延迟加载的方式
- 24.动态创建dom的三种方式
- 25.垃圾回收机制
- 26.内存泄漏的原因
- 27.闭包
- 28.数组的原生方法
- 29.字符串方法
- 30.如何在JS中动态添加/删除对象的属性?
- 31.for in与for of的区别
- 32.forEach与for of 的区别
- 33.预解析
- 34.var const let跟暂时性死区
- 35.new操作符干了什么
- 36. 继承
- 37.class,extends是什么,有什么作用
- 38.异步方案
- 39.图片的懒加载跟预加载
- 40.防抖和节流
1.如何判断js的数据类型
1.1 typeof
基本数据类型
注意:正则、{}、[]、null输出结果为object
1.2 A instance of B
1.3 Object .prototype.toString.call()
使用Object对象的原型方法,toString来判断数据类型
2.强制类型转换跟隐式类型转换
2.1 强制类型转换
1. Number()
2.String()
3.创建函数的几种方式
3.1 函数申明
function a(){}
3.2 函数表达式
let t a= new function()
3.3 箭头函数
let a =()=>{}
4. 创建对象
4.1 字面量创建对象
var obj={
name:‘aaa’,
age:12
}
4.2 构造函数创建对象
function student(name,sex,age){
this.name=name,
this.age=age,
this.sex=sex,
}
var zs=new Student(‘zs’,‘男’,'12) // 返回的是一个对象
4.3 利用Object来创建对象
const obj =new Object()
obj.name=‘zs’;
obj.age=12
5. == 跟 === 的区别
==在使用时会进行隐式强制类型转换
null=undefined //true
null === undefined // false
null === null // true
undefined === undefined // true
6. null和undefined的区别
null表示一个空对象通常用于赋值给可能返回一个对象的变量为初值
typeof null // Object
undefined 使用var跟let申明了一个变量 但是没有初始化
var a;
console.log(a) // undefined
null 加任何数字等于数字 undefined加任何数字等于 NAN
7.什么情况下会返回undefined
1.当访问一个申明但是没有赋初值的变量
2. 当访问一个赋初值为undefined的变量
3. 当访问对象中不存在的属性时
4. 当调用一个没有return的函数
5. 当调用一个return没有内容的函数
8.如何区分数组和对象
8.1 instanceof
[] instanceof Array //true
{} instanceof Object //true
8.2 constructor
([]).constructor //Array
({}).constructor //Object
8.3 Object.prototype.toString.call()
Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call([]) // [object Object]
9.多维数字降维
10.怎么获取当前日期
11.什么是类数组(伪数组),如何将其转化为真实的数组
11.1 定义:
1.类数组是一个对象
2.属性名使用数字
3.带有length长度
11.2 特点:
1.不可以使用数组的方法
2.可以转化为真实的数组
3.可以进行循环遍历
11.3 如何转化为真实的数组:
1.Array.form(); es6新增的方法
let arrr = Array.from(objArr);
2.扩展运算符
&emsplet Str = ‘hello’;
&emsplet arr = […Str];
console.log(arr);
3.Array.prototype.slice.call
&emsplet arr1 = Array.prototype.slice.call(objArr)
12.如何遍历对象的属性
12.1 for in
遍历对象的所有属性 包括继承属性
12.2 Object.keys()
Object.keys() // 属性
Object.values() //属性值
Object.entries() 属性和属性值 不包括继承属性
12.3 Object.getOwnPropertyNam()
遍历对象的属性 不包括Symbol()对象
12.4 Object. getOwnPropertySymbol()
遍历对象的所有Symbol属性
13.dom节点操作
13.1添加
13.1.1 node.appendChild(child)
node父级 child子级 后面追加元素 类似于组数的push
13.1.2 node.insertBefore(child,指定元素)
var lili=document.createElement(‘li’);
ul.insertBefore(lili,ul.children[0]);
13.2移除
13.2.1 removeChild()
13.3移动
13.4复制
13.4.1 cloneNode()
// node.cloneNode() 括号为空或者里面是false 浅拷贝 只复制标签 不复制里面的内容
// node.cloneNode(true) 括号里为true 深拷贝 复制标签复制里面的内容
13.5创建
13.5.1 createElement
13.6查找
1.getElementById
2.getElementsByTagName
3.getElementsByClassName
4.querySelector
14. 阻止默认行为
1.preventDefault()
2 return flase
15.事件补获跟冒泡
- addEventListener(‘click’,function(){},true)
第三个参数是true 就是事件补获 是false就是事件冒泡
当点击一个元素 触发某种事件时 从window对象传导到目标节点 - 事件补获ducument=>html=>body=>farher=>son 反之就是事件冒泡
- 阻止事件冒泡 stopPropogation()
var son=document.querySelector(‘.son’);
son.addEventListener(‘click’,function(e){
alert(‘son’);
e.stopPropagation(); // stop 阻止 propogation 传播
e.cancelBubble=true // 非标准 cancel 取消 bubble 冒泡
},false)
16.事件委托
原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
17.setTimeout与setInterval的用法及区别
- setTimeout是延时时间到了 就去调用这个函数 只调用一次 就结束了这个计时器
- setInterval是每隔一段事件重复执行一次代码 如果执行事件超过了事件间隔,setInterval()仍然会在执行完后立即执行下一次代码,而不是等待事件间隔
18.document.write()与innerHTML的区别
- document.write()会导致页面重新渲染
- innerHTML是覆盖或者追加动作,同时创建多个元素效率更高,采用数组的形式拼接
// var inner=document.querySelector(‘.inner’);
// var arr=[];
// for(var i=0;i<100;i++){
// arr.push(‘百度’);
// }
// inner.innerHTML=arr.join(‘’) // join 数组转换为字符串
19.this指向问题
- 在构造函数中,this指向构造函数的实例
- e.target指向触发事件的对象,this指向事件绑定的对象
20.元素拖动如何实现,原理是什么?
首先mousedown x=e.pageX-login.offsetLeft 得到鼠标在元素内部的位置
然后mouseMove时候 loginX=e.pageX- x 得到物体距离左边界的距离
将left=loginX
21.map()跟forEach的区别
区别主要在于map有返回值,而forEach没有返回值
22.重绘跟回流?如何最小化重绘跟回流
23.延迟加载的方式
23.1 async
- 延迟脚本
- 立即下载,但是延迟执行(延迟到整个页面都加载完毕后再执行)
- 按照脚本的先后顺序执行
23.2 defer
- 异步脚本
- 下载完立刻执行
- 不保证按照脚本的先后顺序执行
23.3 动态创建dom(用的最多)
24.动态创建dom的三种方式
- ducument.write()
- innerHTML
- document.createElement
25.垃圾回收机制
- 垃圾回收机制是为了防止内存泄漏,将不再使用的变量和对象并将它们从内存中清除,以释放内存空间。
- 最常见的是标记清除法
- 工作原理:是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
- 工作流程
–垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记
–去掉环境中的变量以及被环境中的变量引用的变量的标记。
–再被加上标记的会被视为准备删除的变量。
–垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。
26.内存泄漏的原因
- 意外的全局变量(在函数内部没有进行var变量申明)
- console.log
- 闭包
- 未清除的定时器
- 对象的循环引用
- DOM泄漏(获取到DOM节点之后,将DOM节点删除,但是没有手动释放变量)
27.闭包
闭包的概念:通过函数作用域,内部的函数可以访问到外部函数的变量
- 优点:
– 避免全局变量的污染
– 希望一个变量长期存储在内存中(缓存变量) - 缺点:
– 内存泄漏
–增加内存使用量 - 呃呃呃呃呃呃呃呃呃呃呃呃鹅鹅鹅使用场景:封装功能时(需要使用私有的属性和方法),函数防抖、函数节流、函数柯里化、给元素伪数组添加事件需要使用元素的索引值。
28.数组的原生方法
var fruits = [“Banana”, “Orange”, “Lemon”, “Apple”, “Mango”];
- pop() 删除数组的最后一个元素并返回删除的那个元素(改变原数组)
- shift() 删除数组的第一个元素并返回删除的那个元素(改变数组)
- push()向数组的末尾添加一个或者多个元素 返回的是新数组的长度(改变数组)
- unshift() 在数组的头部添加一个元素 返回的是新数组的长度(改变数组)
- slice()提取字符串的某个部分,并以新的字符串返回被提取的部分(不会改变数组)
–var citrus = fruits.slice(1,3); // Orange,Lemon slice - splice(何处添加元素,删除元素的个数,添加的新元素)(会改变原数组)
- splice(start,length)第一个参数开始位置,第二个参数截取长度 (会改变原数组)
- concat() 数组/字符串拼接 // a.concat(b)
- join 将数组用标识符链接成字符串返回拼接好的字符串(不改变原数组);
- reverse() 数组翻转
- toString() 将数组转换为字符串
- split() 字符串分割
- forEach() a.forEach(function(){}) a.forEach(item=>{})
- every() 主要用于检查数组中每个元素是否符合函数的条件,如果其中有一个不符合,则返回false;
- indexOf() 主要用于在数组中查找元素,并把元素的位置返回来。
29.字符串方法
- slice() 截取字符串2个参数,(起始位置,结束位置)
- substring():截取字符串,(起始位置,结束位置)
- substr():截取指定位置和长度的字符串,(起始位置,长度)
- trim():去掉字符串前后所有空格
- split():把字符串按分隔符分割成数组
- indexOf():通过字符查找对应下标(首次出现)
- lastIndexOf():通过字符找最后一次出现的下标值
- charAt():根据下标找到对应值
- charCodeAt():通过下标值找到对应字符Unicode编码
- toLowerCase():字符串转为小写
- toUpperCase():字符串转成大写
30.如何在JS中动态添加/删除对象的属性?
咱们可以使用object.property_name = value向对象添加属性,delete object.property_name 用于删除属性。
例如:
let user = newObject();
// adding a property
user.name=‘Anil’;
user.age =25;
console.log(user);
delete user.age;
console.log(user);
31.for in与for of的区别
区别一:
- for(const index in arr){} index 是数组的小标
- for(const item in arr){} item 是数组的每项的值
区别二: - for…in 循环不仅遍历数字键名,还会遍历手动添加的其它键,甚至包括原型链上的键。for…of 则不会这样
共同点: - 都不能遍历symbol类型的值,遍历symbol类型的值需要用Object.getOwnPropertySymbols()
32.forEach与for of 的区别
forEach不能跳出循环,break 命令或 return 命令都不能奏效;for…of 循环可以与break、continue 和 return 配合使用,跳出循环
33.预解析
预解析就是将所有的变量申明(var)跟函数申明(function)提前到当前作用域的最前面(不提升赋值跟调用函数)
预解析分为变量提升跟函数执行
函数执行就是代码从上到下执行
34.var const let跟暂时性死区
- var 存在变量提升,可以重复申明,全局作用域
- const 变量不可改变,一般用于定义常量,存在块局作用域
- let 不存在变量提升,变量可以改变
- 暂时性死区:在还没有定义的情况下,使用该变量
35.new操作符干了什么
36. 继承
37.class,extends是什么,有什么作用
38.异步方案
39.图片的懒加载跟预加载
39.1懒加载
-
定义:在需要的时候才加载图片,延迟加载甚至不加载图片。
-
原理:利用自定义属性,将图片的自定义scr存到图片标签身上,在需要使用的时候将自定义的scr赋值给src
-
可视区的高度:window.innerHeight
-
兼容性写法:let clientHeight=window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
-
图片在可视区下面:offsetTop>scrollTop+clientHeight
-
图片在可视区上面:offsetTop+offsetHeight<scrollTop
-
// 懒加载
// 参数 : 需要进行预加载的图片的 id (#id) , 类名(.class) ,或标签名(img)
export default function lazyLoad(imgSelector) {
const clientHeight = window.innerHeight|| document.documentElement.clientHeight || document.body.clientHeight , // 兼容获取
const scrollTop = document.documentElement.scrollTop; // 获取页面被卷出去的顶部的高度大小
let imgsNodes = document.querySelectorAll(imgSelector); // 获取预加载图片列表// 遍历检查图片是否在可视区内
imgsNodes.forEach((v) => {
if (
v.offsetTop < clientHeight + scrollTop &&
v.offsetTop + v.offsetHeight > scrollTop
) {
// 设置正确的 src
// 实际使用时
// v.src = v.getAttribute(“srcString”);// 这里使用计时器模拟加载时间 ,为能看到是先显示再加载的效果 。 setTimeout(() => { v.src = v.getAttribute("data-srcString"); }, 800);
}
});
} -
懒加载优化:节流
window.onload = function(){
lazyLoad(‘img’) // 先执行let stop = true; // 节流阀 function throttle (){ // 节流函数 if(stop){ // 如果被节流了 setTimeout(() => { stop = false console.log('节流'); }, 100); return } stop = true lazyLoad('img'); return; } window.addEventListener('scroll',throttle) // scroll 的执行函数改为节流函数}
-
防抖:我们要的图片得往下滑好几页 。 所以前面的几页图片是可以不需要显示的。或者前面的之前我们已经预览过了,我希望预览比较靠后的图片。那么前面的也可以不用去加载了。那么这种情况就可以使用防抖技术了。
let stop = true;
let timeID = ‘’; // 增加一个变量保存倒计时器的 ID
function throttle (){
if(stop){
setTimeout(() => {
stop = false
}, 100);
return;
}
stop=true
// 删除上一个倒计时器
clearTimeout(timeID)
// 重新设置倒计时器
timeID = setTimeout(()=>{
lazyLoad(‘img’);
return
},100) // 延缓 0.1 秒后加载
}
39.2 预加载:通过js的new Image()
1.创建数组,将图片的src存在数组中
2.循环遍历数组,通过new Image,创建Image对象
3.将数组中的src赋值给img的src
let imgs = [
‘./imgsrc1’,
‘./imgsrc2’,
‘./imgsrc3’,
];
const preloadImg(imgUrls) {
imgUrls.forEach(imgUrl => {
// 生成图片对象
const img = new Image()
img.src = imgUrl
})
}
preloadImg(imgs)
40.防抖和节流
防抖:就是只连续触发事件,在设定的一段时间内只执行最后一次
应用场景:搜索框
实现思路:节流