new运算符优先级问题

这里收录一道阿里的变态面试题!!!

function Foo() {
    getName = function() {
        console.log(1);
    };
    return this;
}
Foo.getName = function() {
    console.log(2);
};
Foo.prototype.getName = function() {
    console.log(3);
};
var getName = function() {
    console.log(4);
};
function getName() {
    console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

首先公布一下运行结果,你也可以拷贝然后到浏览器测试:
在这里插入图片描述
接下来我们具体分析一下代码:

预编译

在代码尚未执行时,会发生预编译阶段。

预编译阶段大致上主要分为两个阶段:

  • 变量声明提升
  • 函数声明整体提升

此时会生成一个的全局的GO对象用来保存全局变量:

(之后都将采用function -> n的方式表示是一个函数,n为打印结果。)

GO: {
	Foo: function,
	getName: function -> 5
}
代码执行
Foo.getName = function() -> 2
Foo.prototype.getName = function -> 3
getName = function -> 4

这时候全局GO中的getName值就发生了变化:

GO: {
	Foo: function -> 1,
	getName: function -> 4
}
函数执行
Foo.getName()

这个函数打印结果很显然是2

getName()

该函数执行直接访问GO中的getName方法,所以打印4

Foo().getName()

首先执行Foo函数内部代码,这时全局GO中的getName函数被重新赋值:

GO: {
	Foo: function -> 1,
	getName: function -> 1
}

然后执行reurn this,此时this指向window,所以该函数实际上是调用window.getName(),打印结果为1

getName()

这个函数执行直接在全局范围内执行,所以打印结果也是1

new Foo.getName()

在执行这个函数与下一个函数new Foo().getName()之前,我们需要知道,new时加不加括号的区别,(其实就是一个运算符的优先级问题),在这之前我已经记录过JavaScript运算符优先级,这里直接截图展示:
在这里插入图片描述
可以看出:

  • new(带参数列表)运算的优先级与成员访问运算的优先级相同,并且运算时从左到右。
  • 成员访问运算的优先级高于new(无参数列表)运算的优先级。

搞清楚这一点后我们再看new Foo.getName()这个执行顺序,首先执行Foo.getName()然后在执行new运算符。
执行Foo.getName()打印结果为2new不会改变打印结果。

new Foo().getName()

知道了运算符优先级后,这个函数执行顺序应该是先进行new Foo()操作,得到一个Foo的实例,然后这个实例调用getName()方法,调用的方法应该是原型上的方法,所以打印结果为3

new new Foo().getName()

这个函数执行顺序为先执行new Foo()创建出一个实例,记作xxx,就变成了new xxx.getName(),之后执行顺序为先执行xxx.getName(),同样访问了原型上的方法,打印3,最后的new运算符不改变打印结果。

测验

这道题到这里就结束了,下面有一道类似的题可供大家测验:

function A() {
    alert(1);
}
function Func() {
    A = function() {
        alert(2);
    };
    return this;
}
Func.A = A;
Func.prototype = {
    A: () => {
        alert(3);
    }
};

首先这道题在最后会报错的,但是不会影响得到打印结果。

弹出框依次打印:"1""1""2""1""3""3"

直接注意的是这里使用的是alert()函数打印,该函数会默认调用toString()方法,所以打印结果都为字符串类型的值。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值