分析javascript原型及原型链


Posted in Javascript onMarch 18, 2018

我们创建的每个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个原型对象,而这个原型对象中拥有的属性和方法可以被所以实例共享。

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

一、理解原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象。

在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。

当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262 第 5 版中管这个指针叫 [[Prototype]] 。

虽然在脚本中没有标准的方式访问 [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每个对象上都支持一个属性__proto__ ;而在其他实现中,这个属性对脚本则是完全不可见的。

不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

以前面使用 Person 构造函数和 Person.prototype 创建实例的代码为例,图 6-1 展示了各个对象之间的关系。

分析javascript原型及原型链

在此, Person.prototype 指向了原型对象,而 Person.prototype.constructor 又指回了 Person 。

person1 和 person2 都包含一个内部属性,该属性仅仅指向了 Person.prototype ;换句话说,它们与构造函数没有直接的关系。

可以调用 person1.sayName() 。这是通过查找对象属性的过程来实现的。(会先在实例上搜索,如果搜索不到就会继续搜索原型。)

用isPrototypeOf()方法判断实例与原型对象之间的关系
alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true用Object.getPrototypeOf() 方法返回实例的原型对象
alert(Object.getPrototypeOf(person1) == Person.prototype); //true
使用 hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是存在于原型中。
alert(person1.hasOwnProperty("name")); //false
来着原型
person1.name = "Greg";
alert(person1.name); //"Greg"——来自实例
alert(person1.hasOwnProperty("name")); //true

二、更简单的原型语法

前面例子中每添加一个属性和方法就要敲一遍 Person.prototype 。为减少不必要的输入,也为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象。

function Person(){
}
Person.prototype = {
name : "Nicholas",

age : 29,

job: "Software Engineer",

sayName : function () {


alert(this.name);

}
};

在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外: constructor 属性不再指向 Person 了。

前面曾经介绍过,每创建一个函数,就会同时创建它的 prototype 对象,这个对象也会自动获得 constructor 属性。

var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true

在此,用 instanceof 操作符测试 Object 和 Person 仍然返回 true ,但 constructor 属性则等于 Object 而不等于 Person 了。

如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。

function Person(){
}
Person.prototype = {
  constructor : Person,
  name : "Nicholas",
  age : 29,
  job: "Software Engineer",
  sayName : function () {
    alert(this.name);
  }
};

三、原生对象的原型

所有原生引用类型( Object 、 Array 、 String ,等等)都在其构造函数的原型上定义了方法。

例如,在 Array.prototype 中可以找到 sort() 方法,而在 String.prototype 中可以找到substring() 方法。尽管可以这样做,但不推荐修改原生对象的原型。

四、原型对象的问题

原型模式的最大问题是由其共享的本性所导致的。 修改其中的一个,另一个也会受影响。

function Person(){
}
Person.prototype = {
constructor: Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
friends : ["Shelby", "Court"],
sayName : function () {
alert(this.name);
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true

五、原型链

其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。然后层层递进,就构成了实例与原型的链条,这就是所谓原型链的基本概念。

function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){

return this.property;
};
function SubType(){

this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){

return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true

 一张图说明:

分析javascript原型及原型链

property 则位于 SubType.prototype 中。这是因为 property 是一个实例属性,而 getSuperValue() 则是一个原型方法。既然 SubType.prototype 现在是 SuperType的实例,那么 property 当然就位于该实例中了。

Javascript 相关文章推荐
javascript 添加和移除函数的通用方法
Oct 20 Javascript
防止xss和sql注入:JS特殊字符过滤正则
Apr 18 Javascript
JavaScript实现的一个日期格式化函数分享
Dec 06 Javascript
jQuery实现获取绑定自定义事件元素的方法
Dec 02 Javascript
基于JQuery打造无缝滚动新闻步骤详解
Mar 31 Javascript
关于backbone url请求中参数带有中文存入数据库是乱码的快速解决办法
Jun 13 Javascript
如何用js实现鼠标向上滚动时浮动导航
Jul 18 Javascript
Ionic默认的Tabs模板使用实例
Aug 29 Javascript
JS+canvas绘制的动态机械表动画效果
Sep 12 Javascript
javascript自定义事件功能与用法实例分析
Nov 08 Javascript
koa源码中promise的解读
Nov 13 Javascript
Vue实现购物车的全选、单选、显示商品价格代码实例
May 06 Javascript
jquery 实现拖动文件上传加载进度条功能
Mar 18 #jQuery
jQuery中each方法的使用详解
Mar 18 #jQuery
JavaScript中字符串的常用操作方法及特殊字符
Mar 18 #Javascript
js中DOM事件绑定分析
Mar 18 #Javascript
js中如何完美的解析数据
Mar 18 #Javascript
解决使用vue.js路由后失效的问题
Mar 17 #Javascript
vue实现的上传图片到数据库并显示到页面功能示例
Mar 17 #Javascript
You might like
第三节 定义一个类 [3]
2006/10/09 PHP
PHP怎样调用MSSQL的存储过程
2006/10/09 PHP
Windows PHP5和Apache的安装与配置
2009/06/08 PHP
PHP+MySQL 制作简单的留言本
2009/11/02 PHP
php feof用来识别文件末尾字符的方法
2010/08/01 PHP
PHP中实现生成静态文件的方法缓解服务器压力
2014/01/07 PHP
php数组合并的二种方法
2014/03/21 PHP
两种php给图片加水印的实现代码
2020/04/18 PHP
判断、添加和删除WordPress置顶文章的相关PHP函数小结
2015/12/10 PHP
jQuery之选项卡的简单实现
2014/02/28 Javascript
node.js中的socket.io入门实例
2014/04/26 Javascript
jQuery切换网页皮肤并保存到Cookie示例代码
2014/06/16 Javascript
js实现可得到不同颜色值的颜色选择器实例
2015/02/28 Javascript
JS实现部分HTML固定页面顶部随屏滚动效果
2015/12/24 Javascript
thinkphp标签实现bootsrtap轮播carousel实例代码
2017/02/19 Javascript
node操作mysql数据库实例详解
2017/03/17 Javascript
JavaScript中使用参数个数实现重载功能
2017/09/01 Javascript
JavaScript中的一些隐式转换和总结(推荐)
2017/12/22 Javascript
JS实现延迟隐藏功能的方法(类似QQ头像鼠标放上展示信息)
2017/12/28 Javascript
解决vue 项目引入字体图标报错、不显示等问题
2018/09/01 Javascript
Vue项目部署的实现(阿里云+Nginx代理+PM2)
2019/03/26 Javascript
微信小程序Page中data数据操作和函数调用方法
2019/05/08 Javascript
详解wepy开发小程序踩过的坑(小结)
2019/05/22 Javascript
[53:52]OG vs EG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
Python中用于转换字母为小写的lower()方法使用简介
2015/05/19 Python
Python二分查找详解
2015/09/13 Python
Python语言描述最大连续子序列和
2017/12/05 Python
python OpenCV学习笔记实现二维直方图
2018/02/08 Python
Django 创建/删除用户的示例代码
2019/07/24 Python
党员批评与自我批评思想汇报(集锦)
2014/09/14 职场文书
公司合并协议书范本
2014/09/30 职场文书
成绩单评语
2015/01/04 职场文书
女性健康知识讲座通知
2015/04/23 职场文书
Nginx的rewrite模块详解
2021/03/31 Servers
python中super()函数的理解与基本使用
2021/08/30 Python
详细介绍Java中的CyclicBarrier
2022/04/13 Java/Android