欢迎来到魔豆IT网-IT综合知识分析平台

理解JavaScript中的对象原型和原型链

2020-11-20 21:05:58栏目 : 网络编程围观 : 23次

本文介绍了JavaScript中的对象原型和原型链。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有帮助。

对象原型认为每个人都这样使用过地图:

let arr = [0,1,2]let doubleArr = arr.map(c = >;C * 2) console.log (double arr)//0,2,4不知道大家有没有想过arr本身没有设置map属性,那为什么可以使用函数映射呢?

打印出来看看:

console.log (arr)中有一个名为__proto__的对象//0:0//1:1//2:2//length:3/_ _ proto _ _:Array(0)。如果您再次展开它,您将看到所有数组对象都可以使用的函数。当然,我们也可以在其中找到map函数,这就是例子中调用的函数arr.map:

Console.log (arr.map = = = arr。_ _ proto _ _ _。map)//true这里出现的_ _ proto _ _对象也叫Prototype对象。

不同于基于类的面向对象语言,如Java和C#,属性和方法是通过定义类、创建实例和指定继承来传递的。Javascript是一种基于Prototype的对应语言,它指定当通过预先建立的原型对象建立新对象时,对象的原型应该引用哪个原型对象。

当我们调用一个对象的属性或方法时,如果对象本身没有这个属性或方法,JavaScript会自动在其原型中寻找该方法,这就是为什么可以直接调用arr.map而不出错。

原型链您可能已经发现,在前面的示例中,__proto__对象仍然具有__proto__属性:

Console.log (arr。_ _ proto _ _)//Prototype console . log of array(arr。_ _ proto _ _ _。_ _ proto _ _)//Prototype console . log of Object(arr。_ _ proto _ _ _。_ _ proto _ _ _。_ _ proto _ _)//null在上述机制中,无论何时构建对象,原型都是绑定的。既然对象有原型,那么对象原型也是对象本身,也不例外;我们可以从这个例子中看到:

Arr是数组实例,原型是Arrayarr。__proto__是数组原型,原型是objectarr。_ _ proto _。_ _ proto _ _是对象原型,原型是nullar。_ _ proto _ _ _。_ _ proto _ _是null,没有任何属性,这样就形成了一种隶属关系,相互关联,相互依存。我们称之为原型链;通过这个机制,对象可以使用原型中的属性和方法,按顺序一层一层继承原型链,使对象拥有原型链中所有原型的功能,这就是JavaScript对象背后的操作机制。

注意:在JavaScript中,几乎每个原型链都以一个Object结束,最后指向null。说了这么多关于使用原型的事情,是时候写一些代码了。我们来练习一下原型的建立,设定,修改。

首先,创建一个新的对象构造函数:

