一道有意思的笔试题引发的对于new操作符的思考
2015-04-05 13:58:00 浏览:1691 作者:管理员
楼主比较喜欢看一些很短但很有意思的题目,无意间又瞥到了一题,大家不妨可以一试。(原题链接猛戳这里)
function Fn1() { this.name = 'peter'; return { name: 'jack' };}function Fn2() { this.name = 'peter'; return 'jack';}var obj1 = new Fn1();var obj2 = new Fn2();console.log(obj1.name, obj2.name);
或许你经常写面向对象编程的代码,也熟悉以上代码中this的用法甚至是prototype或者原型链,但是还是无法解释上面代码的输出,这时我们不得不承认对new的了解还不是很透彻。
先看一段普通的使用new操作符创建对象的代码:
function Person(a, b) { this.name = a; this.age = b;}Person.prototype.show = function() { console.log(this.name, this.age);};var p = new Person('hanzichi', 10);console.log(p);
将console的内容截图:
我们可以清楚看到,p是一个对象,并且拥有构造函数Person中创建的name和age属性,还有个__proto__属性(这货太特殊,反正不在p的hasOwnProperty内!),其值为构造函数的prototype属性值。
其实new操作符创建对象可以分为四个步骤:
- 创建一个空对象
- 将所创建对象的__proto__属性值设成构造函数的prototype属性值
- 执行构造函数中的代码,构造函数中的this指向该对象
- 返回该对象(除非构造函数中返回一个对象)
用代码表示如下:
function Person(a, b) { this.name = a; this.age = b;}Person.prototype.show = function() { console.log(this.name, this.age);};// var p = new Person('hanzichi', 10);var p = {};p.__proto__ = Person.prototype;Person.call(p, 'hanzichi', 10);console.log(p);
观察输出的p,我们看到获取的对象p和通过new操作符获取的对象属性以及属性值一致,甚至连p.__proto__通过hasOwnProperty都无法检测到!
通过以上的介绍,我们基本就可以解答本文开头的那个问题了,其实就是构造函数里,如果返回一个非null的对象(包括数组),则将该对象值赋值给新建的对象,其实上面的实例代码还少了一个是否返回对象的判断,整理后应该是:
function Person(a, b) { this.name = a; this.age = b; return { name: 'zichi' };}Person.prototype.show = function() { console.log(this.name, this.age);};function init() { var p = {}; p.__proto__ = Person.prototype; var temp = Person.call(p, 'hanzichi', 10); if(temp !== null && typeof temp === 'object') return temp; return p;}var p = init();console.log(p);