这段时间一直在研究设计模式,在看工厂模式的时候,看到一段代码
VehicleFactory.prototype.createVehicle = function ( options ) { if( options.vehicleType === "car" ){
this.vehicleClass = Car;
}else{
this.vehicleClass = Truck;
} return new this.vehicleClass( options ); };
对这段代码最后的返回new this.vehicleClass( options )有些迷惑,到底是先执行了后面的方法还是先new了一个新对象出来呢?
直到今天v2ex出现一道JS面试题, v2ex链接 前面几问都没问题,到后面涉及到new的时候感觉有些混乱。
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();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
找了原文,看了下评论,找到了关键的地方,下面的1与2是原文的评论。
1.其实博主没讲明白,这里确实是(new Foo()).getName(),但是跟括号优先级高于成员访问没关系,实际上这里成员访问的优先级是最高的,因此先执行了 .getName,但是在进行左侧取值的时候, new Foo() 可以理解为两种运算:new 带参数(即 new Foo())和函数调用(即 先 Foo() 取值之后再 new),而 new 带参数的优先级是高于函数调用的,因此先执行了 new Foo(),或得 Foo 类的实例对象,再进行了成员访问 .getName。
2.第五问和第六问关于优先级的解释也不恰当,new Foo()中的括号并不是括号运算符,而是函数调用的一部分
new Foo.getName(); 和 new Foo().getName(); 的区别在于
new Foo 结合属于 new 无参数列表的情况(17级)
new Foo() 结合属于 new 有参数列表的情况(18级)
成员访问运算符(.)优先级为 18 级,和 new Foo() 同级
对于同级运算符,按照从左到右的顺序依次计算
所以先执行 new Foo() 返回一个 Foo 的对象 ,对 Foo 对象调用 getName 时查找引用链,得到 Foo.prototype.getName
new Foo 结合被判定为无参数列表的new,优先级低于成员访问,
所以先执行成员访问得到 Foo 的属性 getName, 然后 Foo.getName 和 new 结合,执行带参数列表的 new 运算
需要注意的是带参数列表的 new ...(...) 看起来像是 new 后面跟了一个函数调用,但在判断运算符优先级时 new 运算是一个整体,不能把它分开
javascript 中设定带参数列表 new 的优先级高于函数调用,那么在满足带参数列表的 new 运算符时,就不存在函数调用了
虽然带参数列表的 new 运算也会执行函数调用,但是在判断运算时不把 new 和 ...(...) 分开。
v2ex那位楼主对这个问题的解析也很不错,可以看一下。现在对开头的工厂模式那个new有了正确理解了吧。