函数Person(name){ this . name = name } Person . prototype . hello = function(){ console . log(` hello $ { this . name } `)}让Gary = new Person(& # 39;加里& # 39;)Gary . hello()//hello Gary . object . getprototypeof(Gary)//{ hello:,构造函数:}以上示例创建了一个简单的对象构造函数Person(),并在构造函数中设置了对象属性。在object的方法中,由于该方法不需要让每个对象都有自己的副本来避免冗余的内存消耗,所以应该像前面的Array.prototype.map的例子一样设置为prototype对象(Person.prototype),这样这个构造函数创建的所有对象都可以共享这些方法。最后创建一个新的Person对象,通过getPrototypeOf(obj)获得新创建对象的原型。

问:为什么不用__proto__直接获取原型对象?答:因为__proto__虽然几乎所有浏览器都支持,但它是非标准属性;通过getPrototypeOf获取对象的原型是正确的方法。提醒:Person.prototype不是Person的原型,而是执行构造函数后创建的新对象的原型;永远不要混淆构造函数的原型属性和对象的原型!

原型继承然后创建一个新的对象原型并继承人员:

函数工程师(名字,技能){ Person.call(this,名字)this.skill = skill }工程师. prototype = object . create(person . prototype)工程师. prototype . constructor = Engineer let Alice = new Engineer(& # 39;爱丽丝& # 39;,& # 39;JavaScript & # 39)爱丽丝。hello ()//hello Alice。控制台。日志(爱丽丝。技巧)//javascriptobject。get prototype of(Alice)//person { constructor:}一个新对象Engineer的原型已经在这里建立。并通过Engineer.prototype的指定,让其原型继承Person.prototype,最后重置Engineer.prototype.constructor,让构造函数重新指向自身;这就完成了最基本的原型继承。

问:为什么需要重置构造函数?答:Person.prototype的所有属性都被Object.create复制,这会和构造函数属性一起被覆盖。如果构造函数属性错误,在判断instanceof时会产生错误的结果;因此,在这里设置继承时,需要将构造函数重新分配回构造函数本身。修改原型原型的引用和继承直接引用原型对象,而不是在每个对象中复制一个原型;因此,您可以使用此功能向原型添加自定义属性和方法,以便此类型的所有对象都可以获得新方法;很多老浏览器的Polyfill都是这样实现的。

例如,当我们编写Vue项目时,我们可能已经做了类似的操作,并将共享属性方法放入Vue.prototype:

object . define property(Vue . prototype,& # 39;$ date & # 39,{value: dateTimeFormat })//之后就可以用vm了。$date(dateObj)这样,确实方便,但是也要提醒大家,做原型修改的时候要非常小心。按照刚才的例子,如果您试图修改Person原型中的方法:

人。prototype . hello = function(){ console . log(` bye $ { this。名称}。`)}加里。你好()//再见加里。爱丽丝。你好()//再见爱丽丝。如结果所示,当对象原型被修改时,原型链上具有该原型的所有对象都将受到影响

建议除非是Polyfill,否则尽量避免修改原生对象的原型,防止可能出现的意外结果。

ES6班看完上一段会觉得累吗?不要担心,从ES6开始就加入了Class语法糖,大大提升了开发者体验。让我们用类重构前面的例子:

classperson {构造函数(名称){this。name = name }//方法将自动放置在person . prototype hello(){ console . log(` hello $ { this。名称}。`)}} Class engineer扩展Person {constructor (name,skill){ super(name)//这个叫Person的constructor。技能=技能}}让爱丽丝=新工程师(& # 39;爱丽丝& # 39;,& # 39;JavaScript & # 39)爱丽丝。hello ()//hellolaice。对象。getprototype of(Alice)//person { constructor:}很方便,但是同样的功能,代码的可读性提高了很多,可以把繁琐的设置交给语法,帮助你自动完成。但在便捷语法的背后,底层依然是对象原型和原型链。

综上所述,以上是JavaScript中对对象原型的描述,希望能帮助你理解对象原型。在这个一切都是对象的语言中,充分理解和掌握对象原型是专业码农必须突破的障碍之一。

有关编程的更多知识,请访问:编程课程!!以上是为了理解JavaScript中对象原型和原型链的细节,等等

展开剩余内容

分享到:

猜你喜欢

  • 查看CentOS7版本信息的方法

    下面centos基础教程专栏将向大家介绍查看CentOS7版本信息的方法,希望对有需要的人有所帮助!1.检查CentOS的版本号。版本号信息通常存储在配置文件中。在centos...

    2020-12-01
  • Laravel如何在本地构建多站点

    Laravel框架教程下面一栏介绍Laravel在本地搭建多站点,希望对有需要的朋友有所帮助!前言最近有很多想法,想做这个做那个。但是我遇到了一个非常不舒服的问题:所有代码都没...

    2020-12-01
  • Thinkphp6自定义状态代码

    这里thinkphp框架教程专栏介绍TP6自定义状态码的方法,希望对有需要的人有所帮助!在配置目录下创建新的code.php<?phpreturn[';成功';...

    2020-12-01
  • 用Go实现二进制之间的转换

    “本文将介绍使用Go在十进制和二进制之间进行转换“首先你要明白,我们用的数字都是十进制的,二进制只有0和1。然后简单说一下十进制是怎么转换成二进制的。方法1:短除法比如现在需要...

    2020-12-01
热门标签