1.ES6语法
- let const 箭头函数 Promise 展开操作符 默认参数 import export
2.Promise、Promise.all、Promise.race 分别怎么用
- Promise 用法
function fn(){
return new Promise((resolve, reject) => {
成功时调用 resolve(数据)
失败时调用 reject(错误)
})
}
fn().then(success, fail).then(success1, fail1)
- Promise.all 用法
Promise.all([promise1, promise2]).then(success1, fail1)
只有 promise1 和 promise2 都成功才会调用success1
- Promise.race用法
Promise.race([promise1, promise2]).then(success1, fail1)
promise1 和 promise2 只要有一个成功就会调用success1
3. 手写函数防抖和函数节流
- 防抖
一段时间会等,然后带着一起做了
function delays (fn, delay){
let timerId = null
return function (){
const context = this
if(timeId){
window.clearTimeout(timeId)
}
timeId = setTimeout(() => {
fn.apply(context, arguments)
timeId = null
}, delay)
}
}
const delayed = delays(() => {console.log("lalalla")})
delayed()
delayed()
- 节流
一段时间执行一次后,就不执行第二次了
function throttle(fn, delay){
let canUse = true
retuen function() {
function() {
if(canUse){
fn.apply(this,arguments)
canUse = false
setTimeout(() => {
canUse = true
}, delay)
}
}
}
}
const throttled = throttle(() => {console.log("lskllsl")})
throttled()
throttled()
4.手写AJAX
var request = new XMLHttpRequest()
request.open('GET', 'a/b/c?name=mm', true)
request.onreadystatechange = function () {
if(request.readyState === 4 && request.status === 200) {
console.log(request.responseText)
}
}
request.send() //post请求body放在这里面
5.this问题
this 就是你 call 一个函数时,传入的第一个参数(this 就是 call 的第一个参数 fn.call(this, n1,n2))
- fn()
this => window/global - obj.fn()
this => obj - fn.call(xx, arguments)
this => xx - fn.apply(xx)
this => xx - fn.bind(xx)
this => xx - new Fn()
this => 新的对象 - fn = () => {}
this => 外面的this
this
6. 闭包
函数调用了函数之外的变量
!function () {
//两个闭包 函数+变量
var lives = 50
window.addlive = function () {
lives += 1
}
window.dielive = function () {
lives -=1
}
}()
- 内存泄漏:你用不到(访问不到)的变量,依然占据着内存空间,不能被再次利用起来。闭包不会造成内存泄漏
7. 立即执行函数
立即执行函数:声明一个匿名函数,马上调用这个匿名函数
- 写法
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
- 立即执行函数作用
立即执行函数
创建一个独立的作用域
这个作用域里面的变量,外面访问不到(避免变量污染)
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
liList[i].onclick = function(){
alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5
}
}
---------用立即执行函数给每个 li 创造一个独立作用域,在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变--------
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
!function(ii){
liList[ii].onclick = function(){
alert(ii) // 0、1、2、3、4、5
}
}(i)
}
8.JSONP、 CORS 、跨域?
-
同源策略:浏览器处于安全方面的考虑,只允许与同域下的接口交互
-
同域:
1.同协议: 如都是http或都是https
2.同域名: 如都是baidu.com/a和baidu.com/b (用户打开baidu.com/a,当前页面下的js向baidu.com/b的接口发ajax请求,浏览器是允许的。但假如想jianshu.com/b发ajax请求就会被浏览器阻止,因为存在跨域调用)
3. 同端口: 如都是80端口 -
JSONP(创建动态JavaScript)
通过 script 标签加载数据的方式去获取数据当做 JS 代码来执行。
提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP 需要对应接口的后端的配合才能实现。
<script>
function yyy(ret){
console.log(ret);
}
</script>
<script src="api.xxx.com/weather?callbackName=yyy"></script>
--------------------------------------------------------------------------------------------------
这个请求到达后端后,后端会去解析callback这个参数获取到字符串yyy,在发送数据做如下处理:
之前后端返回数据: {"city": "hangzhou", "weather": "晴天"}
现在后端返回数据: yyy({"city": "hangzhou", "weather": "晴天"})
前端script标签在加载数据后会把 「yyy({"city": "hangzhou", "weather": "晴天"})」做为 js 来执行,
这实际上就是调用yyy这个函数,同时参数是 {"city": "hangzhou", "weather": "晴天"}。
- 突破同源策略 === 跨域
- CORS跨域(加响应头)
response.setHeader('Access-Control-Allow-Origin', 'http://xxx.com:8001')
9. async/await怎么用,如何捕获异常?
- promise
function fn() {
return new Promise ( (resolve, reject) => {
setTimeout(() => {
let n = parseInt(Math.random()*6 + 1) //[0-1)*6+1后取整
resolve(n)
},3000)
})
}
fn() .then(
//成功调用resolve()
(x) => {
console.log(x) //这里的x就是上面的n
},
//失败调用reject()
() => {
console.log(失败)
}
)
- await只能放在async函数里面, await命令后面是一个 Promise 对象,返回该对象的结果
- async可以声明一个异步函数, 返回一个Promise 对象
- 把异步代码写成同步代码。
function fn(params) {
return new Promise ( (resolve, reject) => {
setTimeout(() => {
let n = parseInt(Math.random()*6 + 1) //[0-1)*6+1后取整
if(n>3){
if(params==="大"){
resolve(n)
}else{
reject(n)
}
}else{
if(params==="小"){
resolve(n)
}else{
reject(n)
}
}
},3000)
})
}
async function test() {
try{
let n = await Promise.all([fn("大"), fn("小")])
console.log(n)
}catch(error){ //捕获reject()
console.log(error)
}
}
let result = test ()
console.log(result) //打印出一个Promise
10. 如何实现深拷贝?
- json实现深拷贝
var a = {...}
var b = JSON.parse(JSON.stringify(a))
缺点:JSON 不支持函数、引用、undefined、RegExp、Date……
- 递归拷贝
function clone(object){
var object2
if(! (object instanceof Object) ){
return object
}else if(object instanceof Array){
object2 = []
}else if(object instanceof Function){
object2 = eval(object.toString())
}else if(object instanceof Object){
object2 = {}
}
你也可以把 Array Function Object 都当做 Object 来看待,参考 https://juejin.im/post/587dab348d6d810058d87a0a
for(let key in object){
object2[key] = clone(object[key])
}
return object2
}
11.JS数据类型
- string number bool undefined null object symbol
- object 包括了数组、函数、正则、日期等对象
12. 如何用正则实现 string.trim()
function trim(string){
return string.replace(/^\s+|\s+$/g, ' ')
}
13. 如何实现数组去重?
- 计数排序
var a = [4,2,5,6,3,4,5]
var hashTab = {}
for(let i=0; i<a.length;i++){
if(a[i] in hashTab){
// 什么也不做
}else{
hashTab[ a[i] ] = true
}
}
//hashTab: {4: true, 2: true, 5: true, 6:true, 3: true}
console.log(Object.keys(hashTab)) // ['4','2','5','6','3']
- Set去重
- Set对象允许存储任何类型的唯一值,无论是原始值或者是对象引用
Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组
- Set对象允许存储任何类型的唯一值,无论是原始值或者是对象引用
let a = [4,2,5,6,3,4,5]
let b = new Set(a) //返回Set对象 {4, 2, 5, 5, 4, 3}
//将Set对象转化成数组
Array.from(b) //方法一
[...b] //方法二
- 使用 WeakMap???
14. JS原型
- 举例
var a = [1, 2, 3]
只有0, 1, 2, length 4个key
为什么可以a.push(4) , push是哪来的?
a.__proto__ === Array.prototype
push就是沿着a.__proto__ 找到的,也就是Array.prototype.push
Array.prototype还有很多方法,如join、pop、slice、splice
//join(): 将数组的元素组起一个字符串,console.log(a.join("-")); // 1-2-3
//pop():数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项。
//slice():返回从原数组中指定开始下标到结束下标之间的项组成的新数组,在只有一个参数的情况下, slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数
//splice():(1)指定 2 个参数:要删除的第一项的位置和要删除的项数。例如, splice(0,2)会删除数组中的前两项。(2)提供 3 个参数:起始位置、 0(要删除的项数)和要插入的项。例如:splice(2,0,4,6)会从当前数组的位置 2 开始插入4和6。splice (2,1,4,6)会删除当前数组位置 2 的项,然后再从位置 2 开始插入4和6。
Array.prototype就是a的原型(__proto__)
15. 继承
- 不用class
function Animal() {
this.body = 'body'
}
Animal.prototype.move = function() {}
function Human (name){
Animal.apply(this, arguments)
this.name = name
}
//Human.prototype.__proto__ = Animal.prototype//非法
var f = function () {}
f.prototype = Animal.prototype
Human.prototype = new f()
Human.prototype.useTools = function() {}
var mm = new Human()
- 使用class
class Animal{
constructor() {
this.body = 'body'
},
move() {}
}
class Human extends Animal{
constructor(name){
super()
this.name = name
},
useTools() {}
}
let mm = new Human()
网友评论