浅谈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 表达式的结果

 

 

posted on 2013-08-02 14:58  JoeRay  阅读(211)  评论(0)    收藏  举报

导航