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的事件传播分为三个阶段:
- 捕获阶段:事件对象通过目标的祖先从窗口传播到目标的父对象。这个阶段称为捕获阶段。
- 目标阶段:事件对象到达触发事件对象的目标。这个阶段也被称为目标阶段。如果事件类型没有事件冒泡,则事件对象将在完成此阶段后停止。
- 冒泡阶段:事件对象以相反的顺序通过目标依次向祖先进行传播,从目标的父对象开始,到窗口结束。这个阶段也称为冒泡阶段。
事件在整个事件流的传播过程中有两个属性需要注意:
- currentTarget:在整个事件流是变化的,表示事件到达的目标元素
- target:在整个事件流是不变的,表示触发事件的元素
事件委托:
事件的委托利用事件冒泡的原理,把子元素的事件响应处理函数委托至父元素处理。其优点如下
- 减少事件的绑定,减少占用内存,减少dom的引用
- 新增的子元素可以动态的添加绑定事件
阻止事件传播的相关方法:
// 阻止事件冒泡:子元素执行事件时,阻止父元素执行
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:操作浏览器历史
- …