js高级程序设计中关于创建对象的一点问题

function Person(){
}

Person.prototype ={

name: "Nicholas",
age:29,
job: "software engineer",
sayName : function(){
    alert(this.name);
}

};
var friend = new Person();

我们将Person.prototype设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外:constructor属性不再指向Person了。前面曾经介绍过,每创建一个函数,就会同时创建他的prototype对象,这个对象也会自动获得constructor属性,而我们这里使用的语法,而我们在这里使用的语法,本质上完全重写了默认的 prototype 对象,因此 constructor 属性也就变成了新对象的 constructor 属性(指向 Object 构造函数),不再指向 Person 函数。此时,尽管 instanceof操作符还能返回正确的结果,但通过 constructor 已经无法确定对象的类型了。

这是书中的一段话,可以说完全没看懂,这个constructor到底指向啥,一开始,constructor指向Person,后来为什么又指向Object了呢。。

阅读 3.6k
6 个回答
function ww(){}//定义一个函数,那么他有个prototype属性指向一个对象
var pro = ww.prototype  //让pro指向这个对象
pro.construcor === ww  //true,说明pro这个对象的constructor属性指向函数ww
ww.prototype ={//所谓的重写也就是这属性变心了,找其他人去了,但是pro没变心啊,还是那个对象
    a:1
}//让ww的prototype指向另一个对象 ,此时这个对象的constructor显然不是ww啦,而且新创建的对象没有construct属性,自然就沿着原型链往上找了
pro.constructor === ww //true
ww.prototype.constructor === ww//false
Person.prototype.constructor = Person;

Person.prototype ={

name: "Nicholas",
age:29,
job: "software engineer",
sayName : function(){
    alert(this.name);
}
};//给 Person.prototype对象重新赋值 ,很明显 Person.prototype.constructor!==Person
Person.prototype ={
name: "Nicholas",
age:29,
job: "software engineer",
sayName : function(){
    alert(this.name);
}
};

这一步就是把Person.prototype 修改为一个新的字面量对象 函数创建时的prototype仍然存在

function T() {

    };
    T.prototype.a = 3;
    var a = new T;
    T.prototype = {
        a : 4
    };
    var b = new T;
    a.a //3
    b.a //4

如果不想让constructor指向发生变化可以手动设置

Person.prototype ={
constructor : Person,
name: "Nicholas",
age:29,
job: "software engineer",
sayName : function(){
    alert(this.name);
}
};

或者采用ES6的class来创建构造函数及原型

class Person {
    constructor(){
        sth;
    }
    name: "Nicholas",
    age:29,
    job: "software engineer",
    sayName (){
        alert(this.name);
    }

}

MDN constructor 返回一个指向创建了该对象原型的函数引用

function Person() {}

Person.constructor 指向的是Function (因为Person是由Function创建的)
Person.prototype.constructor 指向的是Person 也就是它本身,为默认行为

当你对它的prototype进行赋值后,将会改写prototype对象 (因为prototype这是为Object创建的)

如下可证明
如果 Person.prototype=[] 这样, 则此时的Person.prototype.constructor为 Array

再送给你一张图好好理解一下
172121182841896.png

如上图,SuperType是是一个函数,右侧的方框就是它的原型。
引用

我觉得这种说明方式特别坑新,拿了一个错误示例来说明函数关系;

通常的正确写法应该是这样的:

        function Person() {
            this.name = "Nicholas";
            this.age = 29;
            this.job = "software engineer";
            this.sayName = function () {
                alert(this.name);
            }
        }
        
        //friend 继承Person函数;
        var friend = new Person();
        
        friend.constructor; // function Person() {...}
        friend.name; // "Nicholas"
        friend.__proto__; // chrome可见,prototype 属性;包含两个对象的Object{},一个是constructer:Person(),继承自Person()的一些原型属性。另一个是继承自Object的一些属性
        

而该例子直接覆盖了prototype 原型,导致friend.__proto__里面变成了你写的一些属性;

其实你会发现,这个例子里面只有friend.constructor才是friend自带的属性,并没有friend.name属性。

但是还是可以打印出来。因为js如果找不到friend.name会到他父对象里面找,再找不到会到他父对象的父对象里找;直到找到匹配的第一个,或者把所有祖先对象遍历完才会停下来。

因此friend.name优先级会高于Person.name,并不是覆盖了,而是他先找到这个。

也可以看出来,多重继承非常耗费性能,因为他如果没找到会全部遍历一遍

constructor的存在只会让人把JavaScript和传统的基于类的面向对象语言混淆,建议不要管什么constructor,只要你理解JavaScript中的对象创建和原型,就懂了JavaScript的面向对象的思想。
正好刚写了篇这方面的文章,推荐你看下:https://segmentfault.com/a/11...

推荐问题
宣传栏