javascript
模拟实现
- 根据async/await与generator的关系模拟实现
function myAsync(genF){
return new Promise(function(resolve, reject) { // async返回的是一个promise对象
const gen = genF(); // 拿到这个遍历器
function step(nextF) {
let next;
try {
next = nextF(); // 执行传入的回调函数获取{value:xx,done:xx}
} catch(e) {// 出错就直接抛出,抛出的错误就是当前出错的promise对象
return reject(e);
}
if(next.done) {//完成就直接resolve
// resolve的参数如果是promise对象,会继续等待promise对象返回,再resolve返回的结果
return resolve(next.value);
}
// 直接resolve当前的指针指向的对象然后继续执行下一个
Promise.resolve(next.value).then((res)=> {
step(()=> gen.next(res)); // 返回上一个promise对象的返回值
}).catch((e)=>{
step(()=> gen.throw(e)); // 错误就抛出
})
}
// 初始化调用这个遍历器
step(()=> gen.next());
});
}
// 测试代码
myAsync(function* () {
const a = yield Promise.resolve(1)
const b = yield new Promise((res, rej) => {
setTimeout(() => {
res(2)
}, 2000)
})
const c = yield Promise.resolve(3)
console.log(a, b, c);
try {
const d = yield Promise.reject(4)
} catch (error) {
console.log(error);
}
return [a, b, c]
}).then(console.log)
// 输出
// 1 2 3
// 4
// [1,2,3]
理论
- 考察隐式类型转换,下面if为真的有哪些
if([]) // [] 对象为true // 只有'', 0, false, undefined, null, NaN 在转换为布尔值是变成false
if({}) // {} 对象为true
if([]==false) // 转换后比较为true // 类型不同的值进行比较时先转为同类型再比较,对象先调用valueOf取值,如果仍是对象再取toString的值,再将 字符串转换成逻辑值,因此空数组转为字符串为'',所以逻辑值为false,比较结果为true
if({}==false) //转换后比较为false // {} 依次调用valueOf和toString,得到的字符串为[object Object],转换为布尔值为true,比较的结果为false
- this指向考察
function a(){
this.b = 3
}
a()
console.log(b) // 3,a中的this为window,影响了全局的b
var b = 5
console.log(b) // 5, 前一句代码修改了全局的b
var c = new a()
console.log(b) // 5, 前一句代码创建a的实例时,对b的修改影响的是新创建的对象
c.prototype.b = 4
c.prototype.c = 5
console.log(c.b) // 3,从当前对象到原型链末端依次查找b,取距离最近的,即自身的b
console.log(c.c) // 5,当前对象没有属性c,因此取值为原型上的c
console.log(b) // 5, 始终没有代码对全局的b再次进行修改
- 什么是动态作用域?什么是静态作用域?
- 动态作用域:函数的作用域需要在运行过程中才能动态确定
- 静态作用域:函数的作用域在定义时就已经确定
- js是动态还是静态作用域
- 静态作用域
- 作用域考察
例1
var scope = "global scope";
function checkscope() {
var scope = "local scope";
function f() {
return scope;
}
return f();
}
console.log(checkscope()); // local scope
例2
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()(); // local scope
例3
for(var i = 0;i<2;i++){
setTimeout(()=>{
for(var j = 0;j<3;j++){
setTimeout(()=>{
console.log(i*j)
},0)
}
},0)
}
// 输出结果是多少?为什么
/**
* 答:输出结果是666666,因为setTimeout是异步代码,外层的setTimeout要等外部的for循环完成才会执行,执行时i = 2,
* 内部的setTimeout要等内部的for循环完成才会执行,执行时j = 3,因为var声明的变量没有块级作用域,ij全都定义在外部,内层定时器回调函数引用的变量也都是相同的,因此全都打印的2*3,即6
**/
// var 变为 let 结果又是多少?为什么
/**
* 答:输出结果是000012,同样内外层的setTimeout的执行需要等到各自的for执行完成,但是内层定时器回调引用的变量是各自的,原因如下:
* let声明的变量拥有块级作用域,在for循环中这个块级作用域的范围就存在于for右边的一对小括号里面,因此每次循环的时候都会创建一个不同的变量,
* 并且将之前的变量值赋值过去。而由于内层定时器回调函数的引用,使得这些块级作用域的变量生存期被延长了,存在于对应回调[[scoped]]的block对象中
*/
dom相关
- 如何获取一个dom对象
document.getElementById(id)
document.getElementsByClassName(className)
document.getElementsByName(name)
document.getElementsByTagName(tagName)
document.querySelector(selector)
document.querySelectorAll(selector)
- 如何获取指定dom的指定属性
// 获取一般属性
.getAttribute()
// 获取自定义属性
.dataset
- 如何获取指定dom的指定样式
.style[property]
- 如何获取指定dom的生效样式
getComputedStyle(element)
// 老版ie
element.currentStyle