手机版

JavaScript中的原型原型学习指南

时间:2021-10-31 来源:互联网 编辑:宝哥软件园 浏览:

原型是什么?

函数类型有一个属性原型,直接翻译为prototype。这个属性只是一个指向对象的指针,它包含一些属性和方法,将由当前函数生成的所有实例(对象)共享。

这句话根据上面所说,仔细揣摩下来,就可以得到下面的代码:

职能人员(){ 0.}人。prototype={country:' China ',say name 3360 function(){ 0.}}首先创建了一个函数类型person的实例,然后person的方法原型是一个对象,所以声明指向一个对象。此对象中的属性和方法将由当前person函数生成的实例共享。也就是说:

Person 1=new Person();Person 2=new Person();人员1和人员2都是通过人员的功能类型实例重新生成的实例。它们都有相同的属性country和方法sayName,因为它们都有一个指针(_ prototype _ _),直接指向Person.prototype所指向的对象,但是需要注意的是,指针_ _ prototype _ _并不是标准的。它仅由Chrome和Firefox等浏览器定义。在实践中,这个属性不会被使用,而仅用于理解原型:

201659145452510.png  (668270)

关于原型的用法等。我们稍后会更具体地讨论。

创建对象的模式。

接下来,我们将看看创建对象的方法和常见模式,以及它们的优缺点。

1.工厂模式。

就像工厂一样,它抽象出创建具体对象的过程,并使用函数封装创建具有特定接口的对象的细节。用函数代替部分重复性工作,代码如下:

函数createPerson(姓名、年龄、职务){ var o=new Object();o.name=nameo.age=年龄;o.job=jobo . SayName=function(){ alert(this . name);};返回o;}var person1=createPerson('姜水',' 22 ','工程师');这样就创建了一个人,工厂模式解决了多个相似对象重复创建的问题,但没有解决对象识别的问题。简单地创建一个对象,不管该对象是从人类模板还是动物模板创建的,都不能区分对象的类型。

2.构造器模式。

创建自定义构造函数来定义自定义对象类型的属性和方法。

功能人员(姓名、年龄、工作){ this.name=namethis.age=年龄;this.job=jpbthis . SayName=function(){ alert(this . name);};};var person1=新人员(.);3.构造器模式和工厂模式的区别:

没有明确的创建对象。将属性和方法直接分配给此对象。没有退货单。人是函数类型的对象。新建后,将继续生成一个对象。但是,当这个新生成的对象传入函数中的参数并被分配给这个指针时,传入的内容就变成了新生成的对象的属性或方法。

构造函数的默认习惯是大写第一个字母。上述代码的执行经历了以下步骤:

创建一个新对象,将构造函数的范围分配给新对象,执行构造函数中的代码,并返回新对象。默认情况下,所有生成的实例都包含指向构造函数的构造函数属性,例如:

alert(Person 1 . constructor==Person);因此,使用构造函数模式,类型之间是有区别的,它的实例可以被识别为特定的类型。

此外,构造函数是普通函数,所以用new调用它们,因为它们希望通过反馈获得新的对象。如果不用,直接执行就跟普通函数一样。比如上面,执行Person.sayName()会弹出window.name因为函数是在window下执行的,所以这个指向window。

构造函数模式也有缺陷。构造函数模式中的方法在每个实例中重新创建,因此不同实例上同名的函数不相等。例如:

person 1 . SayName==person 2 . SayName;//false也就是说,构造函数生成的每个对象实例、属性和方法都是唯一的,并且只复制一次。唯一的属性是必须的,因为这是对象之间的区别,但是很多方法都有相同的功能和代码。重复复制显然会浪费资源。

所以我们可以把函数放在外面,然后用构造函数中的指针指向这个函数。在生成的实例中,该方法存储指向某个函数的指针,从而共享一个函数:

函数Person(姓名、年龄){ this.name=namethis.age=年龄;this.sayName=sayName}函数SayName(){ alert(this . name);}但这样一来,这个函数就变成了一个全局函数,与Person构造函数的关系并不密切,所以完全没有封装。

