1. 防抖和节流?滚动用防抖还是节流(都可以吧)
2. call和apply的区别?怎么实现call?
就参数不一样,call是参数序列,apply是数组
call实现
Function.prototype.call2 = function(obj,...arg) {
console.log('指向对象:' , obj , '函数:', this , '函数参数:', arg)
//判断是否为空,否则指向全局
if(obj == null){
obj = window
}
// 采用方法就是在指向目标对象中加入一个函数,并执行,然后删除,这样函数内的this指向就是目标对像了
obj.fn = this;
var res = obj.fn(...arg);
delete obj.fn;
//添加返回值,就是返回函数执行结果
return res
}
3. 闭包的使用场景和缺点
闭包就是:函数内部会返回一个函数,使得在函数外部调用函数内部的变量,这个返回的函数就叫做闭包。
我的理解是,闭包就是能够读取其他函数内部变量的函数。
闭包的缺点:比普通函数占用更多的内存。可以通过不使用了就释放解决这个问题。
滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
使用闭包的好处是不会污染全局环境
闭包可以用在许多地方。它的最大用处有两个,
1、一个是前面提到的可以读取函数内部的变量,
2、另一个就是让这些变量的值始终保持在内存中。
闭包的常用场景:
一是函数作为返回值:
防抖和节流函数、立即执行函数正确获得索引值(for+setTimeout)、函数柯里化
二是函数作为参数来传递。
不适用于返回闭包的函数是个特别大的函数,很多高级应用都要依靠闭包实现.
4. 实现数组去重
5. 箭头函数
优点:
相当于匿名函数,简化了函数的定义
使用注意事项:
1、箭头函数是匿名函数,不能作为构造函数,不能使用new。
2、箭头函数的this
会捕获其所在的上下文的this值,作为自己的this值。
this指向当前函数的上上个函数。
var obj = {
a: 10,
b: () =>{
console.log(this.a, this); // undefined, Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
},
c: function() {
return ()=>{
// 这里的this是c所在的上下文,所以有a值
console.log(this.a); //10
}
}
}
obj.b();
obj.c()();
3、 不能用arguments
在使用箭头函数时,arguments 指向的对象并不是当前函数所属的argments,而是上级函数的arguments,所以需要将箭头函数转为function。会报错;Uncaught ReferenceError: arguments is not defined
// 获取参数可以使用扩展运算符
let C = (...c) => {
console.log(c);
}
C(3,82,32,11323); // [3, 82, 32, 11323]
4、箭头函数通过 call() 或apply() 方法调用一个函数时,对 this 指向 并没有影响。
5、箭头函数没有原型属性
var a = ()=> 1 ;
console.log(a.prototype); // undefined
只有函数才有prototype,对象一般是通过_proto_ 获取prototype。
6、箭头函数不能当做Generator函数,不能使用yield关键字
6. js继承?
https://www.cnblogs.com/Grace-zyy/p/8206002.html
7. 原生js什么时候知道页面加载完成
window.οnlοad=function(){
//somecode
}
8、webworkers
当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。
web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。
您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。
http://www.ruanyifeng.com/blog/2018/07/web-worker.html
9、for 、forEach、for in 、 for of 、while区别
for i : 这种写法比较麻烦
forEach :没有办法终止循环,用break报错,return的作用在这里跟continue一样
for...in循环主要是为遍历对象而设计的,它还会遍历手动添加的、原型上的键(enumerable:true)。
(可以使用Object.propertyIsEnumerable(属性名)是不是存在于对象上的键,而不是原型上的)
所以遍历键的方法:
1、for...in
2、Object.keys(myObject)不会遍历原型上的键, 同样属性要满足enumerable:true)
3、Object.getOwnPropertyNames(myObject), 所有属性,无论是否可枚举
hasOwnProperty 和 in的区别:
person1.hasOwnProperty("name")只在属性存在于实例中时才会返回true
"name" in person1 除了实例还回去原型上找
for...in 如果用于数组要注意:
1、键名是字符串类型的'1','2'...
2、而且除了所有数值索引,还会包括所有的枚举类型(甚至原型上的)
for...of 是用于iterator接口,用for...of循环遍历它的成员。
iterator :(set、map、数组、generator、字符串)
10、for of跟promise和async await 有啥区别?for of 能不能放异步操作?
(我觉得是两类东西)大概共同点就是能够处理异步函数
能,我说generator函数返回的是一个Iterator,通过next执行yield调用异步,
所以for of应该也可以。
实际上在阮一峰es6中就说了,通过for of执行generator
function* foo() {
yield 1; yield 2; yield 3; yield 4; yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
11、Object.defineProperty() 除了get和set,还有什么?
这个是访问描述符,还有数据描述符(value、writable、configurable、enumerable)
12、图片base64编码:
利用canvas里面的toDataUrl,现在一般UI框架上传图片都是编码好了的,比如vantUI
13、promise的all和race
Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
(1)、p1/p2/p3都是fullfilled时,p的状态才变成fulfilled,p1/p2/p3的返回值组成一个数组,传递给p的回调函数
(2)、只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
那个率先改变的 Promise 实例的返回值,就传递给p的回调函。
14、异步怎么捕获异常
一般捕获异常都是
try{
throw new Error('fail');
... //异常的抛出
}catch(e){
... //异常的捕获与处理
}finally{
... //结束处理
}
但是try模块里面是通过异步操作抛出的异常,异常就不能正常捕获到,但可以在异步代码里面加
try...catch
setTimeout(()=>{
try{
throw new Error('fail');
}catch (e){
console.log(e);
}
},1000);
或者通过浏览器错误监听:
window.onerror = function(x){alert(x)}
setTimeout(() => {
throw new Error('fail');
},1000)
比如promise的异常捕获是:
1、通过 .then((v)=>{} , (error) => { //错误信息处理 }}) , reject方法的作用,等同于抛出错误。
2、.then(null, rejection)的别名:Promise.prototype.catch() :
promise.then(function(data) {
//cb
// success
}).catch(function(err) {
// error——这个可以捕获到then里面的错误
});
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
async await 捕获错误
1、使用catch方法
2、在异步代码外面包一层try catch
3、window.onerror全局监听
15、map和Object区别
1、object的键值只能是string或者symbol,map可以是所有数据类型(基本数据类型和对象函数等等) 2、map中键值对的顺序是依照写入的顺序,object是无序的,一定要说有什么规律就是数字键在前,字符键在后
3、map中有size方法得到键值对数量,object不行,只能遍历计数
4、map有 Iterator 接口,可以使用for…of遍历成员,object没有
16、promise .then的链式写法(阮一峰)
17、var 和let的区别?const初始不赋值?
1、变量只在let命令所在的代码块内有效。这个作用可以替代IIFE立即执行函数
{
// 这个a 和外面的a互不影响,只存在这个块作用域
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
2、let不能重复定义变量,var可以
3、let不能变量提升,所以声明要在定义之前
const a :报错,const一定要初始化
const 赋值之后改变赋值怎么办?
分情况:
如果赋值是基本数据类型,之后再赋值会报错
如果是引用类型,像数组,对象等就可以改变内部的成员,因为const只要引用地址没变,不管堆上面的数据变化
18、this指向,bind
1、改变this指向
bind、call、apply、new(其实也是调用了apply)
2、bind之后调用call,能不能改变指向
不能
function func(){
console.log(this.a,this.b,arguments)
}
func.bind({a:1,b:2},1).call({a:3,b:4},9)
打印 1,2 Arguments(2) [1, 9, callee: ƒ, Symbol(Symbol.iterator): ƒ]
bind 之后就不能改变
3、最顶层的function和箭头函数中的this指向
最顶层的this指向window
箭头函数的this默认指向在定义它时所处的对象(宿主对象)
19、判断对象是数组的方法。
4种,typeof得到的是object,不可以
var arr = []
isArray: Array.isArray(arr) // true
instanceof: arr instanceof Array // true
constuctor: arr.constructor == Array // true
toString: Object.prototype.toString.call(arr) //"[object Array]"
20、深拷贝和浅拷贝
对象:
https://www.jb51.net/article/160063.htm
浅拷贝
obj1 = Object.assign({}, obj0)
深拷贝
1、通过递归
2、JSON.stringify序列化,再JSON.parse反序列化。这个方法有局限:
以下属性 --> 拷贝之后
属性中有时间对象 --> 字符串
regExp/Error对象 --> 空对象
undefined --> 丢失
NaN、Infinity和-Infinity --> null
JSON.stringify()只能序列化对象的可枚举的自有属性
数组:
浅拷贝:
arrCopy = [...array]
数组其他拷贝的方法:map、for、while、filter、reduce、slice、concat等等,都是浅拷贝
深拷贝:
nums= [[1], [2]];
numsCopy = JSON.parse(
JSON.stringify(nums)
)