目录
- 【常问】
- 【ES6】
- JS基础
- ❗栈stack和堆heap
- ❗js中的内存泄露
- ❗null和undefined的区别
- ❗0.1+0.2=0.3返回true还是false?怎样可以返回true?
- ❗2)typeof返回的数据类型有哪些?
- ❗如何判断一个数据是NaN
- ❗判断数据类型的方法
- 判断数组的方法
- ❗2)数组常用操作方法
- ❗2)map和forEach有什么区别
- ❗splice和slice和split区别
- ❗for in和for of区别
- ❗怎么遍历多层嵌套的数组?
- ❗2)this指向
- ❗call、apply、bind有什么区别?
- ❗js中有哪些事件
- ❗js里有变量提升的问题?怎么解决这个问题?
- js获取一个对象上所有的key有哪些方式
- js怎样添加、移除、移动、复制、创建和查找节点?
- js中的`==`和`===`有什么区别?
- js中哪些数据在if判断时是false
- ❗什么是回调函数
- 作用域和作用域链
- JS对象/类
- JS库
- 【Git】
【常问】
❗7)深拷贝和浅拷贝
考点:(1)能答上基本数据类型和引用数据类型的关系(2)能答上堆栈关系
js的数据类型有基本数据类型和引用数据类型,基本数据类型是存储在栈中,引用数据类型的地址是存储在栈中,值是存储在堆中的。
深拷贝复制的是对象的值和对象的引用,新对象和原对象不会共享内存,修改复制后的对象不会影响原对象。
浅拷贝复制的是对象的引用,新对象和原对象还是共享同一块内存,如果修改复制后的对象,原对象也会跟着改变。
深拷贝实现
1.1 JSON对象
JSON.parse(JSON.stringify(value))
JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象
缺点:不能复制undefined、function、symbol的类型
const info = { name: 'why', age: 18, friend: { name: 'lili' } }
const obj = JSON.parse(JSON.stringify(info))
info.friend.name = 'cici'
console.log(obj.friend.name) //lili
1.2 递归
function deepClone(obj) {
//判断储存的类型
let objClone = Array.isArray(obj) ? [] : {};
if (obj && typeof obj === 'object') {
//循环遍历obj的key
for (let key in obj) {
if (obj[key] && typeof obj[key] === 'object') {
//循环递归直到属性不为一个object为止
objClone[key] = deepClone(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
return objClone;
}
let person1 = {
name: '园丁',
job: {
age: 18,
address: '高新',
id: {
idCard: 5003888
}
}
};
let person2 = deepClone(person1);
person2.job.age = 19
person2.job.id.idCard = 155
console.log(person1, 'person1');
console.log(person2, 'person2');
1.3 jQuery的$.extend()
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js">
</script>
<script>
let person1 = {
name: '园丁',
job: {
age: 18,
address: '高新',
id: {
idCard: 5003888
}
}
};
let person2 = $.extend(true, {}, person1);
person2.job.age = 19
person2.job.id.idCard = 155
console.log(person1, 'person1');
console.log(person2, 'person2');
</script>
1.4 通过第三方库loadsh,深拷贝_.cloneDeep(value)
浅拷贝实现
1.1 Object.assign({}, info)
ES6对象的合并,第一个参数必须是个空对象。会把info对象所有的属性拷贝到{}中,会将拷贝的对象作为返回值返回出去用obj接收,会创建一个新的对象,拷贝所有的属性,保存对象的引用
const info = { name: 'why', age: 18, friend: { name: 'lili' } }
const obj = Object.assign({}, info)
info.name = 'kobe'
console.log(obj.name) //kobe
info.friend.name = 'cici' //把info里面对象的属性值改了,就等于把拷贝的obj的值也改了
console.log(obj.friend.name) //cici
1.2 展开运算符…
const fxArr = ["One", "Two", "Three"]
const fxArrs = [...fxArr]
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]
1.3 Array.prototype.concat(),Array.prototype.slice()
都不会改变原数组
const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.concat()
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]
const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.slice(0)
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]
1.4 通过第三方库loadsh,浅拷贝_.clone(value)
❗6)事件循环(event loop)?宏任务微任务有了解吗?
因为js是单线程的,同一时间只能做一件事情,所以所有的任务都需要排队。js执行的线程就称为主线程,当主线程执行的时候,遇到同步任务就直接运行,遇到异步任务会创建任务队列把异步任务放到队列里面。当同步任务执行完成以后,再去执行任务队列中的异步任务。异步任务又分为宏任务和微任务,微任务会创建一个微任务队列,宏任务会创建宏任务一个队列,会先把微任务全部放到执行栈中执行,最后再从宏任务队列中取出一个放入执行栈中执行,执行完后,再取一个,直到执行完所有的宏任务。当任务执行完以后,重复这样的查找执行,整个这个过程和机制,称为js的事件循环。
宏任务:setTimeout,setInterval,ajax,Dom事件回调
微任务:process.nextTick(Node独有),Promise.[then/catch/finally],async/await
❗2)事件委托(事件代理)
比如说我时候想做一个事件委托,就是有一个ul,还有li,我点击这个li,我不可能对每个li都绑定点击事件,我需要做一个事件委托,这时候可以怎么做啊,我要绑定这个事件
事件委托:将元素的事件委托给它的父级或者更外级的元素处理,它的实现机制就是事件冒泡。
❗阻止事件冒泡和默认行为
阻止事件冒泡
W3C:event.stopPropagation()
IE:event.cancelBubble = true
阻止事件默认行为
W3C:event.preventDefault
IE:event.returnValue = false
场景:a标签href属性上的跳转;鼠标右键呼出菜单
return false方法阻止事件冒泡和默认行为
JS的return false只会阻止默认行为
jQuery的return false既阻止默认行为又阻止对象冒泡
<div id="father" onclick="alert('father')">
<h3>father</h3>
<div id="son" onclick="alert('son')">
<h3>son</h3>
<a href="https://www.baidu.com" id="btn">son</a>
</div>
</div>
<script>
/*阻止冒泡*/
$('#son').click(function (e) {
e.stopPropagation();
})
/*阻止默认事件*/
$('#btn').click(function (e) {
e.preventDefault();
})
/*return false既会阻止默认行为也会停止冒泡*/
$("#son").on('click', function () {
return false
})
</script>
❗4)原型和原型链
原型:每个函数都有一个prototype属性,它指向的是原型对象(Person.prototype
),这个原型对象的作用是共享对象的所有属性和方法。所有的原型对象里都有一个constructor
属性,它指向的是创建它的构造函数。
原型链:每个对象都有个__proto__
属性,通过这个属性可以访问到原型对象。当访问一个实例的属性时,会先在当前实例上找,如果没找到就会通过__proto__
到原型对象上一级一级的去查找,最终会找到顶级对象Object.prototype
,它指向的是null。构造函数、原型对象、实例之间的联系就构成了原型链。
hasOwnProperty是判断一个对象是否有某个属性或对象。var obj={}; obj.hasOwnProperty("val") //判断obj对象是否具有val属性
注释:
- prototype属性(显式原型)、constructor(构造器)、
__proto__
属性(隐式原型) - constructor它为了让构造函数构造出来的所有的对象都能找到自己的构造器
- 通过构造函数new创建出来的对象是"实例对象"
//这个是函数
function fn(){
//to do something
}
//这个是方法 通过对象调用的javascript函数
var obj = {
//两种写法都可以,用逗号分隔
fn: function () {
console.log("xixi")
},
fn1() {
console.log("hahha")
}
}
obj.fn()//方法调用
obj.fn1()//方法调用
//这个是构造函数
function Fn(){}
//这个obj就是实例对象
var obj = new Fn()
❗2)构造函数,new的过程
创建对象三种方式:
①对象字面量var obj = {}
②系统自带的构造函数var obj = new Object()
③自定义构造函数
构造函数是一种特殊的函数,主要用来初始化对象,为对象成员变量赋初始值,它需要跟new一起使用,然后它的首字母要大写。(有浪费内存问题)
new的过程:
- 创建一个空的对象
- 将新创建的空对象的隐式原型proto指向构造函数的原型对象prototype
- 将构造函数中的this指向这个空对象
- 判断构造函数返回值的类型。如果没有返回值或返回值是基本数据类型,就把这个新创建的对象返回;如果返回值是引用数据类型,就返回这个引用类型的对象(所以构造函数里面不需要return)
// 定义一个Person构造函数
function Person(name, age){
this.name = name;
this.age = age;
}
//另外定义一个createNew()用来模拟new关键字的执行过程
function createNew(fn, ...args) {
// 1. 创建一个空对象
let obj = {};
// 2. 将新对象的__proto__属性指向构造函数的原型对象prototype
obj.__proto__ = fn.prototype;
// 3.将构建函数的this指向新对象
let result = fn.apply(obj, args);
//console.log(result) //fn.apply()的返回值就是fn的返回值,由于例子中Person()没有返回值,所以此处返回值是undefined
//4. 根据返回值判断。如果构造函数返回的是引用数据类型,则直接返回这个结果。否则,返回新创建的对象
return result instanceof Object ? result : obj;
}
//执行createNew()看一下它的返回结果
let createNew1 = createNew(Person, 'yy', 18)
console.log(createNew1)//Person {name: "yy", age: 18}
//使用new直接操作Person()看一下它的结果
let person = new Person('yy',18)
console.log(person )//Person {name: "yy", age: 18}
//可以看到createNew()的结果与使用new得到的结果一致,说明createNew()代表的就是new内部的原理。
❗3)js数据类型有哪些?区别?
基本数据类型:String、Number、Boolean、Null、Undefined、Symbol、Bigint
引用数据类型:Object、Array、Function
区别在于存储数据的地方是不同的。
基本数据类型存放在栈中,引用数据类型在栈中保存指针,在堆中保存对象值;
❗4)闭包?特性?实际项目中有哪些应用场景
什么情况会触发闭包:多个函数互相嵌套,内部的函数返回到了外部。
定义:
红宝书:闭包是指有权访问另外一个函数作用域中的变量的函数。
阮一峰:闭包就是能够读取其他函数内部变量的函数(可以把闭包简单理解成"定义在一个函数内部的函数"。)
闭包有3个特性:
①函数嵌套函数;②外部函数可以访问内部函数的变量;③参数和变量不会被垃圾回收机制回收;
优点:可以将一个变量长期存储在内存中,用于缓存;可以避免全局变量的污染。
缺点:
闭包会导致原有作用域链不释放,造成内存泄漏;
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,会造成网页的性能问题。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
应用场景:
①防抖节流函数
//闭包:既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量了
function f1(){
var n = 999;
function f2(){
alert(n);
}
return f2;
}
var result = f1();
result(); // 999
②事件绑定的回调方法
③setTimeout的延时回调
❗3)防抖和节流是什么?应用场景?
防抖和节流都是为了限制函数的执行次数,防止高频调用函数带来的性能损耗和卡顿,节省计算资源。
- 防抖:多次触发事件后,在n秒内只执行最后一次;如果在n秒内又触发了事件,就会重新计时。
- 节流:多次触发事件后,在n秒内只执行一次。
- 防抖应用场景:搜索框搜索输入/输入手机号邮箱验证时的检测(停止输入时才发送请求),窗口调整resize。
- 节流应用场景:滚动加载更多/滚到底部监听,按钮重复点击(刷新按钮、表单重复提交)。
实现方式一:通过第三方库lodash/underscoreinputEl.oninput = _.debounce(inputChange, 2000)
,_.throttle
实现方式二:
/*防抖*/
function debounce(fn, delay) {
let timer = null;
return function(...args){
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay)
}
}
/*节流*/
function throttle(fn, delay) {
let flag = true;
return function (...args) {
if (!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, args);
flag = true;
}, delay)
}
}
❗对象继承的实现方法
- ES6的class继承。
//使用class构造一个父类;再使用class构造一个子类,并使用extends实现继承,super指向父类的原型对象
class Parent{
constructor(){
this.age = 18;
}
}
class Child extends Parent{
constructor(){
super();
this.name = 'haha'
}
}
let ChildList = new Child()
console.log(ChildList)
- 原型链继承。缺点:过多的继承了没用的属性。
function Parent() {
this.age = 18
}
function Child() {
this.name = 'xixi'
}
Child.prototype = new Parent()
let ChildList = new Child()
console.log(ChildList, ChildList.age)
- 借用构造函数。缺点:不能继承借用构造函数的原型;每次构造函数都要多走一个函数。
function Parent() {
this.age = 18
}
function Child() {
this.name = 'xixi'
Parent.call(this)
}
let ChildList = new Child()
console.log(ChildList, ChildList.age)
- 组合继承。
function Parent() {
this.age = 18
}
function Child() {
Parent.call(this)
this.name = 'xixi'
}
Child.prototype = new Parent()
let ChildList = new Child()
console.log(ChildList, ChildList.age)
❗递归
递归就是函数在运行的过程中调用自己。
必须具备两个条件:一个是调用自己,另一个是有终止条件。
运用场景:阶乘、深拷贝
【ES6】
❗5)ES6有哪些新特性
只用说前7个
- 变量声明let和const
- 解构赋值(先提取,再赋值)
var names = ["abc", "bbc", "cbc"];
//对数组的解构:[]
var [item1, item2, item3] = names
console.log(item1, item2, item3)//abc bbc cbc
//解构后两个元素
var [, itema, itemb] = names
console.log(itema, itemb)//bbc cbc
- 箭头函数
- Promise(异步函数)
- class类
- 模块化(import / export / export default)
import { sum } from 'js/index.js'; //只导入一个
import { sum, sub, add } from 'js/index.js'; //导入多个
export default sum//导出
- 扩展运算符…
- 数组的扩展(用于取出参数对象所有可遍历属性然后拷贝到当前对象)
/*基本用法*/
let person = {name: "Amy", age: 15};
let someone = { ...person };
someone; //{name: "Amy", age: 15}
/*可用于合并两个对象*/
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person; //{age: 15, name: "Amy"}
//扩展运算符在等号右边, 将数组中的数据解构开
let arr1 = [1, 3, 5];
let arr2 = [2, 4, 6];
let arr = [...arr1, ...arr2];
// let arr = [1, 3, 5, 2, 4, 6];
- 函数参数的扩展:不定参数(不定参数用来表示不确定参数个数,形如,…变量名)
function f(...values){
console.log(values.length);
}
f(1,2); //2
f(1,2,3,4); //4
- 模板字符串反引号``(可以换行可以嵌套变量,字符串插值${})
- 对象字面量的增强写法
/*属性的增强写法*/
const obj = { name: name, age: age } //ES5写法
const obj = { name, age } //ES6增强写法
/*函数的增强写法*/
bbb:function(){} //ES5写法
bbb(){} //ES6增强写法
- 基本数据类型(Symbol),表示独一无二的值,最大的用法是用来定义对象的唯一属性名
❗4)let、const、var的区别
ES5中的作用域有:全局作用域、局部(函数、块级)作用域。
ES6中新增了块级作用域。块作用域由{}包括,if语句和for语句里面的{}也属于块级作用域。
- 块级作用域:var没有块级作用域,let和const有块级作用域
- 变量提升(变量在声明之前就能使用):var有变量提升,let和const没有
- 重复声明:var可以重复声明变量,let和const不可以
- 设置初始值:声明变量的时候,var和let可以不设初始值,const必须设置初始值
- 指针指向(重新赋值):var和let可以修改指针指向的,const不能修改
- 全局变量:使用var声明的全局作用域变量属于window对象(会被添加到全局对象的属性中),let和const不属于。(var在函数内部是局部变量,在函数外部是全局变量)
let const区别:
let可以不设初始值,const必须设置初始值;
let可以重新赋值,const不可以;let a = 10; a = 20;
总结:
let和const有块级作用域,var没有
var有变量提升,let和const没有
var可以重复声明,let和const不可以
var和let可以不设初始值,const必须设置初始值
var和let可以重新赋值,const不可以
var声明的全局变量会挂载到window上,let和const不会
❗2)箭头函数与普通函数的区别
- 声明方式。普通函数是用关键字function;箭头函数就是=>比普通函数的声明更简洁
- this指向。普通函数有this;箭头函数没有自己的this(会捕获其所在的上下文的this作为自己的this,如果没有上下文环境对象,那么就指向最外层的window)
- arguments。普通函数可以使用arguments来访问传递给函数的参数;箭头函数没有自己的arguments,可以用扩展运算符…代替arguments对象
- new调用。普通函数可以作为构造函数使用new调用;箭头函数没有prototype(原型),不能作为构造函数使用new调用
- 作用域提升。普通函数有作用域提升,可以在定义前调用;箭头函数不可以
- 箭头函数没有new.target。new.target是用来检测函数是否被当做构造函数使用的,会返回一个指向构造函数的引用。
❗3)Promise,业务场景?
Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息。
优点:
支持链式调用,避免了层层嵌套的回调函数,解决了回调地狱的问题。
缺点:
首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
第三,当处于Pending状态时,无法得知目前进展到哪一个阶段。
三个状态:
pending:进行中/等待中;resolved:成功会回调then;rejected:失败会回调catch
两个过程:
pending→resolved,pending→rejected
❗2)promise的API方法有哪些?
Promise.all
可以将多个Promise实例包装成(放在一个数组中)一个新的Promise实例。当全部成功时才会返回成功,有一个失败就返回失败的
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('result1')
},2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('result2')
},1000)
})
]).then(results => {
console.log(results)
})
Promise.race()
Promise.race([p1, p2, p3])
最先得到哪个结果,就返回哪个结果,不管结果本身是成功状态还是失败状态
Promise.any()
Promise.any([p1, p2, p3])
只要有一个成功,就返回成功的promise,如果没有一个成功,就返回一个失败的promise
Promise的基本用法及参数?
①使用new实例化一个Promise对象,Promise的构造函数中传递一个参数。这个参数是一个函数,该函数用于处理异步任务;
②并且传入两个参数:resolve和reject,分别表示异步执行成功后的回调函数和异步执行失败后的回调函数;
③通过promise.then() 处理返回结果。
④Promise自身有all、any、race、reject、resolve方法,原型上有then、catch、finally方法。
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("hello")
}, 1000)
}).then((res) => {
console.log(res)
}).catch((err) => {
console.log(err)
})
❗Promise为什么可以一直.then
因为返回了一个新的promise,新的promise能继续调用.then
Promise中的reject和catch处理上有什么区别?
reject是用来抛出异常,catch是用来处理异常
reject是Promise的方法,而catch是Promise实例的方法
const定义的对象属性能否改变
可以改变对象内部的属性,但是对象的指针不能改变
const p = {
name: 'cc',
age: 18
}
p.name = 'aa' //p对象的name属性是可以改变的
p = {
name: 'bb',
age: 18
}// 如果让p指向一个新对象就会报错
const定义的基本数据类型的变量确实不能修改,因为对象是引用类型的,p中保存的仅是对象的指针,const仅保证指针不发生改变,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。
箭头函数和箭头函数的this指向
箭头函数只有一个参数时,可以省略小括号;箭头函数的函数代码块只有一行代码可以省略{}和return
//普通写法
setTimeout(function(){
},1000)
//箭头函数写法
setTimeout(()=> {
},1000)
箭头函数没有自己的this,会向外层作用域中一层一层的查找直到有this的定义。
JS基础
❗栈stack和堆heap
栈存储的是基本数据类型和引用数据类型的地址,会指向堆内存中的值;
堆存储的是引用数据类型的值;
栈的特点:先进后出,后进先出;
栈内存可以称为一级缓存,由垃圾回收器自动回收;
堆的特点:先进先出,后进后出;
堆内存可以称为二级缓存,堆中的对象不会随时释放,一般需要开发人员自己回收它;
基本数据类型赋值相互不影响,引用数据类型赋值会影响原对象;
var num = 1; // 栈
var name = '前端'; // 栈
// 变量user存在栈中,{name:'河畔'}存在堆内存中
var user = { name: '河畔' };
// 变量arr存在栈中,[1, 2, 3] 作为对象存在堆内存中
var arr = [1, 3, 5];
因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从栈中获取了该对象的指针,然后再从堆内存中取得我们需要的数据。
❗js中的内存泄露
❗null和undefined的区别
- undefined 和 null 都是基本数据类型;
- undefined 表示的是未定义,null 表示的是空对象;使用 typeof 对null进行判断会返回 “object”;
- 当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。
❗0.1+0.2=0.3返回true还是false?怎样可以返回true?
返回false
❗2)typeof返回的数据类型有哪些?
typeof返回的数据类型有:string、number、boolean、undefined、object、function
typeof两种写法:typeof(num)
、typeof num
typeof输出结果:
- typeof null结果:object
- typeof []结果:object
- typeof {}结果:object
- typeof NaN结果:number
- typeof undefined结果:undefined
❗如何判断一个数据是NaN
①isNaN(value)是NaN时会返回true不是NaN会返回false,每次判断会先将值转成数值然后进行判断
console.log(isNaN(NaN)) //true
console.log(isNaN(123)) //false
console.log(isNaN('1531sad')) //true
②Object.is(value1, value2)判断两个值是否为同一个值
console.log(Object.is("a", NaN)) //false
console.log(Object.is(1, NaN)) //false
console.log(Object.is(NaN, NaN)) //true
❗判断数据类型的方法
typeof可以判断基本数据类型,不能判断引用数据类型;
instanceof返回的是布尔值,适合判断引用数据类型。
- typeof
typeof("aaa") --> string
无法判断引用类型(数组函数对象)和null,返回的都是object; - instanceof
[1,2,3] instanceof Array --> true
判断A是否为B的实例,instanceof后面一定要是对象类型,并且大小写不能错; - constructor
let num = 1; console.log(num.constructor); --> number(){}
返回创建实例对象的 Object 构造函数的引用,所有对象都会从它的原型上继承一个 constructor属性。无法判断null和undefined因为它们没有构造函数; - Object.prototype.toString.call(需要判断的值):
Object.prototype.toString.call(1)
基本上所有对象的类型都可以通过这个方法获取到(Boolean、Number、String、Function、Array、Date、RegExp、Object、Error等类型)。
判断数组的方法
let arr = [1, 2, 3];
以下6种方法都返回true
①arr instanceof Array
:判断arr是否是由构造函数Array实例化得到的
②arr.constructor === Array
:判断数组arr的构造函数属性是否等于构造函数本身
③Array.prototype.isPrototypeOf(arr)
:判断构造函数Array的原型是否是arr的原型对象
④Object.getPrototypeOf(arr) === Array.prototype
:获取arr的对象原型属性和构造函数Array的对象原型属性相比较
⑤Object.prototype.toString.call(arr) --> [Object Array]
:最准确。会返回[Object type],其中 type为对象的类型。判断获取的arr的对象原型经过字符串化后的类型是否等于’[Object Array]’
⑥Array.isArray(arr)
:最准确。ES6新增的方法。
❗2)数组常用操作方法
操作方法:
- 增:
push()
、unshift()
- 删:
pop()
、shift()
- 增删:
splice()
- 改:截取
slice()
、拼接concat()
、转换toString()
、join()
- 查:
indexOf()
、find()
、includes()
排序方法:sort()
、reverse()
迭代方法:for of
、for in
(适合遍历对象)、forEach()
、map()
、reduce()
、filter()
、every()
、some()
去重方法:new Set()
❗2)map和forEach有什么区别
共同点:
都是遍历数组的方法
不同点:
map() 不会改变原始数组,会返回一个新的数组
forEach() 会改变原始数组,返回值为undefined
❗splice和slice和split区别
区别:splice会改变原数组,slice,split不会改变原数组。
splice截取(数组) 。功能一是删除数组元素;功能二是删除并插入元素:
let arr = [1,2,3,4,5,6,7,8,9]
// 从下标为3的项开始,依次向后删除2个元素,返回被删除的元素数组:[4, 5],原数组改变为:[1, 2, 3, 6, 7, 8, 9]
arr.splice(3,2)
slice切割(字符串/数组)。
let str = 'hello world'
// 截取下标 [2,5) 区间的字符串,左闭右开,结果为:llo
let str2 = str.slice(2,5)
split分割(字符串)。
var date1 = "2017-08-12";
var date1Str = date1.split("-");//['2017','08','12']
❗for in和for of区别
for in(遍历对象)遍历的是对象的属性名,数组的键名(key)
for of(ES6 遍历数组)遍历的是数组的值(value)
❗怎么遍历多层嵌套的数组?
❗2)this指向
详解 this是函数的内置对象,所以this只能出现在函数里。
- 【默认绑定】在普通function函数调用时,this指向全局对象window(严格模式下指向undefined);
- 【隐式绑定】在对象中的方法调用时,this指向该方法所属的对象;
- 【显示绑定】
- call,apply,bind显示绑定后,this指向绑定的对象;
- 内置函数
- 在事件绑定的方法时,this指向绑定事件的DOM对象;
- setTimeout,this指向的是window
- 【new绑定】在new构造函数调用时,this指向实例对象;
- 箭头函数中的this会向外层作用域中一层一层的查找直到有this的定义;
优先级:new绑定 > 显示绑定> 隐式绑定 > 默认绑定
❗call、apply、bind有什么区别?
Fn.call(obj, 'arg1', 'arg2', 'arg3', '...')
Fn.apply(obj, ['arg1', 'arg2', 'arg3', '...'])
Fn.bind(obj, ['arg1', 'arg2', 'arg3', '...'])
相同:
- 都是用来改变函数的this指向;
- 第一个参数都是this要指向的对象;
不同点:
- 传参不同。apply和call传入的参数列表形式不同。apply接收arguments,call接收参数列表
- 执行机制不同。call和apply会立即执行函数,bind执行后不会立即调用原函数,而是返回一个新函数,bind需要调用它才会被执行 。
❗js中有哪些事件
1)点击事件:
onclick:单击事件
ondblclick:双击事件
2)焦点事件
onblur:失去焦点
onfocus:元素获得焦点。
3)加载事件:
onload:一张页面或一幅图像完成加载。
4)鼠标事件:
onmousedown 鼠标按钮被按下。
onmouseup 鼠标按键被松开。
onmousemove 鼠标被移动。
onmouseover 鼠标移到某元素之上。
onmouseout 鼠标从某元素移开。
5)键盘事件:
onkeydown 某个键盘按键被按下。
onkeyup 某个键盘按键被松开。
onkeypress 某个键盘按键被按下并松开。
6)选择和改变事件:
onchange 域的内容被改变。
onselect 文本被选中。
7)表单事件:
onsubmit 确认按钮被点击。
onreset 重置按钮被点击。
❗js里有变量提升的问题?怎么解决这个问题?
变量提升的问题可以使用let或者const定义变量
js获取一个对象上所有的key有哪些方式
Object.keys( )不会走原型链,而for in会走原型链
- for in
let obj = {
name: '王大锤',
age: '18',
weight: '70kg'
}
for(let key in obj) {
console.log(key); // name age weight
console.log(obj[key]); // 王大锤 18 40kg
}
- Object.keys
let colors = {
color1: 'pink',
color2: 'red'
};
let myColors = Object.keys(colors);
console.log(myColors); // ["color1", "color2"]
js怎样添加、移除、移动、复制、创建和查找节点?
js操作DOM的常用API:
创建:
document.createElement(“p”); 创建新的<p>
元素
document.createTextNode() 创建文本节点
添加、移除、替换、之前插入、之后插入:
appendChild() 添加/追加
removeChild() 移除
replaceChild() 替换
insertBefore() 之前插入
insertAfter() 之后插入
cloneNode() 复制
查找:
document.getElementById:根据ID查找元素
document.getElementsByClassName:根据类名查找元素
document.getElementsByTagName:根据标签查找元素
document.querySelector
document.querySelectorAll
其他:
setAttribute 添加一些属性
innerHTML 获得html内容
js中的==
和===
有什么区别?
= = 只要等号两边的值相等,就会返回true,在判断的时候会自动进行类型转换。
= = = 表示全等,需要值和类型完全相等。
js中哪些数据在if判断时是false
0、false、null、undefined、“”、NaN 判断为false
❗什么是回调函数
当一个函数做另一个函数的参数时,这个函数就叫回调函数。
作用域和作用域链
作用域[[scope]]:
在一定的空间内可以对数据进行操作,这个空间就是作用域,有全局作用域和局部作用域(函数作用域和块级作用域)
全局作用域:任何地方都能访问到这个变量;
局部作用域:
①函数作用域是只有在函数内部可以访问到这个变量,只有在函数执行的时候存在,执行完就销毁;
②es6新增的let const用来创建块级作用域,块级作用域由{}包括,if语句和for语句里面的{}也属于块级作用域.
作用域链:
查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。
比如函数A内部定义了一个函数B,然后这个函数B就可以访问函数A里面的变量和方法,函数B会先在自己的作用域中查找变量,如果找不到就向外层作用域去查找,这种一层一层向上依赖的关系就构成了作用域链。
(从作用域链的顶端依次向下查找)
阮一峰:子对象会一级一级地向上寻找所有父对象的变量
//如何从外部读取局部变量?在函数的内部,再定义一个函数。
function f1(){
var n = 999;
function f2(){
alert(n); //999
}
}
//函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的
JS对象/类
创建对象有几种方法
- 通过对象字面量
var obj = {}
- 通过构造函数
function Person(){}; var obj = new Person()
- Object.create()
var person = {}; var obj = Object.create(person)
JS库
同步与异步的区别
同步:同步是指一个进程在执行某个请求的时候,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,直到收到返回信息才继续执行下去。
异步:异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有信息返回的时候会通知进程进行处理,这样就可以提高执行的效率了。
❗ajax同步和异步的区别
ajax中根据async的值不同分为同步(async = false)和异步(async = true)两种执行方式。
async默认值为false是同步。同步请求即是当前发出请求后,浏览器什么都不能做,必须得等到请求完成返回数据之后,才会执行后续的代码。
async默认值为true是异步。异步请求就当发出请求的同时,浏览器可以继续做任何事,Ajax发送请求并不会影响页面的加载与用户的操作。
❗ajax的实现?
$.ajax({
url: "test.json", //json文件位置
type: "GET", //请求方式为get
dataType: "json", //返回数据格式为json
success: function(data) { //请求成功完成后要执行的方法
//each循环 使用$.each方法遍历返回的数据date
$.each(data.first, function(i, item) {
var str = '<div>姓名:' + item.name + '昵称:' + item.nick + '</div>';
document.write(str);
})
}
})
❗jQuery有什么特点?
- 链式编程/链式语法(即对发生在同一个JQuery对象上的一组动作,可以直接通过…连写无需要重复获取对象。更加简洁优雅)
- CSS选择器($(“.nav”)元素/class/id/过滤选择器等)
- 事件处理、动画设计和Ajax交互(事件处理:onload/click/mouseenter/blur等;动画:slideDown/slideUp,hide/show,fadeIn/fadeOut等)
- DOM操作的封装(节点:append/remove/clone/parent/find/next等)
- 插件扩展机制和丰富的插件(第三方插件:树形菜单、日期控件、图片切换插件等)
- 兼容各种主流浏览器
- 轻量级的js框架
❗jQuery怎么获取DOM元素
通过jQuery选择器$,元素选择器,ID选择器,类选择器来查找元素
❗jQuery里面要扩展插件一般可以怎么做?
jQuery里面有一个API的,比如想写一个类似于Vue那种指令的东西
第一种:给jQuery类本身添加方法$.extend()
$.extend({
foo:function(){
alert("foo");
},
bar:function(){
alert("bar");
}
})
//调用方法
$.foo();
$.bar();
第二种:给jQuery对象添加方法$.fn.extend()
$.fn.foo = function(){
alert("hello jquery");
}
$('#myF').foo()
jQuery.extend()
是为类添加类方法(静态方法),需要通过jQuery类来调用(或直接$.XXX
调用);
jQuery.fn.extend()
是为jQuery类添加成员函数(实例方法),所有jQuery实例都可以直接调用(需要使用$().XXX
调用)
❗jQuery绑定事件是怎么绑定的?
比如说有bind,leve怎么绑定的,你就说on事件注册是怎么注册吧,on事件里面总共有3个参数分别是什么
第一种:$(“选择器”).事件名称(匿名函数)
//这里的button为元素选择器,click为鼠标点击事件,mouseenter为鼠标聚焦事件,mouseleave为鼠标离焦事件
$("button").click(function(){
//函数内容
})
第二种:$(“选择器”).bind({“事件名称”:匿名函数})
//button为元素选择器,bind的中文意思为‘绑定’
$("button").bind({"click":function(){
//函数内容
}})
第三种:
两个形参:$(“选择器”).on(“事件名称”,匿名函数)
三个形参:$(“父节点选择器”).on(“事件名称”,“孩子节点,即要绑定的元素”,匿名函数)
$("button").on("click",function(){
//函数内容
})
$("ul").on("click","li",function(){
$(this).css("color","blue"); //this表明当前点中的对象,此语句表明,当点击li标签时候,将该li标签颜色变为blue
})
第四种:$(“选择器”).live(“事件名称”, fn)
$("button").live({"click", function(){
//函数内容
}})
第五种:$(“父节点选择器”).delegate(“孩子节点,即要绑定的元素”,“事件名称”,匿名函数)
$("ul").delegate("li","click",function(){
$(this).css("color","blue");
})
❗jQuery里面设置样式怎么设置
.css('color': '#fff')
❗jQuery怎么判断div有没有显示或隐藏
❗form表单提交数据有几种方式?
1、submit提交
<!-- 如果点击提交,表单数据会被发送到名为demo_form.asp的页面,如果没有action属性,表单数据会被发送到当前页面的浏览器地址栏中显示 -->
<form action="demo_form.asp">
First name:<input type="text" name="firstname">
<input type="submit" value="Submit">
</form>
2、ajax提交
❗ECharts你有了解吗?
使用:
①实例化对象init;②指定配置和数据;③配置项和数据给我们的实例化对象。
回答:我做一个折线图,改一下上面的label,改变颜色啦这些
【Git】
Git怎么使用?
Git常用的是以下 6 个命令:git clone、git push、git add、git commit、git checkout、git pull
创建仓库命令:
git init
初始化仓库
git clone 粘贴仓库地址
拷贝一份远程仓库,也就是下载一个项目
提交与修改:
git add .
添加文件到暂存区
git status
查看仓库当前的状态,显示有变更的文件
git diff
比较文件的不同,即暂存区和工作区的差异
git commit
提交暂存区到本地仓库
git reset
回退版本
git rm
删除工作区文件
git mv
移动或重命名工作区文件
提交日志:
git log
查看历史提交记录
git blame <file>
以列表形式查看指定文件的历史修改记录
远程操作:
git remote
远程仓库操作
git fetch
从远程获取代码库
git pull 粘贴仓库地址
下载远程代码并合并
git push
上传远程代码并合并
分支管理:
git branch (branchname)
创建分支
git checkout (branchname)
切换分支
git merge
合并分支
git branch -d (branchname)
删除分支
git冲突怎么解决
在文件中手动去修改它。用git add
和git commit
再提交一次
❗git如果你commit了一个信息写错了,你怎么进行修改?
步骤1. 输入git commit --amend
命令
随后,进入vim命令窗口
步骤2. 按i
,在#的最上方删掉错误的描述,然后重新输入注释。
步骤3. 按 Esc
按钮退出编辑模式,按 :wq
键,保存并退出即可。