请欢迎原型模式。

原型模式

我已经介绍了一些关于原型的基本知识。简单来说,每个函数都有一个原型属性,它指向一个对象(prototype object),其中可以放置一些属性或方法。那么这个函数生成的实例将有一个指向原型的不规则属性(_proto__)。

从这个角度来看,您应该理解原型生成的属性和方法被所有实例共享。

通过这种方式,解决了上述构造器模式下实例中的函数共享问题。例如,以下代码:

函数Person(){ 0.}Person.prototype.name='姜水';person . prototype . SayName=function(){ alert(this . name);};var Person 1=new Person();person 1 . SayName();//姜水或。

Person . prototype={ constructor : Person,name : '姜水',say name : function(){ alert(this . name);}};第二种方法覆盖了整个原型对象,所以需要手动指定构造函数属性,指向构造函数或者指向对象。

梳理他们的关系:

人。prototype-> prototype对象,它可以定义一些属性或参数,并由所有实例共享。人。prototype . constructor==person-> prototype对象有一个默认的属性构造函数,指向原型对象所属的构造函数(注意,另一个编写将覆盖这个属性,需要重新指定)。Person 1=new person ()-“构造函数生成一个实例,该实例包含构造函数和原型对象的内容。人员1。_ _ proto _ _-”指向创建此实例的原型对象(未标准化,不要使用它)。使用isPrototypeOf()确定对象之间的关系。例如:

person . prototype . is rototype of(person 1);当代码读取对象的属性时,它会执行搜索。从当前对象开始,如果没有,将搜索指针指向的原型对象,而不是构造函数。实例可以访问但不能重写原型对象的值。如果在实例中设置了与原型对象同名的属性,则搜索过程在实例中结束,无需访问原型对象,从而达到覆盖的目的。因此,即使该属性设置为null,也意味着该属性已经存在于实例中,并且该属性不会被取消,因此可以访问原型的相应属性。

因此,您需要使用delete操作符来完全删除实例属性,以便可以重新访问原型。

原型是动态的,对原型对象所做的任何修改都可以立即从示例中反映出来。原因是实例和原型之间松散的链接关系。每次调用实例的属性方法时,都会进行查询。如果原型改变,查询结果也会改变。

理解原型之后,我们还可以向原生对象添加新的方法或属性。Object、Array、String等原生引用类型与上述构造函数类似,我们可以用prototype扩展它们的方法。例如:

string . prototype . starts with=function(text){ return this . indexof(text)=0;};var msg=《你好世界》;msg . starts with(' Hello ');这段代码是一个本机引用类型的字符串,并添加了一个startsWith方法。它的功能是传入一个参数,查看要测试的字符串是否以该参数开始。由于原型的动态特性,只要执行它,所有字符串类型的变量都会得到这个方法。

但是,不建议使用此方法。如果使用太多代码,会导致维护困难和代码混乱。通常,先继承本机引用类型,然后在新的自定义类型上创建它。继承将在后面总结。

原型模式也不是万能的。原型中的所有属性和方法都被所有实例共享,所以非常适合函数之类的,对于包含引用类型的属性会产生一些冲突。例如:

function PeRsoN(){ } PeRsoN . prototype={ constructor : PeRsoN,friends : ['greg ',' jack ']};var Person 1=new Person();var Person 2=new Person();person 1 . friends . push(' Tom ');console . log(person 2 . friends);您可以在控制台中看到,person2的朋友多了一个tom,这不是我想要的,但是当为person1定义他的朋友时,它确实会影响person2的实例。

所以要把原型模式和构造模式结合起来。

结合构造器模式和原型模式。

这是最常用的模式。构造函数用于定义实例属性,并通过传递参数实现自定义。原型用于定义需要由所有实例共享的方法或属性。这样既实现了定制,又保证了共享,避免了问题。

