分析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实现用户注册的表单验证示例
Aug 28 Javascript
javascript数组操作(创建、元素删除、数组的拷贝)
Apr 07 Javascript
ES6中的数组扩展方法
Aug 26 Javascript
AngularJs Managing Service Dependencies详解
Sep 02 Javascript
jQuery Ajax请求后台数据并在前台接收
Dec 10 Javascript
jQuery实现的粘性滚动导航栏效果实例【附源码下载】
Oct 19 jQuery
浅谈Vue2.0父子组件间事件派发机制
Jan 08 Javascript
详解Vue快速零配置的打包工具——parcel
Jan 16 Javascript
使用sessionStorage解决vuex在页面刷新后数据被清除的问题
Apr 13 Javascript
JS实现集合的交集、补集、差集、去重运算示例【ES5与ES6写法】
Feb 18 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 Javascript
vuex Module将 store 分割成模块的操作
Dec 07 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
图书管理程序(二)
2006/10/09 PHP
用PHP和ACCESS写聊天室(二)
2006/10/09 PHP
CI(CodeIgniter)模型用法实例分析
2016/01/20 PHP
PHP实现RSA签名生成订单功能【支付宝示例】
2017/06/06 PHP
jquery 跨域访问问题解决方法(笔记)
2011/06/08 Javascript
javascript温习的一些笔记 基础常用知识小结
2011/06/22 Javascript
extjs表格文本启用选择复制功能具体实现
2013/10/11 Javascript
使用Js让Html中特殊字符不被转义
2013/11/05 Javascript
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现
2015/03/05 Javascript
Javascript removeChild()删除节点及删除子节点的方法
2015/12/27 Javascript
jQuery遮罩层效果实例分析
2016/01/14 Javascript
分享一个插件实现水珠自动下落效果
2016/06/01 Javascript
浅谈JavaScript前端开发的MVC结构与MVVM结构
2016/06/03 Javascript
jQuery插件Echarts实现的双轴图效果示例【附demo源码下载】
2017/03/04 Javascript
jsonp跨域请求详解
2017/07/13 Javascript
微信小程序 按钮滑动的实现方法
2017/09/27 Javascript
妙用缓存调用链实现JS方法的重载
2018/04/30 Javascript
element-ui表格合并span-method的实现方法
2019/05/21 Javascript
jQuery 选择方法及$(this)用法实例分析
2020/05/19 jQuery
VUE异步更新DOM - 用$nextTick解决DOM视图的问题
2020/11/06 Javascript
python中精确输出JSON浮点数的方法
2014/04/18 Python
python使用装饰器和线程限制函数执行时间的方法
2015/04/18 Python
pandas 获取季度,月度,年度首尾日期的方法
2018/04/11 Python
python实现对文件中图片生成带标签的txt文件方法
2018/04/27 Python
python实现Virginia无密钥解密
2019/03/20 Python
pyqt 多窗口之间的相互调用方法
2019/06/19 Python
Python 3.6 -win64环境安装PIL模块的教程
2019/06/20 Python
Python tkinter实现图片标注功能(完整代码)
2019/12/08 Python
django实现模型字段动态choice的操作
2020/04/01 Python
canvas离屏技术与放大镜实现代码示例
2018/08/31 HTML / CSS
企业管理毕业生求职信范文
2014/03/07 职场文书
父母寄语大全
2014/04/12 职场文书
个人纪律作风整改措施思想汇报
2014/10/12 职场文书
党的群众路线教育实践活动个人整改措施
2014/10/27 职场文书
2015年创先争优活动总结
2015/03/27 职场文书
MySQL Server 层四个日志
2022/03/31 MySQL