1.null/undefined
两者的区别
typeof null === 'object // null是表示为“无”的对象
typeof undefined === 'undefined' // undefined是表示为“无”的原始值
Number(null) === 0
Number(undefined) === NaN
什么时候会出现undefined
// 1. 已声明,未赋值
let o;
console;log(o) // undefined
// 2.对象某个属性不存在
let obj = {};
console.log(obj.a)
// 3.函数调用时少参数
function fn(a,b){
console.log(a,b)
}
fn()
// 4.函数的默认返回值
function fn2(){
}
console.log(fn2())
null 的特点
// 1.手动释放内存
let obj={};
obj = null;
// 2.原型链的顶端
2.ES6-filter
let a = [1,2,3,14,15]
// current 当前值;index 当前值的下标;array a数组对象
let b = a.filter((current, index, array) => {
console.log(current, index, array)
return current > 10
})
console.log(a)
console.log(b)
3.forEach和map(如何终止稍等?)
let arr = ['a','b','c']
// forEach没有返回值
const res = arr.forEach((ele, index, ary) => {
console.log(ele) // a
console.log(index) // 0
console.log(ary) // ['a','b','c']
return ele + '1'
})
console.log(arr) // ['a','b','c']
console.log(res) // undefined
// map 有返回值
const res = arr.map((ele, index, ary) => {
console.log(ele) // a
console.log(index) // 0
console.log(ary) // ['a','b, 'c]
return ele + '1'
})
console.log(arr) // ['a,''b, 'c]
console.log(res) // ['a1','b1, 'c1']
4递归求和1-100
// 1+2+3+4+.....
function fn(a, b) {
const sum = a + b
const c = b + 1
if (c > 100) {
return sum
} else {
return fn(sum, c)
}
}
const res = fn(1, 2)
console.log(res) // 5050
5 var、let、const
// var的特点(不足)
// 1.声明提升
console.log(num) // undefined
var num = 123
// 2.变量覆盖
var a1 = 12
var a1 = 34
console.log(a1) // 34
// 3.没有块级作用域
function fn() {
for(var i = 0; i < 3; i++) {
console.log(i) // 0 1 2
}
console.log(i) // 3
}
fn()
const 定义的是常量,不允许被修改
const 声明之后必须赋值
支持块级作用域
let 声明后可以不赋值,允许被修改,支持块级作用域
6 通过es6的相关知识将下面的值互换
let a = 1;
let b = 2;
[a,b] = [b, a]
console.log(a,b) // 2,1
7 es6数组去重
const ary = [12, 43, 23, 12, 43, 55]
const newAry = [...new Set(ary)]
console.log(newAry) // [12, 43, 23, 55]
8 Promise相关题
// 构造函数是同步执行的
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
// 异步执行的
promise.then(() => {
console.log(3)
})
console.log(4)
// 1243
9 闭包
1 闭包是什么? --- 方法里面返回一个方法
2 为什么会出现?
当函数执行完后,函数内部的局部变量会被回收;为了延长局部变量的生命周期,出现了闭包;也正因为闭包会导致局部变量常驻内存,所以也要慎用闭包。
3 此外,闭包还可以创建私有环境
// 1 闭包是什么? --- 方法里面返回一个方法
function a () {
let a1 = 2;
return function() {
return a1;
}
}
// 2 存在的意思---延长变量的生命周期;创建私有环境;
为什么会出现?:
当函数执行完后,函数内部的局部变量会被回收;为了延长局部变量的生命周期,出现了闭包;也正因为闭包会导致局部变量常驻内存,所以也要慎用闭包。
// 01 延长变量的生命周期:
let a = '小明'; // a是全局变量(会污染局部变量,也不会被垃圾回收机制回收)
function fn1() {
let b = 1;
console.log(a) //'小明'
}
fn1()
console.log(b) // b is not defined 报错
// 改动成闭包
function fn1() {
let b = 1;
return function () {
return b
}
}
const res = fn1()()
console.log(res) // 1
// 02 创建私有环境
Vue中的data() 为什么是一个函数?
data() {
return {}
}
// 回答: 这是一个闭包的设计,vue通过闭包给每个组件设计了一个私有域空间,保证每个组件都有私有的作用域,就不会造成数据之间的相互干扰。
下面就验证了闭包可以实现每个对象都有独立的词法作用域
let make = function() {
let num = 0;
function changeBy(val) {
num += val
}
return {
add: function() {
changeBy(1)
},
reduce: function() {
changeBy(-1)
},
value: function() {
return num
}
}
}
let counter1 = make()
let counter2 = make()
console.log(counter1.value()) // 0
counter1.add()
counter1.add()
console.log(counter1.value()) // 2
counter2.add()
console.log(counter2.value()) // 1
10 防抖与节流
防抖:将多次操作变成一次
<input />
// 防抖函数
function debounce(fn, delay) {
let timer = null
return function(...args) {
if (timer) {
clearTimeout(timer)
timer = null
}
timer = setTimeout(() => {
fn.apply(this, args)
clearTimeout(timer)
timer = null
}, delay)
}
}
const inputEl = document.querySelector('input')
function request (e) {
console.log(this) // <input> 不是window
console.log(e) // InputEvent 不是undefined
}
inputEl.addEventListener('input', debounce(request, 1000))
补充:
(function fun(){
console.log(arguments) // 非数组
// 先变成数组
const ary = Array.prototype.slice.apply(arguments) // [1,2]
// 连接
console.log(ary.concat([3]))//[1,2,3]
})(1,2)
节流:一定时间内只调用一次函数
应用场景:比如手指在盒子上疯狂滑动时,会不停触发事件,但节流让它有节奏慢慢地触发事件
<div class="box"></div>
const boxEl = document.querySelector('.box')
function boxFn(e) {
console.log(e) // touchEvent
console.log(this) // <div class="box"></div>
}
function throttle(fn, delay) {
let timer = null
return function(...args) {
if (timer) return false
timer = setTimeout(() => {
fn.apply(this, args)
clearTimeout(timer)
timer = null
}, delay)
}
}
boxEl.addEventListener('touchmove', throttle(boxFn, 1000))
另一种节流写法:
function throttle(fn, delay) {
let end_time = 0;
return function(...args) {
const current_time = +new Date() // 触发时的时间戳(尤其是第二次)
if(current_time - end_time < delay) return false
fn.apply(this, args)
end_time = +new Date() // 执行结束后的时间
}
}
11 原型链和继承
原型: prototype,是函数所特有的;在函数的原型上挂东西,就是为了实例的继承
原型链: __proto__,是大家都有的;
当实例对象要查找某个属性时,先从当前实例属性去查找,如果找到了就返回,否则就顺着原型链一层层往上找,直到找到null为止。如果没有找到,则报错。