两道比较牛逼的题

接下来,请听第一题:

function Foo(){
	getName = function(){alert(1)};
	return this;
}
Foo.getName = function(){ alert(2) };
Foo.prototype.getName = function(){alert(3)};
var getName = function(){alert(4)};
function getName(){alert(5)};
//写出以下的输出结果。先给出答案
Foo.getName();					//2
getName();						//4
Foo().getName();				//1
getName();						//1
new Foo.getName();				//2
new Foo().getName();			//3
new new Foo().getName();		//3

这题,光是看着就吓银,硬着头皮,干!!
先来试试写出他的AO,这是全局中的

AO:{
	Foo:function(){
		getName = function(){alert(1)};
		return this;
		}
	getName:function(){ alert(4) }
}

执行阶段:

  • 第一个:Foo.getName();

通过Foo创建了一个可以通过类直接调用的静态方法getName,那就执行它弹出2.

  • 第二个:getName();

直接getName函数,弹出4。这里存在变量提升,函数提升的问题,我有三个锦囊妙计,可以看看之前的文章。

  • 第三个:Foo().getName();

即先执行Foo(),函数Foo()返回当前的Foo对象,直接在调用该对象的getName方法,这里考察的是this的指向问题,Foo()直接执行,返回的是window对象,window对象上的getName()方法,会在Foo()执行完后,被其内部的getName = function(){alert(1)};覆盖掉。所以会alert(1).

  • 第四个:getName();

再次调用getName方法,此时getName已经被覆盖掉,所以还是alert(1)

  • 第五个:new Foo.getName();

此处考察的是运算符优先级的问题,看下表在这里插入图片描述
可以看到 . 运算符的优先级大于new运算符,所以相当于new (Foo.getName)(),即将静态方法getName作为构造函数执行,最终alert(“2”);

  • 第六个:new Foo().getName();

也是运算符优先级的问题,new大于(),先new,该构造函数的返回值为this也就是代表当前的对象,相当于实例化了一个foo对象,然后调用该对象的getName方法,没有,怎么办,上原型链查找。所以alert(“3”)。

  • 第七个:new new Foo().getName();

还是运算符优先级的问题
相当于new (new Foo()).getName();也就是将实例化对象的原型上的方法getName当作构造函数,再new,所以alert(“3”);


第二题:

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

async function async2(){
console.log('async2')
}
console.log('script Start')
 
setTimeOut(function(){
	console.log('setTimeOut')
},0);
async1();
new Promise(function(resolve){
	console.log("promise1");
	resolve();
}).then(function(){
	console.log("promise2");
})

console.log("script end");

这道题是不是更惊悚、更刺激…
这道题考察的是对底层运行机制的理解,事件轮询,同步异步,宏任务和微任务。

简单说说async,async会返回一个promise对象,好了完了。
再说说await,await意思是等待,它等待它右侧表达式返回一个结果。而且很重要的一个点,await会让出线程,会阻塞其后续代码的结果。但是不影响其后续代码的计算。等到返回结果后,会阻塞后面的代码先执行async外面的同步代码。

好了,分析分析,真的复杂:
1.先执行主线程上的同步代码。
console.log(“script start”);//打印script start,
2.然后是async1()执行,先打印async1 start,
遇到await async2,跳出当前,找到async2,执行async2函数,打印async2。此时await让出主线程,后面的代码被阻塞也就是console.log(‘async1 end’);会被阻塞。
3.然后继续执行同步代码new Promise(这是一个宏任务,前面的同步代码也是宏任务),打印Promise1,然后回调中有一个微任务console.log(“promise2”);,加入微任务队列。继续执行,打印"script end"。
4.本轮宏任务全部执行结束,检查微任务列表,还有一个微任务未执行,打印promise2。微任务也执行结束,回到await,await之前让出了主线程,现在开始执行await后面被阻塞的部分,即打印 async1 end。
5.OK,本轮所有任务全部执行完,开始下一轮的宏任务,即定时器异步任务setTimeout,它从事件列表中被添加到ESC执行栈,打印setTimeout。

看到这,也许你的内心是崩溃的,甚至内心里已经是一万头羊驼狂奔而过。
没事,问题不大,再看看涉及的知识点吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值