js小知识点(二)

263 阅读6分钟

1. 获取url传递的参数

方法一

/**
 * @description 获取查询字段
 * @param {string} searchKey 需要获取的查询 key
 * @return {string | null} 返回查询结果
 */
export function getQueryString(searchKey: string : (string | null) ) {
  // 正则匹配
  let reg = new RegExp(`(^|&)${searchKey}=([^&]*)(&|$)`, 'i')
  let r = window.location.search.substr(1).match(reg)
  return r !== null ? decodeURI(r[2]) : null

}

方法二

export function getQueryString(searchKey: string) {
  const urlSearch = location.search

  if (!urlSearch) {
    return ''
  }
  // 移除url中的问号
  const queryString = urlSearch.slice(1) 
  // 将所有参数转化为数组
  const queryArray  = queryString.split('&')
  // 将参数转化为二维数组,如[['name','fruit'],['language', 'zh-CN']]
  const queryMap    = queryArray.map( (item: string) => item.split('=') )
  // 获取参数的value
  const [ result ] = queryMap.filter( ([key, _value]: string[]) => key === searchKey ).map( ([_key, value]: string[]) => value )

  return (result || '').replace(/[ +]/g, '%20').replace(/(%[a-f0-9]{2})+/ig, match => decodeURIComponent(match) )
}

2. 变量提升

var a = 2
function a() {
    a = 3
}
a() // Uncaught TypeError: a is not a function
alert(a)

实际运行顺序

var a
function a() {
    a = 3
}
a = 2
console.log(a) // 2

3. 异步执行顺序

参考文档:www.ruanyifeng.com/blog/2014/1…

3.1 宏任务和微任务的执行顺序

// 宏任务队列:setTimeout
// 微任务队列:Promise
// 异步宏任务
setTimeout(() => { 
  console.log('timeout')
}, 0)

// 异步微任务
const promise = new Promise((resolve, reject) => {
// 这里面的两个console.log方法是同步方法,因此先执行
  console.log('promise init')
  resolve(1) // 触发then微任务
  console.log('promise end')
})
promise.then((res) => {
  console.log('promise result', res)
})
// 执行结果
1. promise init
2. promise end
3. promise result 1
4. timeout

3.2 宏任务微任务交错执行

在代码执行的过程中,将宏任务和微任务放入相应的队列中。

只要见到setTimeout就会被塞到宏任务队列中,然后按塞入的顺序进行执行。

// 1. 此setTimeout先进入宏任务,但不执行
setTimeout(() => {
  console.log('timeout1')
  // 微任务先执行
  Promise.resolve().then(() => {
    console.log('promise1')
  })
}, 0)
//  最先执行微任务
Promise.resolve().then(() => {
  console.log('promise2')
  // 2. 这个setTimeout,在执行文promise微任务后,再将这个setTimeout放入宏任务。因此这个宏任务比上一个setTimeout后执行。
  setTimeout(() => {
    console.log('timeout2')
  }, 0);
})
// 执行结果
1. promise2
2. timeout1
3. promise1
4. timeout2

3.3 async await 拆解

async function fn() {
    return await 1234
    // 相当于返回如下代码,代码的执行结果相同,也就是说async会被包裹成Promise.resolve返回。
    return Promise.resolve(1234)
}
fn().then(res => console.log(res))

async实际上是返回了一个promise

3.4 async thenable

返回一个包含then方法函数

async function fn() {
    return await {
        then(resolve) {
            resolve(1234)
        }
    }
}
fn().then(res => console.log(res))

async function fn() {
    // promise规范:当return返回一个对象或function时,并且存在一个then方法,就会当成promise处理,
    return ({
        then(resolve) {
            resolve(1234)
            // 如果resolve的也是then,则将会递归,如下
            resolve({
                then(r) {
                // 遇到thenable会递归使用promise.then,调用,直到resolve返回值是一个基础类型
                    r(1)
                }
            })
        }
    })
}
fn().then(res => console.log(res))

