首页IT科技js原型和原型链的理解(记录–JS原型链)

js原型和原型链的理解(记录–JS原型链)

时间2025-04-30 21:12:00分类IT科技浏览3536
导读:这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助...

这里给大家分享我在网上总结出来的一些知识          ,希望对大家有所帮助

通过 函数名.–proto– 可以得到 Function.prototape          。通过 函数名.constructor这个属性                  ,可以得到它的构造函数是Function                  。比较巧的是     ,Function的constructor就是它自身       ,Function的–proto–也是它的 Function.prototape     。但是规定                  ,一切函数的prototape的–proto– 指向 Object.prototape        ,即函数名.prototape.–proto–等于Object.prototape

对象的创建

通过new +构造函数    ,比如var obj=new Object() 通过字面量的形式                 ,比如var obj={}           ,这个是JOSN对象的简写       。JOSN是由Object构造的  ,也就是说 JOSN不是函数                ,也就不拥有prototape这个属性              ,JOSN.–proto–为Object.prototape,而不是Function.prototape                  。JOSN.constructor为Object        。Math对象和JOSN一样             ,也是由Object实例的    。那么                 ,Math.constructor也为Object  ,Math.–proto–也为Object.prototape值得注意的是          ,JOSN和Math已经是实例对象了                  ,不可以再new一个实例对象                 。也就是不能new JOSN()和new Math()等     ,这些都是错误的操作       ,这是很多新学者会出错的地方           。

函数的创建

通过函数声明式                  ,如function name(){} 通过函数表达式        ,如let name=function(){} 通过Function实例    ,如let name=new Function().凡事由Function实例的                 ,都是函数

函数的静态属性和方法           ,以及函数的实例属性和方法

静态属性和方法

通过函数名.属性或者方法就是静态属性或者方法  。

上代码
function Son(){} ; Son.age=18; Son.sex="男"; Son.play=function(){ console.log("我会玩游戏"); } Son.sing=function(){ console.log("我会唱歌"); } 要想得到age  ,sex属性以及play(),sing()方法                ,只能通过函数名.属性或者方法使用 如 console.log(Son.age,Son.sex)//18,男 Son.play()//我会玩游戏 Son.sing()//我会唱歌 不能通过new一个对象得到 比如 var son= new Son(); console.log(Son.age,Son.sex)//undefined,undefined son.sing()//son.sing is not a function
实例属性和方法 通过在函数内部              ,用this.属性或者this.方法的就是实例属性或方法 上代码
function Son(name,age,phone){ this.name1=name; this.age=age; this.phone=phone; this.dance=function(){ console.log("我会跳舞") } this.getAge=function(){ return this.age; } } 要想得到age,sex             ,phone属性以及dance(),getAge()方法                 ,只能new一个实例对象  , 然后通过实例对象.属性或者方法使用 如 var son1=new Children("小强","18","苹果"); console.log(son1.name1);//小强 console.log(son1.age);//18 console.log(son1.phone);//苹果 console.log(son1.getAge);//18 son1.dance();//我会跳舞 不能通过函数名.属性或者方法使用 如 console.log(Children.name1);//undefined Children.dance();//Uncaught TypeError: Parent.say is not a function

–proto–属性的例子

–proto–属性          ,指向构造它的函数的prototape属性                。比如

function Son() { } var son=new Son(); console.log( son.__proto__==Son.prototape)//true console.log( Son.__proto__==Function.prototape)//true var obj=new Object()或者 var obj=new Object({})或者var obj={} console.log( obj.__proto__==Object.prototape)//true console.log(Object.__proto__==Function.prototape)//true console.log(Array.__proto__==Function.prototape)//true console.log(JOSN.__proto__==Object.prototape)//true console.log(Math.__proto__==Object.prototape)//true console.log(JOSN.__proto__==Function.prototape)//false console.log(Math.__proto__==Function.prototape)//false console.log(Function.__proto__==Function.prototape)//true 特殊 上述表明                  ,函数的__proto__属性指向的     ,都是Function.prototape       ,而实例对象指向的 是构造函数的prototape属性              。

constructor属性的例子

constructor属性                  ,指向构造它的函数

function Son() { } var son=new Son(); console.log(son.constructor==Son)//true console.log(Son.constructor==Function)//true console.log(Object.constructor==Function)//true console.log(Date.constructor==Function)//true console.log(Math.constructor==Object)//true console.log(JOSN.constructor==Object)//true console.log(Function.constructor==Function)//true 上述表明        ,函数的constructor属性指向的    ,都是Function                 ,而实例对象指向它的构造函数

prototape属性的例子

prototape属性函数特别拥有           ,对象没有这个属性

var obj={} console.log(obj.prototape)//undefined function Son() { } var son=new Son(); console.log(obj.prototape)//undefined console.log(son.prototape)//undefined console.log(Date.prototape)//undefined console.log(JOSN.prototape)//undefined console.log(Object.prototape) //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ,...} console.log(Son.prototape) //{constructor: ƒ} console.log(Function.prototape) //ƒ () { [native code] } 由此可见  ,对象没有这个属性                ,并且              ,prototape的值为对象 我们可以通过prototape.constructor,可以知道这个原型对象的构造函数是谁 console.log(Object.prototape.constructor)//ƒ Object() { [native code] } console.log(Son.prototape.constructor)//ƒ Son() { } console.log(Son.prototape.constructor)//ƒ Function() { [native code] } 我们可以向prototape中添加方法或者属性             ,但一般添加方法                 ,代表这个链上的公共方法  ,个人认为          , 这个方法如果很多对象都用到了                  ,不妨放在Object.prototape中。 Object.prototape.sing=function(){ console.log("我会唱歌"); } Object.prototape.sing()//我会唱歌 首先new 一个实例对象 var son=new Son(); 然后通过实例对象.方法名就可以使用 son.sing();//我会唱歌

