关于 js new 的疑惑。 请帮忙解答。
发布于 3个月前 作者 workgang 390 次浏览 来自 问答

今天偶然发现这个问题。看不懂。 请大家帮忙解答。

var log = console.log; var $$ = ajQuery = function(selector) {
log(‘aaa’); if(!(this instanceof ajQuery)){ log(‘bbb’); return new ajQuery(selector); } log(‘ccc’); this.selector = selector; return this } $$(‘xxxxx’);

就是上面这个代码。 大家可以 复制 到 console 执行。 结果是: aaa bbb aaa ccc Object { selector="xxxxx"}

函数调用一次,却被执行了 2次。 求解。

8 回复

你在console里跑过了吗?

Screen Shot 2014-11-20 at 10.09.30 AM.png

第一次打印的bbb,是因为this在此时表示global context,所以进入if条件语句,当执行new ajQuery()的时候,因为Function也是javascript里面的一个对象,当你使用new关键字的时候,其实就相当于把function作为构造方法来调用(另外一种调用方式是直接function()),而第二次使用new 调用的时候context就是该方法本身了,所以if判断为false。既然是调用,那方法当然会执行,所以你的这个方法会调用2次。希望对你有帮助。

还有你paste过来的代码单引号不对,所以@leapon 运行的时候报错

感谢大家解答。 我直接 从 控制台 copy 过来的。 看来是这个网站的编辑器会做符号替换。

不知道是不是这样理解。 这里出现了 函数内部又调用了自身。 这里是一个典型的 递归调用。 但是 js 的递归调用 和 其他语言 不太一样。 其他语言 必须明确 获取 递归调用的返回值。 在这个 js 里面。 并没有 获取 return new ajQuery(selector); 的返回值。

第一次调用 this 指向 window 并且返回了一个 this 指向 ajQuery 的对象实例

还是不明白 this 怎么就变了。

js的递归应该和其他语言的递归一样,递归不是语言的特性。 你要理解这个问题,得搞明白javascript的执行上下文。在一个方法的内部,this的指向取决于该方法被调用的方式,并且当使用*’use strict’的时候,它还有有所不同。 简单来说,当你用普通的方法调用function的时候,也就是ajQuery(selector). 此时的context是这个方法被调用的时候的context,你的代码在浏览器里面是window*。那么此时this就是window 但是当方法以构造方法的形式调用的时候,也就是new ajQuery(selector),此时this指向用新建的对象,这里也就是ajQuery。 不知道说的清不清楚。。道友,老夫只能帮你到这儿了。

@workgang

if (!(this instanceof ajQuery)) return new ajQuery(selector);

这是一个经典的自调用构造函数。检查this是否是ajQuery创建的实例,否的话创建。

起源

如果构造函数没有通过new而直接调用,函数中的this将会默认为全局对象,由此造成的破坏将会十分可观。 比如:

var Func = function () {
  this.name = 'Ven';
  this.age = 'unknown';
};
Func(); 
console.log(window.name, age);//log ' Ven unknown '

PS: return this 很多余啊

感谢大家的热心回答。

我突然想明白了。 确实是 我是 php思维。 和 js 真的有点不一样。 php 递归调用。 需要明确的 获取返回值。 然后是分层次的调用。 所有调用完成了。是要返回第一次调用的返回值的。

这里的js调用有点不一样。 第一次调用的时候, 发现 this 不是 ajquery 对象。 就执行了 return new ajQuery(selector);
这个时候 第一次调动已经结束,后面的代码不再执行。

第二次调用的时候 this 已经是 指向 ajquery的实例 了。 第二次调用走完了全部函数代码。 return this 确实是多余的。

回到顶部