1、背景app
在网上看到一篇别人转的玉伯前辈关于“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'this
实际上,new Dog()的过程等价于spa
var o = {__proto__: Dog.prototype}; Dog.apply(o); return o;
而JS引擎在遇到函数声明的时候会给函数对象添加prototype属性,即Dog.prototype = {constructor: Dog},运行到new Dog(...)时,prototype
执行的操做至关于code
// Dog.prototype = {constructor: Dog}; var o = {__proto__: Dog.prototype}; // 如今,o = {__proto__: {constructor: Dog}} Dog.apply(o); // 如今,Dog.prototype = {shout: function(){...}} return o;
因此,dog1.shout()会报错也是情理之中的事情。对象
2、探索blog
虽然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对象并无被抛弃
3、小结
事实上,在使用new Func()来生成一个对象的时候, 整个过程是这样的:
一、建立一个新对象,它的类型是Func,而且它会继承Func.prototype的全部属性(原型继承)
二、构造函数被调用,this对象被绑定给这个新建立的对象
三、若构造函数没有明确的返回值,那么新建立的对象就是整个 new
表达式的结果;反之,若构造函数内显式定义了返回值,则该返回值为整个 new
表达式的结果