原型链

没有改变prototape的原型链

如图

箭头指向它们的方向     ,上述关系(–proto–,constructor,prototape)都在例子中讲解了       ,就不再赘述                  ,这里关注的是原型链             。(备注:本图的JOSN和Math对象不好画在图的左边        ,因此又画了一个Object.prototape原型对象在右边                 。)我们看Son的实例对象    ,为了方便                 ,我写一个var son=new Son()  。通过son.–proto–           ,可以得到Son.prorotape          。如果继续通过链式  ,即son.–proto–.–proto–可以得到Object.prototape                  。我们已经知道了                ,son.–proto–就是为Son.prorotape              ,那么我们通过Son.prorotape.–proto–也可以得到Object.prototape     。也就是说,–proto–能够让我们顺藤摸瓜             ,一直向上查找                 ,这就是原型链(图中已经用红色大边框包裹起来了)       。当我们son.–proto–.–proto–.–proto–(相当于Object.prototape–proto–  ,也相当于Son.prorotape.–proto–.–proto–)时          ,得到null                  ,这说明     ,原型链是有终点的                  。

为什么要原型链?

当我们需要一些方法时       ,别的函数已经有了这些方法                  ,那么我们不需要自己再次造轮子        ,可以通过原型链    ,查找各个父级的prototape属性的值                 ,得到想要的方法        。比如:我们想要让Object的实例对象可以使用sing()方法           ,同时也想让Son的实例对象使用一个sing()方法  ,那么我们就可以通过在Object的原型对象上                ,写上这个sing()共有方法              ,不需要让Son的原型对象上,再写下这个sing()方法    。

Object.prototape.sing=function(){ console.log("我会唱歌"); } 首先new 一个实例对象 var son=new Son(); 然后通过实例对象.方法名就可以使用 son.sing();//我会唱歌
所以             ,通过原型链                 ,可以让我们少些一些相同的代码                 。我们只需要把相同的方法放在父级上  ,就不必自己重写一个;除此之外          ,如果我们这个实例对象的构造函数如果没有这个方法                  ,那么这个实例对象会依次向原型链查找     ,直到查找到Object.prototape为止       ,如果还没有找到                  ,那就终止        ,并且报错           。如果这个构造函数有这个方法    ,那么按照构造函数的来                 ,而不是父级的prototape里面的方法  。这说明           ,存在一定的优先级  ,我们需要注意                。 改变了prototape的值原型链

如图

我们已经知道了prototape的值是一个对象                ,那么我让prototape的值等于一个实例对象              ,会怎么样?

如上图所示,即Son.prototape=new Parent()              。我们试着打印一下Son.prototape的值             ,console.log(Son.prototape)//Parent {},显示是parent的实例对象                 ,再试着打印console.log(Son.prototape.constructor)//function Parent(){},发现竟然是Parent  ,你会心想          ,这就不合理了。我应该指向Son才对啊             。这里我做出解释                  ,因为我们是将Son.prototape重新赋值了     ,将原本的对象覆盖了       ,即地址发生了变化                 。现在的地址和之前的地址不是同一个地址(对象的重新赋值                  ,会改变地址)        ,那么大家是不是瞬间清楚了  。同时    ,这也说明了                 ,Son.prototape.constructor继承Parent.prototape.constructor           ,我相信这下子大家都清楚了  ,说明constructor也可以继承          。为了解决这种问题                ,我们必须让Son.prototape.constructor重新指向Son              ,所以Son.prototape.constructor=Son,这样子             ,console.log(Son.prototape.constructor)//function Son(){}就解决问题了                  。之后通过–proto–与没有改变prototape的原型链是一样的                 ,只不过Son.prototape.–proto–为Parent.prototape     。那么  ,我们new 一个Son的实例对象          ,有
var son=new Son(); console.log(son.--proto--)//Son.prototape console.log(son.--proto--.--proto--)//Parent.prototape console.log(son.--proto--.--proto--.--proto--)//Object.prototape console.log(son.--proto--.--proto--.--proto--.--proto--)//null console.log(Son.prototape.--proto--)//Parent.prototape console.log(Son.prototape.--proto--.--proto--)//Object.prototape console.log(Son.prototape.--proto--.--proto--.--proto--)//null console.log(Patent.prototape.--proto--)//Object.prototape console.log(Patent.prototape.--proto--.--proto--)//null console.log(Object.prototape.--proto--)//null
并不是说                  ,只有一个函数的prototape的值可以更改     ,我们还可以更改很多函数的prototape值       。比如Parent的prototape的值       ,让Parent.prototape=new Grandparent又加了一个父级                  ,多出来一条链                  。有兴趣的        ,可以去试试        。

本文转载于:

https://juejin.cn/post/7101887288652595230

如果对您有所帮助    ,欢迎您点个关注                 ,我会定时更新技术文档           ,大家一起讨论学习  ,一起进步    。

声明:本站所有文章                ,如无特殊说明或标注              ,均为本站原创发布                 。任何个人或组织,在未征得本站同意时             ,禁止复制            、盗用               、采集      、发布本站内容到任何网站         、书籍等各类媒体平台           。如若本站内容侵犯了原著者的合法权益                 ,可联系我们进行处理  。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
crystaldiskinfo下载官网(MAC OS X 10.9.X下用命令行开启SSD trim的方法汇总) mac 更改用户名称(Mac修改用户名图文教程 如何修改MAC用户名)