功能人员(姓名、年龄、工作){ this.name=namethis.age=年龄;this.job=jobthis.friends=['greg ',' jack '];} Person . prototype={ constructor : Person,say name : function(){ alert(this . name);}};var姜水=新人('姜水',' 22 ','工程师');实际应用实例。

好了,在这里,你可能明白什么是原型,如何创建对象,但是这一切有什么用呢?事实上,在我之前的工作中,我只需要用jQuery编写一些代码,不需要封装然后生成对象来实现功能。这一切有什么用?

这种开发方法主要用于模块化和有组织的开发。例如,您可以每次粘贴和复制弹出代码,然后修改它以在项目中使用。更好的选择是将您的弹出功能代码抽象地打包到这样一个组件中,这样当您需要使用弹出窗口时,您只需要传递参数来生成一个弹出窗口实例,然后就可以调用它了。

原型对象和原型链。

在Javascript中,一切都是一个Object,但是对象之间是有区别的,大致可以分为两类:普通对象和Function对象。

一般来说,新Function生成的对象是函数对象,其他对象是普通对象。

举个例子:

函数f1(){ //todo}var f2=函数(){//todo };var f3=新函数(' x ',' console . log(x)');var O1={ };var o2=新对象();var o3=新f1();console.log(typeof f1,//function typeof f2,//function typeof f3,//function typeof o1,//object typeof o2,//object type of O3//object);function function object是函数的声明,定义函数最常见的方式是f2实际上是一个匿名函数,赋给f2,属于函数表达式。f3不常见,但也是一个函数对象。

是函数JS的对象。当创建f1和F2时,JS将通过新的Function()自动构建这些对象。因此,这三个对象是由新的Function()创建的。

在Javascript中创建对象有两种方式:文字对象和新表达式。o1和o2的产生正好对应这两种方式。关注o3。如果用Java和C#理解,o3是f1的实例对象,o3和f1是同一类型。至少我之前是这么想的,但事实并非如此…

那么如何理解呢?很简单,看o3是不是新Function生成的,显然不是。既然不是函数对象,那就是普通对象。

在简单了解了函数对象和普通对象之后,让我们来看看Javascript中的原型和原型链:

在JS中,每当创建一个函数对象f1时,都会在对象中构建一些属性,包括prototype和_ _ prototype _ _。Prototype是一个原型对象,它记录了f1的一些属性和方法。

请注意,prototype对f1是不可见的,也就是说,f1不会在prototype中寻找属性和方法。

函数f(){ } f . prototype . foo=' ABC ';console . log(f . foo);//undefined那么,原型有什么用呢?其实原型的主要功能是继承。一般来说,prototype中定义的属性和方法都是为自己的“后代”保留的,所以子类完全可以访问prototype中的属性和方法。

要知道f1是如何把原型留给“后代”的,我们需要知道JS中的原型链。这个时候JS中的_ _ prototype _ _进入了,很奇怪,很隐蔽,你经常看不到,但是它既存在于普通对象中,也存在于函数对象中,它的作用是保存父类的原型对象。JS通过新表达式创建对象时,通常会将父类的原型赋给新对象的__proto__属性,从而形成代与代的继承…

函数f(){ } f . prototype . foo=' ABC ';var obj=new f();console . log(obj . foo);//abc现在我们知道obj中的__proto__存储了F的原型,那么F的原型中的__proto__存储了什么呢?请看下图:

201659150626664.png  (515122)

如图所示,Object.prototype存储在f.prototype的_ _ prototype _ _中,object.prototype中也存在_ _ prototype _ _从输出结果来看,object.prototype. _ _ prototype _ _为空,表示obj对象的原型链结束。如下图所示:

201659150641500.png  (607148)

obj对象有了这样的原型链之后,在执行obj.foo的时候,obj会先找出它是否有这个属性,但是不会找到它的原型。当foo没有找到时,obj将依次沿着原型链搜索…

在上面的例子中,我们在f的原型上定义了foo属性,然后obj会在原型链上找到这个属性并执行它。

版权声明:JavaScript中的原型原型学习指南是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。