分析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 相关文章推荐
基于jQuery实现左右div自适应高度完全相同的代码
Aug 09 Javascript
js播放wav文件(源码)
Apr 22 Javascript
IE下window.onresize 多次调用与死循环bug处理方法介绍
Nov 12 Javascript
jQuery中live()方法用法实例
Jan 19 Javascript
检测一个函数是否是JavaScript原生函数的小技巧
Mar 13 Javascript
js立即执行函数: (function ( ){})( ) 与 (function ( ){}( )) 有什么区别?
Nov 18 Javascript
JS获取鼠标坐标并且根据鼠标位置不同弹出不同内容
Jun 12 Javascript
浅谈jquery fullpage 插件增加头部和版权的方法
Mar 20 jQuery
js循环map 获取所有的key和value的实现代码(json)
May 09 Javascript
js中比较两个对象是否相同的方法示例
Sep 02 Javascript
小程序websocket心跳库(websocket-heartbeat-miniprogram)
Feb 23 Javascript
Vue + iView实现Excel上传功能的完整代码
Jun 22 Vue.js
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
模仿OSO的论坛(二)
2006/10/09 PHP
谈谈新手如何学习PHP
2006/12/23 PHP
PHP 图片水印类代码
2012/08/27 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
PHP 并发场景的几种解决方案
2019/06/14 PHP
关于UTF-8的客户端用AJAX方式获取GB2312的服务器端乱码问题的解决办法
2010/11/30 Javascript
script的async属性以非阻塞的模式加载脚本
2013/01/15 Javascript
随窗体滑动的小插件sticky源码
2013/06/21 Javascript
jquery datatable后台封装数据示例代码
2014/08/07 Javascript
微信小程序 http请求详细介绍
2016/10/09 Javascript
Javascript 实现微信分享(QQ、朋友圈、分享给朋友)
2016/10/21 Javascript
Bootstrap轮播图学习使用
2017/02/10 Javascript
webpack热模块替换(HMR)/热更新的方法
2018/04/05 Javascript
vue上传图片到oss的方法示例(图片带有删除功能)
2018/09/27 Javascript
[01:45]IMBATV TI4前线报道-选手到达
2014/07/07 DOTA
[45:50]完美世界DOTA2联赛PWL S3 CPG vs Forest 第二场 12.16
2020/12/17 DOTA
python分布式环境下的限流器的示例
2017/10/26 Python
python 2.7 检测一个网页是否能正常访问的方法
2018/12/26 Python
更新修改后的Python模块方法
2019/03/03 Python
Django对数据库进行添加与更新的例子
2019/07/12 Python
使用Python代码实现Linux中的ls遍历目录命令的实例代码
2019/09/07 Python
使用AJAX和Django获取数据的方法实例
2020/10/25 Python
纽约现代艺术博物馆商店:MoMA STORE(室内家具和杂货商品)
2016/08/02 全球购物
如何利用cmp命令比较文件
2016/04/11 面试题
2014年关于两会精神的心得体会
2014/03/17 职场文书
导师工作推荐信范文
2014/05/17 职场文书
驾驶员安全责任书
2014/07/22 职场文书
医德医风自我评价
2014/09/19 职场文书
涉外离婚协议书怎么写
2014/11/20 职场文书
单位考核聘任报告
2015/03/02 职场文书
出国留学自荐信模板
2015/03/06 职场文书
2015年乡镇环保工作总结
2015/04/22 职场文书
CSS布局之浮动(float)和定位(position)属性的区别
2021/09/25 HTML / CSS
vue使用echarts实现折线图
2022/03/21 Vue.js
python中pycryto实现数据加密
2022/04/29 Python
Win11 21h2可以升级22h2吗?看看你的电脑符不符合要求
2022/07/07 数码科技