js原型小问题

function Tt(){
    this.name = "hello";
    this.age = 88;
    if(typeof this.say != "function"){
        Tt.prototype = {
            constructor: Tt,
            say: function(){
                return this.name;
            }
        };
    }
}
var t = new Tt();
**console.log(t.say());   // Uncaught TypeError: Object #<Tt> has no method 'say'  这里为什么访问不到方法???**


// 如果这么做
function Tt(){
    this.name = "hello";
    this.age = 88;
    if(typeof this.say != "function"){
        Tt.prototype.say = function(){
                return this.name;
            }
    }
}
var t = new Tt();
**console.log(t.say()); // 这样就没有问题!**

小白,不知道为什么这样??希望帮忙解释一下~

阅读 3.1k
4 个回答

What happens when a constructor is called? When new Vehicle() is called, JavaScript does four things:

  • It creates a new object.

  • It sets the constructor property of the object to Vehicle.

  • It sets up the object to delegate to Vehicle.prototype.

  • It calls Vehicle() in the context of the new object.

通俗的说,t在实例化的时候,原型是Tt.prototype指向的对象,所以

Tt.prototype.say=function(){}//创建了原型上的方法,这是可行的

然后构造函数执行了

Tt.prototype = {
        constructor: Tt,
        say: function(){
            return this.name;
        }
    };//Tt.prototype指向了另一个对象,但这个对象不是t的原型!!!!

但是注意了,Tt.prototype的引用改变了,不代表t原型改变了
例如

var a={name:"old"};//a引用了对象{name:"old"}
var b=a;//b通过a引用了对象{name:"old"}
a={name:"new"}//a改变了引用的对象
console.log(b)//b没有改变

@小杰控 说的对!最后才会调用构造器,并以开始创建的空对象当做构造器里面的this来调用构造器的。

function Tt(){
    this.name = "hello";
    this.age = 88;
    //执行到这里的时候,this的原型链上是没有say函数的,而下面直接修改了构造器的原型属性,但是this的原型并没有变化
    if(typeof this.say != "function"){
        Tt.prototype = {
            constructor: Tt,
            say: function(){
                return this.name;
            }
        };
    }
}

如果你在函数定义下面立即调用一下这个函数就不会报错,但是这个say并不是你赋值的say

function Tt(){
    this.name = "hello";
    this.age = 88;
    if(typeof this.say != "function"){
        Tt.prototype = {
            constructor: Tt,
            say: function(){
                return this.name;
            }
        };
    }
}
Tt();
var t = new Tt();
console.log(t.say());

@小杰控 说的是正确的啊,为什么把人家的答案忽略了?

你的问题可以分为两个点:

  1. new操作符做了啥

  2. 对象字面量赋值和对象属性赋值两者的区别

第一点小杰的答案就是了,new操作符会先生成个继承了这个构造器原型的对象,然后再把这个对象绑定到构造函数的this中,最后再执行构造函数。也就是说你在改变构造函数原型方法之前,你的对象实例实际上就已经生成了。

第二点就是 @crp205 所说的了。
形如obj = {}的对象字面量整体赋值,这是创建个新对象,并把这个新对象的引用交给等式的左值。
形如obj.say = ...的对象属性赋值,这个是给已经存在的对象中添加新的属性。

在你的第一个例子中,生成的第一个对象实例之后,这个实例的原型和构造函数的原型实际上已经不是同一个了。
而第二个例子,它们的原型引用的是同一个原型,所以它可以找到say方法。


另外,在你的第一个例子中,你可以再创建第二个实例,看看这个实例能否使用say方法。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