浅谈Javascript的new运算符
一、背景
在网上看到一篇别人转的玉伯前辈关于“new FunctionName()运行机制浅析”的文章,里面举了一个例子,代码如下:
function Dog(name) { this.name = name; Dog.prototype = { shout: function() { alert("I am " + this.name); } }; } var dog1 = new Dog("Dog 1"); dog1.shout();
运行之后报错:Uncaught TypeError: Object #<Dog> has no method 'shout'
实际上,new Dog()的过程等价于
var o = {__proto__: Dog.prototype}; Dog.apply(o); return o;
而JS引擎在遇到函数声明的时候会给函数对象添加prototype属性,即Dog.prototype = {constructor: Dog},运行到new Dog(...)时,
执行的操作相当于
// Dog.prototype = {constructor: Dog}; var o = {__proto__: Dog.prototype}; // 现在,o = {__proto__: {constructor: Dog}} Dog.apply(o); // 现在,Dog.prototype = {shout: function(){...}} return o;
所以,dog1.shout()会报错也是情理之中的事情。
二、探索
虽然dog1没有shout()方法,但是目前Dog的prototype已经是{shout: function(){...}}
所以此时再写2句var dog2 = new Dog('xxx');dog2.shout();就可以正常执行了
总的来说,上面的构造函数还都是比较规范的,下面我们做一点改变,在构造函数里加一句return 语句
function a() { this.name = 'joe'; return {name: 'ray'}; } var obj = new a(); alert(obj.name); //ray
运行的结果是ray,由此可见,new a()生成的a对象被抛弃,返回的是return语句后面的对象
下面我们再来做一个实验
function a() { this.name = 'joe'; return 'ray'; } var obj = new a(); alert(obj.name); //joe alert(obj); //[object Object]
这回obj.name的值是joe,而且obj是一个对象,说明new a()生成的a对象并没有被抛弃
三、小结
事实上,在使用new Func()来生成一个对象的时候, 整个过程是这样的:
1、创建一个新对象,它的类型是Func,并且它会继承Func.prototype的所有属性(原型继承)
2、构造函数被调用,this对象被绑定给这个新创建的对象
3、若构造函数没有明确的返回值,那么新创建的对象就是整个 new 表达式的结果;反之,若构造函数内显式定义了返回值,则该返回值为整个 new 表达式的结果
浙公网安备 33010602011771号