原型链的理解是javascript中的老大难题,对于初学者非常不友好,甚至对于很多工作两三年的程序员来说,也没能真正理解javascript中的原型链的精妙设计!
我们想要理解原型链,首先我们先要跳出原型链的直接讲解,
因为javascript中的原型链其实涉及到一个javascript的本源设计
,就是我们先要探讨一下为什么javascript要设计原型链,并且javacript这门语言其实是没有原型链也能完美执行并且保持图灵完备的。
首先我们看一下一个风靡世界的游戏 英雄联盟LOL 的英雄制作过程我们用javascrip描述 以下 英雄薇恩(vn)。
此时我们用javascript中的对象来模拟英雄联盟中的英雄的功能和属性。
var hero = {
heroName:'vn',
heroLife:'95%',
Q(){
//闪避突袭 复杂处理函数省略 console.log代替过程
console.log('闪避突袭 薇恩翻滚到合适位置,为下次攻击做好准备。她的下次攻击造成额外伤害。')
},
W(){
//圣银弩箭 复杂处理函数省略 console.log代替过程
console.log('闪避突袭 圣银弩箭 薇恩用稀有金bai制作箭弩,让邪恶敌人中毒。对同一目标的第3次攻击或技能施放会对其造成额外真实伤害,数值相当于目标最大生命值一定百分比。(对怪物最多造成200伤害')
},
E(){
//恶魔审判 复杂处理函数省略 console.log代替过程
console.log('恶魔审判 薇恩从背后拿出重弩,朝目标发射巨箭,对其造成伤害并击退他们。如果在击退过程中碰撞墙或者地形边缘,目标将受到额外伤害并晕眩。')
},
R(){
//决战时刻 复杂处理函数省略 console.log代替过程
console.log('决战时刻 誓死一战。她获得额外攻击力,在闪避突袭期间潜行,暗夜猎手(被动)生效时加速效果提高3倍。')
}
}
好, 以上是一个英雄的对象定义, 英雄联盟中有一个模式叫做 :克隆模式
游戏玩法界面是这样的, 以下是十个英雄薇恩
十个一样的英雄同场作战, 甚至私服 mod 可以容纳更多的英雄, 我们用代码来描述一下!
var heros = []
var hero
for (var i = 0; i<10; i++) {
var heroVn = {
heroName:'vn',
heroLife:'95%',
Q(){
//闪避突袭 复杂处理函数省略 console.log代替过程
console.log('闪避突袭 薇恩翻滚到合适位置,为下次攻击做好准备。她的下次攻击造成额外伤害。')
},
W(){
//圣银弩箭 复杂处理函数省略 console.log代替过程
console.log('闪避突袭 圣银弩箭 薇恩用稀有金bai制作箭弩,让邪恶敌人中毒。对同一目标的第3次攻击或技能施放会对其造成额外真实伤害,数值相当于目标最大生命值一定百分比。(对怪物最多造成200伤害')
},
E(){
//恶魔审判 复杂处理函数省略 console.log代替过程
console.log('恶魔审判 薇恩从背后拿出重弩,朝目标发射巨箭,对其造成伤害并击退他们。如果在击退过程中碰撞墙或者地形边缘,目标将受到额外伤害并晕眩。')
},
R(){
//决战时刻 复杂处理函数省略 console.log代替过程
console.log('决战时刻 誓死一战。她获得额外攻击力,在闪避突袭期间潜行,暗夜猎手(被动)生效时加速效果提高3倍。')
}
}
heros.push(heroVn)
}
//制造出了十个英雄vn
console.log(heros)
这样设计其实是没问题的, 英雄的技能组成, 以及思路都是没问题,但是这样设计游戏人物有j几个重大的缺陷!!!!
- 这种代码存在一个巨大的缺陷不利于商业化,可以观察到这十个英雄唯一在游戏中不同的只是 heroLife(玩家受到的伤害不用生命值显示不同,会根据玩家受到的伤害不同而减少, 每个玩家的生命值在游戏中都是动态变化的。
- heroName(英雄名字) 以及英雄的四个技能 Q W E R 十个英雄, 都是一样的。没必要重复创造十次,去占据内存, 白白消耗用户的机器性能。
- 只有heroLife 英雄的血量根据游戏的过程受到的伤害不同而动态改变,那样就得想一个办法,让这个英雄共用heroName 以及Q W E R 以达到节约内存的效果!
我们将代码进行改进
//共有属性
var vn = function(){
}
vn.prototype = {
heroName:'vn',
Q(){
//闪避突袭 复杂处理函数省略 console.log代替过程
console.log('闪避突袭 薇恩翻滚到合适位置,为下次攻击做好准备。她的下次攻击造成额外伤害。')
},
W(){
//圣银弩箭 复杂处理函数省略 console.log代替过程
console.log('闪避突袭 圣银弩箭 薇恩用稀有金bai制作箭弩,让邪恶敌人中毒。对同一目标的第3次攻击或技能施放会对其造成额外真实伤害,数值相当于目标最大生命值一定百分比。(对怪物最多造成200伤害')
},
E(){
//恶魔审判 复杂处理函数省略 console.log代替过程
console.log('恶魔审判 薇恩从背后拿出重弩,朝目标发射巨箭,对其造成伤害并击退他们。如果在击退过程中碰撞墙或者地形边缘,目标将受到额外伤害并晕眩。')
},
R(){
//决战时刻 复杂处理函数省略 console.log代替过程
console.log('决战时刻 誓死一战。她获得额外攻击力,在闪避突袭期间潜行,暗夜猎手(被动)生效时加速效果提高3倍。')
}
}
var heros = []
var vn1
for (var i = 0; i<10; i++) {
vn1 = {
heroLife:'初始100后续会根据每个英雄受到伤害不同动态变化'
}
vn1.__proto__ = vn.prototype
}
好了, 通过以上的改进, 我们就达到我们的目的, 英雄的生命值属于, 每一个唯一id的英雄, 但是英雄的共有属性不在占据独有的内存空间 而是去指向共有的英雄属性不在白白浪费内存空间了!这也是原型链设计的最终目的以及初衷!
但是这样的写法, 很拗口也很难理解, JS的官方组织也有意去弱化这个设计,让不知道这个设计的程序员也可以很好的使用这个功能去节约内存,然后就有了new 操作符!
new操作符实际上只做了四步
- 新生成一个对象
- 链接到原型
- 绑定 this
- 返回新的对象
以下代码演示, 被隐藏的这一步
var 临时对象 = {}
临时对象.__proo__ = vn.prototype
//this赋值和指向
临时对象.heroLife = heroLife
return 回去这个临时对象
你可以理解成: 是把上面的详细代码的过程给你隐藏, 直接让你得到一个绑定好原型链不占用内存的一个新的对象。此例中是英雄vn。
而实际上的原型链是一个为了不占用内存空间而寻祖的过程我们再通过一幅图来很好的理解原型链!
上图可以看到, 孙悟空、 六耳猕猴用的技能实际上是菩提老祖创造出来的,他们的共有属性是__proto__连接 ,对菩提老祖是一种寻祖的过程。
至于原型链的尽头为什么是null, 这里就要设计到一种哲学思想了,
宇宙大爆炸之前宇宙也是null,盘古开天地以来天地也是null,所以原型链也是javascript的世界观!
总结
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!