prototype和constructor

本文深入探讨了JavaScript中构造函数的局限性,以及如何利用原型对象(prototype)来解决实例对象间无法共享属性的问题,详细解释了prototype属性的作用、原型链的概念及constructor属性的用法。
prototype 对象
 3.1 构造函数的缺点
            实例对象的属性和方法,可以定义在构造函数内部。
            通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法
            共享属性,从而造成对系统资源的浪费。 
            function Cat(name, color) {
              this.name = name;
              this.color = color;
              this.meow = function () {
                console.log('喵喵');
              };
            }
            var cat1 = new Cat('大毛', '白色');
            var cat2 = new Cat('二毛', '黑色');
            cat1.meow === cat2.meow
            // false
            上面代码中,cat1和cat2是同一个构造函数的两个实例,它们都具有meow方法。由于meow方法是生成在
            每个实例对象上面,所以两个实例就生成了两次。
            这个问题的解决方法,就是 JavaScript 的原型对象(prototype)。
 3.2 prototype 属性的作用
            JavaScript 的每个对象都继承另一个对象,后者称为“原型”(prototype)对象。一方面,任何一个对
            象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。null也可以
            充当原型,区别在于它没有自己的原型对象。
            原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象
            可以视作从原型对象衍生出来的子对象。
            Animal.prototype.walk = function () {
              console.log(this.name + ' is walking');
            };
            上面代码中,Animal.prototype对象上面定义了一个walk方法,这个方法将可以在所有Animal实例对象上
            面调用。构造函数就是普通的函数, 所以实际上所有函数都有prototype属性。
3.3 原型链
            对象的属性和方法,有可能定义在自身,也有可能定义在它的原型对象。由于原型本身也是对象,又有自己
            的原型,所以形成了一条原型链(prototype chain)。比如,a对象是b对象的原型,b对象是c对象的原型
            ,以此类推。如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数
            的prototype属性。那么,Object.prototype对象有没有它的原型呢?回答是有的,就是没有任何属性和方
            法的null对象,而null对象没有自己的原型。
            如果让某个函数的prototype属性指向一个数组,就意味着该函数可以当作数组的构造函数,因为它生成的
            实例对象都可以通过prototype属性调用数组方法。
            var MyArray = function () {};
            MyArray.prototype = new Array();
            MyArray.prototype.constructor = MyArray;
            var mine = new MyArray();            mine.push(1, 2, 3);
            mine.length // 3
            mine instanceof Array // true
 3.4 constructor 属性
            prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
            function P() {}
            P.prototype.constructor === P
            // true
            由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。
            function P() {}
            var p = new P();
            p.constructor
            // function P() {}
            p.constructor === P.prototype.constructor
            // true
            p.hasOwnProperty('constructor')
            // false

 

在 JavaScript 中,`Function.prototype.constructor` 是一个指向构造函数本身的引用。每个函数都具有 `prototype` 属性,该属性是一个对象,而这个对象默认包含一个 `constructor` 属性,它指向原始的构造函数。这一机制确保了通过构造函数创建的对象实例可以访问到其构造函数的引用。 当定义一个新的函数时,JavaScript 引擎会自动为该函数的 `prototype` 对象设置 `constructor` 属性,并将其指向该函数本身。例如: ```javascript function Person(name) { this.name = name; } console.log(Person.prototype.constructor === Person); // true ``` 上述代码中,`Person.prototype.constructor` 指向 `Person` 函数,这表明构造函数与其原型之间存在双向关系[^1]。 此外,这种设计允许从对象实例追溯到其构造函数,尽管这不是一种推荐的做法,因为直接依赖 `constructor` 可能会在某些继承模式下导致问题。例如: ```javascript const person = new Person('Alice'); console.log(person.constructor === Person); // true ``` 此特性对于实现特定的设计模式(如工厂模式或反射)可能非常有用,但在实际开发中应谨慎使用,以避免潜在的维护难题混淆[^2]。 ### 原型链中的 `constructor` 在原型继承模型中,如果子类的原型被替换为父类的一个实例,则子类的原型上的 `constructor` 通常会被重新指向父类。为了保持一致性,开发者常常手动修正这个 `constructor` 指针: ```javascript function Child() {} Child.prototype = Object.create(Person.prototype); Child.prototype.constructor = Child; // 修复 constructor 指针 ``` 这样做是为了保证 `Child.prototype.constructor` 正确地指向 `Child` 而不是 `Person`,从而避免误导后续的开发者或者框架对类型的判断[^1]。 ### 总结 `Function.prototype.constructor` 提供了一种方式来从原型对象反向访问构造函数,这对于调试某些编程模式可能是有用的。然而,在复杂的继承结构中,需要特别注意 `constructor` 的正确性,以防止出现意料之外的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值