当前位置: 首页 > Web前端 > JavaScript

原型模式

时间:2023-03-27 14:11:04 JavaScript

每个函数都会创建一个原型属性,它是一个对象,包含应由特定引用类型的实例共享的属性和方法。其实这个对象就是调用构造函数创建的对象的原型。使用原型对象的优点是定义在其上的大型属性和方法可以被对象实例共享。1.原本在构造函数中赋给对象实例的值,可以直接赋给它们的原型,如下图:functionPerson(){}Person.prototype.name="张三";Person.prototype.age=29;Person.prototype.job="Web前端开发";Person.prototype.sayName=function(){console.log(this.name);}letperson1=newPerson();person1.sayName();//张三letperson2=newPerson();person2.sayName();//张三console.log(person1.sayName===person2.sayName);//true也可以用函数表达式:letPerson=function(){};Person.prototype.name="李四";Person.prototype.age=20;Person.prototype.job="IOS开发";Person.prototype.sayName=function(){console.log(this.名字);}让person1=newPerson();person1.sayName();//李思让person2=newPerson();person2.sayName();//李思console.log(person1.sayName===person2.sayName);//true这里所有的属性和sayName()方法都是直接添加到Person的prototype属性中,构造函数体什么都没有.但是这样定义之后,调用构造函数创建的新对象还是有相应的属性和方法的。与构造器模式不同,使用此原型模式定义的属性和方法由所有实例共享。所以person1和person2访问相同的属性和相同的sayName()函数。要理解这个过程,有必要理解ECMAScript中原型的性质。2、理解原型无论何时,只要创建了一个函数,就会按照特定的规则为该函数创建一个原型属性(指向原型对象)。默认情况下,所有原型对象都会自动获得一个名为constructor的属性,该属性指向与其关联的构造函数。对于前面的示例,Person.prototype.constructor指向Person。然后,根据构造函数,可以将其他属性和方法添加到原型对象。自定义构造函数时,原型对象默认只会获取constructor属性,其他方法均继承自Object。每次调用构造函数创建新实例时,实例的内部[[Prototype]]指针都会被分配构造函数的原型对象。在脚本中没有标准的方法来访问这个[[Prototype]]属性,但是Firefox\Safari和Chrome会在每个对象上暴露proto属性,通过它可以访问对象的原型。在其他实现中,此功能是完全隐藏的。关键是要理解这一点:实例和构造函数原型之间有直接联系,但实例和构造函数之间没有直接联系。3.这种关系不容易形象化,但是可以通过下面的代码理解原型的行为:构造函数可以是函数表达式,也可以是函数声明,所以可以接受下面两种形式:/*functionPerson(){}letPerson=function(){}*/functionPerson(){}/*声明之后,构造函数有一个与之关联的原型对象:*//*如前所述,构造函数有一个原型属性引用其prototype对象,而这个prototype对象还有一个constructor属性,引用这个constructor也就是两个循环引用:console.log(Person.prototype.constrctor===Person);//真*/4。Normal原型链总是终止于Object的原型对象;Object原型的原型为空。console.log(Person.prototype.__proto__===Object.prototype);//trueconsole.log(Person.prototype.__proto__.constructor===Object);//trueconsole.log(Person.prototype.__proto__.__proto__);//null5。constructor\prototypeobject\instance是三个完全不同的对象:letperson1=newPerson(),person2=newPerson();console.log(person1!=Person);//真正的控制台.log(person1!=Person.ptototype);//trueconsole.log(Person.prototype!=Person);//真1。实例通过__proto__链接到原型对象,它实际上指向隐藏属性[[Prototype]]2.构造函数通过原型属性链接到原型对象3.实例与构造函数没有直接联系,但具有与原型对象直接连接console.log(person1.__proto__===Person.prototype);//trueconsole.log(person1.__prototype__.constructor===Person);//真6。同一个构造函数创建的盟友实例共享同一个原型对象。控制台日志(person1.__proto__===person2.__proto__);//真7。使用instanceof检查实例的原型链是否包含指定构造函数的原型:console.log(person1instanceofPerson);//trueconsole.log(person1instanceofObject);//trueconsole.log(Person.prototypeinstanceofObject);//真8。对于前面例子中的Person构造函数和Person.prototype,可以通过图8-1看到各个对象之间的关系。图8-1显示了Person构造函数\Person的原型对象与Person的两个现有实例之间的关系。请注意,Person.prototype指向原型对象,而Person.prototype.constrctor指向Person构造函数。原型对象包含constructor属性和后来添加的其他属性。Person的两个实例,person1和person2,只有一个引用Person.prototype的内部属性,并且都与构造函数没有直接联系。另请注意,虽然两个实例都没有属性或方法,但可以正常调用person1.sayName()。这是由于对象属性查找机制。9.虽然不是所有的实现都会向外界公开[[Prototype]],但是你可以使用isPrototypeof()方法来确定两个对象之间的这种关系。本质上,当传入参数的[[Prototype]]指向调用它的对象时,isPrototypeof()返回true,如下所示:console.log(Person.prototype.isPrototype(person1));//trueconsole.log(Proson.prototype.isPrototype(person2));//true在这里,person1和person2通过调用原型对象的isPrototypeof()方法来检查。因为这两个示例都有指向Person.prototype的内部链接,所以它们都返回true。10、ECMAScript的Object类型有一个方法叫Object.getPrototypeof(),返回参数的内部属性[[Prototype]]的值。例如:console.log(Object.getPrototypeof(person1)==Person.prototype);//trueconsole.log(Object.getPrototypeof(person1).name);//Lisi的第一行代码简单的确认了Object.getPrototypeof()返回的对象是传递对象的原型对象。第二行代码获取原型对象上name属性的值,即“李四”。使用Object.getPrototypeof()可以轻松获取对象的原型,这在通过原型实现继承时尤为重要。11、Object类型还有一个setPrototypeof()方法,可以向实例的私有属性[[Prototypeo]]写入一个新值。这样就可以改写一个对象的原型继承关系:letbiped={numLegs:2};letperson={name:"Chen"}Object.setPrototypeof(person,biped);console.log(person.name);//Chenconsole.log(person.numLegs);//2console.log(Object.getPrototypeof(person)===biped);//true警告:Object.setPrototypeof()可能会严重影响代码性能。Mozilla的文档说的很清楚:“在所有的浏览器和JavaScript引擎中,修改继承关系的影响是微妙而深远的。这种影响不仅仅是执行Object.setPrototypeof()语言这么简单,而是涉及到所有访问修改[[Prototype]]"的对象的代码。12、为了避免使用Object.setPrototypeof()可能带来的性能下降,可以通过Object.create()创建一个新对象,同时为其指定一个原型:letbiped={numLegs:2}letperson=Object.create(biped);person.name="Chen";console.log(person.name);//Chenconsole.log(person.numLegs);//2console.log(Object.getPrototypeof(person)===biped);//真13。本期的分享到这里就结束了,希望对大家有所帮助,让我们一起努力,勇攀高峰!