设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2635|回复: 3
打印 上一主题 下一主题

[原创发布] 简明易懂的原型和原型链教程

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1912
在线时间
1554 小时
注册时间
2013-4-13
帖子
917
跳转到指定楼层
1
发表于 2016-8-26 14:45:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 沉滞的剑 于 2016-8-26 15:03 编辑

原型是js和c++之类面向对象的语言本质区别所在。
在js中一切都是对象,js本身并没有类这样的概念,与其说一个对象是类的一个实例,不如说一个对象是另一个对象的克隆。
具体的,就需要了解prototype属性和__proto__属性了。

1.Function 对象

函数对象是很特殊的一类对象, 它比一般的Object对象多出来很多属性。
对比一下:
例子1:
JAVASCRIPT 代码复制
  1. var fun = new Function();
  2. var obj = new Object();

用控制台就能发现Function对象拥有比Object对象更多的成员。
那这些多出来的成员是从哪里来的呢?当然是从Function对象那里找来的。
在new Function的时候fun肯定从Function那里克隆了一部分内容。
但是,它是克隆的Function的成员么?乍一看上去Function的成员和fun的成员是一致的,
但其实真正的源头是Function.prototype,用控制台查看Function.prototype的话就会发现这面也有和Function一样的成员。
推理一下,如果拷贝的是Function的话,那么fun也应该有何Function一样的prototype,但结果fun的prototype是空的。
所以说fun在创造的时候是从Function.prototype处拷贝的成员。
那么如果这个推理是正确的,那么对其他函数对象(比如fun)来说这个克隆规则也一样适用。
例子2:
JAVASCRIPT 代码复制
  1. var people = new Function();
  2. people.age = 80;
  3. people.prototype.age = 24;
  4. var li = new people();
  5. li.age;

输出: 24;
结论: a = new b的时候, a会拷贝b的prototype属性中的成员

2. new的原理
那么我们可以分析一下new的工作原理
1. fun拷贝了Function.prototype里的成员
2. fun修改了这些成员方法中的this指针(这些方法的指针原先是指向Function.prototype的,现在指向了fun)
3. fun执行了构造器中的内容比如:
JAVASCRIPT 代码复制
  1. var people = function(age){this.age = age};
  2. people.age = 80;
  3. people.prototype.age = 24;
  4. var li = new people(44);
  5. li.age;

那么new出来的成员和原本的成员有关系么
例子3:
JAVASCRIPT 代码复制
  1. var people = new Function();
  2. people.age = 80;
  3. people.prototype.age = 24;
  4. var li = new people();
  5. console.log(li.age);
  6. li.age = 10;
  7. console.log(people.prototype.age);
  8. people.prototype.age = 30;
  9. console.log(li.age);

输出: 24,24,10
例子4:
JAVASCRIPT 代码复制
  1. var people = new Function();
  2. people.age = 80;
  3. people.prototype.makeCall = function(){console.log('Hello')};
  4. people.prototype.makeCall2 = function(){console.log('Hello 2')};
  5. var li = new people();
  6. li.makeCall = function(){console.log('Hello 3')};
  7. li.makeCall();
  8. people.prototype.makeCall();
  9. people.prototype.makeCall2 = function(){console.log('Hello 4')};
  10. li.makeCall2();

输出:Hello 3, Hello, Hello 4;
结论: 通过上面两个例子你会发现,对于在li中重新定义过的成员(比如 makeCall和age)不会受到people.prototype改变的影响
而未在li中定义过的成员MakeCall2就依然会跟随者people.prototype的改变而改变。
那这是为什么呢?拷贝的和重新定义的属性有什么不同呢?

3.原型链
先介绍一个函数:hasOwnProperty, 这个函数用来判断一个成员是否是这个对象自有的。
例子5:
JAVASCRIPT 代码复制
  1. li.hasOwnProperty('makeCall2');
  2. li.hasOwnProperty('makeCall');

输出: false, true;
结论: 显然, makeCall2并没有真正复制到了li上,而只是被li引用了而已。
那么js又是怎么找到makeCall2的呢?
这就要谈到__proto__属性了。
所有的对象都有一个__proto__属性。
在函数对象的情形下li.__proto__ 可以等价于 people.prototype
当你访问li的一个成员的时候,js首先会在li的所有自有的成员中寻找。
比如你在寻找MakeCall2, 但是li并没有这个成员。
那么js则会转到li.__proto__里去寻找
假设还没找到则会到li.__proto__.__proto__里寻找,一直到找到或找不到为止。
这就是js最重要的原型链的原理。


结论:
1.a = new b 拷贝的是b.prototype的属性而不是b的属性
2.a = new b 会导致 a.__proto == b.prototype,__proto__代表了对象的原型, 如果在对象中找不到指定的成员, js会在对象的原型中寻找。
夏普的道具店

塞露提亚-道具屋的经营妙方同人作品
发布帖:点击这里

Lv1.梦旅人

梦石
0
星屑
220
在线时间
161 小时
注册时间
2015-11-23
帖子
92
2
发表于 2016-8-26 17:59:53 | 只看该作者
好棒的教程,顶一个
自天地未辟混沌未开时就已经开始装逼的神奇人物
MV的魔塔模板::托管在github上的游戏,可以直接运行
基于RPGMakerMV的JavaScript基础
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1232
在线时间
1017 小时
注册时间
2011-4-30
帖子
1516
3
发表于 2016-8-27 20:55:50 手机端发表。 | 只看该作者
好教程。讲的很清楚
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
55
在线时间
69 小时
注册时间
2008-3-2
帖子
29
4
发表于 2016-10-6 16:32:56 | 只看该作者
绝对的精品教程!之前在网上找了很多关于prototype的教程,没有任何一篇比楼主说得通俗易懂!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-12-20 03:13

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表