3.5 使用async await顺序判断

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')

}
async function async2() {
  console.log('async2')
}

async1()
console.log('script')
// 执行结果
1. async1 start
2. async2
3. script
4. async1 end

或 将async转换成我们熟悉的promise

async function async1() {
// 同步方法
 console.log('async1 start')
  new Promise(resolve => {
    // 同步方法
    console.log('async2')
    resolve()
    // 异步方法
  }).then(res => console.log('async end'))

}

async1()
// 同步方法
console.log('script')
// 执行结果
1. async1 start
2. async2
3. script
4. async1 end

3.6 如果promise没有resolvereject

async function async1() {
  console.log('async1 start')
  await new Promise(resolve => {
    console.log('promise1')
    // 没有执行resolve或reject,就会导致整个promise永远没有完成,await下面的代码就永远不会执行
  })
  console.log('async1 success')
  // return了一个undefined的promise
  return 'async1 end'
}
console.log('script start')
async1().then(res => console.log(res))
console.log('script end')
// 执行结果
1. script start
2. async1 start
3. promise1
4. script end

3.7 再来一个

js代码从上到下执行,先执行同步任务,再执行微任务,最后执行宏任务。

async function async1() {
  console.log('async1 start')
  // 调用的async会返回一个promise,因此await会等一下
  await async2()
  // await执行完,才会继续执行,先进入异步微任务,先执行
  console.log('async1 end')
}
// async会返回一个promise,因此await会等一下
async function async2() {
  console.log('async2')
}
console.log('scrpit start')
setTimeout(() => {
  console.log('setTimeout')
}, 0)
async1()
new Promise(function(resolve) {
// 同步执行
  console.log('promise1')
  resolve()
}).then(function() {
  console.log('promise2')
}).then(function() {
  console.log('promise3')
}).then(function() {
  console.log('promise4')
}).then(function() {
  console.log('promise5')
})
console.log('scrpit end')
// 执行结果
1. scrpit start
2. async1 start
3. async2
4. promise1
5. scrpit end // 第一轮执行完成
6. async1 end
7. promise2
8. promise3
9. promise4
10. promise5
11. setTimeout

3.8 最后一个

async function async1() {
  console.log('async1 start')
  return new Promise(resolve => {
    resolve(async2())
    // resolve执行完成后,抛出一个then的微任务,塞到队里中
  }).then(() => {
    console.log('async1 end')
  })
}
function async2() {
  console.log('async2')
}
setTimeout(() => {
  console.log('setTimeout')
}, 0)
async1()
new Promise(function(resolve) {
  console.log('promise')
  resolve()
}).then(function() {
  console.log('promise2')
}).then(function() {
  console.log('promise3')
}).then(function() {
  console.log('promise4')
})
// 执行结果
1. async1 start
2. async2
3. promise
4. async1 end
5. promise2
6. promise3
7. promise4
8. setTimeout

改一下

resolve处理thenable,也会包裹一层promise

async function async1() {
  // 1. 打印async1 start
  console.log('async1 start')
  // 2. 将promise塞入异步队列
  return new Promise(resolve => {
    //4. 执行resolve,执行async2。resolve处理thenable也会再包裹一层promise
    resolve(async2())
  }).then(() => {
    console.log('async1 end')
  })
}
// 6.将async塞入异步队列,自己本身已是一个promise
async function async2() {
  console.log('async2')
}
setTimeout(() => {
  console.log('setTimeout')
}, 0)
async1()
// 3. 将promise塞入异步队列
new Promise(function(resolve) {
  // 5. 打印promise,执行resolve,将下一个then塞入异步队列
  console.log('promise')
  resolve()
  
}).then(function() {
  console.log('promise2')
}).then(function() {
  console.log('promise3')
}).then(function() {
  console.log('promise4')
})
// 执行结果
1. async1 start
2. async2
3. promise
4. promise2
5. promise3
6. sync1 end
7. promise4
8. setTimeout
async function async1() {
  console.log('async1 start')
  return new Promise(resolve => {
    resolve(async2())
  }).then(() => {
    console.log('async1 end')
  })
}
// 去掉async,并包裹成thenable
function async2() {
  console.log('async2')
  return { then(r){r()} }
}
setTimeout(() => {
  console.log('setTimeout')
}, 0)
async1()

new Promise(function(resolve) {
  console.log('promise')
  resolve()
}).then(function() {
  console.log('promise2')
}).then(function() {
  console.log('promise3')
}).then(function() {
  console.log('promise4')
})
// 执行结果
1. async1 start
2. async2
3. promise
4. promise2
5. sync1 end
6. promise3
7. promise4
8. setTimeout

总结:

  1. async本身会返回一个promise
  2. js代码从上到下执行,先执行同步任务,再执行微任务,最后执行宏任务
  3. 遇到async await的时候要想办法转成promise

4. nodejs中的EventLoop

4.1

APPLICATION: 相当于我们的reactvue的程序

4.2 nodejs中的任务队列

宏任务 微任务
setTimeout Promise(async)
setInterval process.nextTick
setImmediate
IO

4.3 nodejs中的任务比较

1. 比较setImmediate和setTimeout的执行顺序

2. 理解process.nextTick

3. 比较process.nextTick和setImmediate

5. 基础

console.log(a) // 1
console.log(typeof fruit(a)) // Uncaught TypeError: fruit is not a function
var flag = true
if (flag) {
  var a = 1
}
if (flag) {
  function fruit(a) {
    fruit = a
    console.log("fruit1")
  }
} else {
  function fruit(a) {
    fruit = a
    console.log('fruit2')
  }
}
function fn() {
  console.log(this.length)
}
var fruit = {
  length: 5,
  method: function() {
    "use strict"
    fn()
    arguments[0]()
  }
}
const result = fruit.method.bind(null)
result(fn, 1)
// 打印结果
0
2

3.如下,请问变量a会被GC回收吗

function test() {
  var a = 'fruit'
  return function() {
    eval('')
  }
}
test()()

会,因为a是局部变量

  1. 写出以下代码输出值,并解释原因
Object.prototype.a = 'a'
Function.prototype.a = 'a1'
function Person() {}
var fruit = new Person()
console.log(Person.a)
console.log(fruit.a)
console.log(1..a)
console.log(fruit.a)
console.log(fruit.__proto__.__proto__.constructor.constructor.constructor)

Object.prototypeFuntion.prototype打印的内容差距很大原因是什么

-{
  var a = 1
  const b = 2
  function test(){}
  test = 3
  console.log(typeof test)
}
console.log(a)
console.log(typeof test)
console.log(b)
  1. ES6的元编程
  2. 解释下babel编译后的async原理
let a = 0
let fruit = async () => {
  a = a + await 10
  console.log(a)
}
fruit()
console.log(++a)
async function async1() {
  console.log(1)
  await async2()
  console.log(3)
}

async function async2() {
  console.log(2)
}
async1()
console.log(4)
$('#test').click(function(argument) {
  console.log(1)
})
setTimeout(function() {
  console.log(2)
}, 0)
while(true) {
  console.log(Math.random())
}
const pro = new Promise((resolve, reject) => {
  const innerpro = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 0)
    console.log(2)
    resolve(3)
  })
  innerpro.then(res => console.log(res))
  resolve(4)
  console.log('fruit')
})
pro.then(res => console.log(res))
console.log('end')

var s = []
var arr = s
for (var i = 0; i < 3; i++) {
  var pusher = {
    value: 'item' + 1
  },tmp

  if (i !== 2) {
    tmp = []
    pusher.chuldren = tmp
  }
  arr.push(pusher)
  arr = tmp
}
console.log(s[0])