js原型链结构理解
在一般的面向对象的语言中,都存在类(class)的概念,类就是对象的模板,对象就是类的实例。
但在js中是没有类的定义的(万物皆是对象)。 题外话:但是在ES6中提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
为了在对象直接建立联系(如继承),起初通过构造函数(constructor)实现。但是构造函数存在一个弊端,那就是同一个对象实例之间,无法共享属性。如下:
function Person(name,height){
this.name=name;
3 this.height=height;
this.hobby=function(){
return 'watching movies';
}
}
var boy=new Person('aa',180);
var girl=new Person('bb',153);
console.log(boy.name); //'aa'
console.log(girl.name); //'bb'
console.log(boy.hobby===girl.hobby); //false
上面代码中boy和girl的hobby方法是不一样的。也就是说,每当你使用new来调用构造函数放回一个对象实例的时候,都会创建一个hobby方法。这既没有必要,又浪费资源,因为所有hobby方法都是同样的行为,完全可以被两个对象实例共享。
为了解决构造函数的对象实例之间无法共享属性的缺点,js提供了prototype属性,即引入了原型链的概念。
下面我们进入正题:
原型即构造函数的prototype属性,对于该构造函数的实例通过__proto__来访问。对于构造函数来说,它是一个属性,对于对象实例来说,它是一个原型对象。
首先明确: 函数(Function)才有prototype属性,对象(除Object)只拥有__proto__。
关于构造函数、实例、原型直接的关系,话不多说,直接上图:
其中要说明的是Function是js中的一等公民,所有函数都是Function的实例:
①本地对象:独立于宿主环境(浏览器)的对象——包括Object、Array、Date、RegExp、Function、Error、Number、String、Boolean
②内置对象——包括Math、Global(window,在js中就是全局变量),使用的时候不需要new
③宿主对象——包括自定义对象、DOM、BOM
理解完结构之后,来看代码:
function Person(name,height){
this.name=name;
this.height=height;
}
Person.prototype.hobby=function(){
return 'watching movies';
}
var boy=new Person('aa',180);
var girl=new Person('bb',153);
console.log(boy.name); //'aa'
console.log(girl.name); //'bb'
console.log(boy.hobby===girl.hobby); //true
将hobby方法放在原型对象上,那么两个实例对象都共享着同一个方法。
其中原型对象的属性不是对象实例的属性。对象实例的属性是继承自构造函数定义的属性,因为构造函数内部有一个this关键字来指向将要生成的对象实例。
对象实例的属性,其实就是构造函数内部定义的属性。只要修改原型对象上的属性和方法,变动就会立刻体现在所有对象实例上。
原型链(prototype chains)
对象的属性和方法,有可能是定义在自身,也有可能是定义在它的原型对象。由于原型对象本身对于对象实例来说也是对象,它也有自己的原型,所以形成了一条原型链(prototype chain)。
即通过图片最右侧的线路fun --> Fun()的prototype --> Object的prototype
所有一切的对象的原型顶端,都是Object.prototype,即Object构造函数的prototype属性指向的那个对象。
当然,Object.prototype对象也有自己的原型对象,那就是没有任何属性和方法的null对象,而null对象没有自己的原型。
console.log(Object.getPrototypeOf(Object.prototype)); //null getPrototypeOf用来返回对象Objiect.prototype指向的原型(即Object.prototype.__proto__)
console.log(Person.prototype.isPrototypeOf(boy)) //true isPrototypeOf用来判断Person.prototype是否在boy的原型链(不单单只上一个原型)上
原型链(prototype chain)的特点有:
a:读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
b:如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。
c:一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
还有一个问题就是原型是如何产生的呢?其实就是通过new关键字来实现的。
此处应该明确函数(Function)才有prototype属性,对象(除Object)只拥有__proto__。
这就是自定义的构造函数的实例没有prototype属性的原因,个人认为是Function在定义时内部就写好了protoytpe属性(这个一个对象)供其实例继承。
下面就是new关键字进行的操作:
var obj = {};
obj.__proto__ = Base.prototype; //我们将这个对象obj的__proto__成员指向了构造函数Base对象的prototype属性(成员对象)
Base.call(obj); //当通过原型链调用到Base对象的prototype成员对象中的属性时,this指针仍执行obj
结构学习完毕,其作用以及利用其实现多种继承方式的功能还在学习中。
个人总结日志,若有相似之处,是因为您文章写的特别好,学习借鉴了一下,还忘见谅。
js原型链结构理解的更多相关文章
- 谈谈我对 js原型链的理解
想要学习 “原型链” 必须要认识什么是 “原型” 和 “原型链” 先理解一下普通的继承和原型的区别,下面写一段js代码来帮助理解: var Animal = function(){ // 动物抽象类 ...
- js原型链结构与链表结构对比
在结构上多一个指向自身的constructor构造函数,这就是原型链够简单吧. 利用原型链结构实现继承和向链表中插入节点,有区别吗? 没区别!!
- JS原型链的理解和使用(一)
一些个人的理解,不一定是对的,仅供参考. 在JS中有函数和对象两个概念,而又有一切皆对象的概念及函数也是一个对象.所以可以说函数一定可以作为一个对象,而对象不一定是一个函数. 也可以说在js中对象分为 ...
- JS原型链的理解和使用(二)
根据在创建对象的时候,创建出来的对象的__proto__指向创建这个对象的函数的prototype属性. 由于在调用对象的属性或者方法的时候会首先在对象的作用域中查找指定的属性或者方法,如果未找到则会 ...
- 分享一个关于js原型链的理解
http://www.cnblogs.com/wyaocn/p/5815761.html
- js原型链理解(2)--原型链继承
1.原型链继承 2.constructor stealing(构造借用) 3.组合继承 js中的原型链继承,运用的js原型链中的__proto__. function Super(){ this.se ...
- 深入理解JS原型链与继承
我 觉得阅读精彩的文章是提升自己最快的方法,而且我发现人在不同阶段看待同样的东西都会有不同的收获,有一天你看到一本好书或者好的文章,请记得收藏起来, 隔断时间再去看看,我想应该会有很大的收获.其实今天 ...
- 简单粗暴地理解js原型链–js面向对象编程
简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...
- JS原型链简单图解
JS中原型链,说简单也简单. 首先明确: 函数(Function)才有prototype属性,对象(除Object)拥有__proto__. 首先,我画了一张图. 所谓原型链,指的就是图中的proto ...
随机推荐
- 傻瓜式教学--win10 + frp + rdpwrap + 阿里云服务器 --实现win10 多用户同时远程登录内网机
概述: 使用win10 专业版 + frp + RDPwrap + 阿里云服务器 的组合实现win10 多用户同时远程登录内网机.使用frp 做内网穿透,将内网机的指定端口暴露在外网,通过ip+por ...
- MySQL8.0窗口函数实践及小结
MySQL8.0之前,做数据排名统计等相当痛苦,因为没有像Oracle.SQL SERVER .PostgreSQL等其他数据库那样的窗口函数.但随着MySQL8.0中新增了窗口函数之后,针对这类统计 ...
- js基础练习题(2)
5.函数 1.按要求封装两个函数 1.封装一个函数,要求输入字符串转化成数组弹出 2.封装一个函数,要求能求出三个数中的最小值,注意:不准使用js内置函数 2.封装一个函数,求参数的和,注意:参数不固 ...
- fatal error C1189: #error : This file requires _WIN32_WINNT to be #defined at least to 0x0403. Value 0x0501 or higher is recommended.
说了原因,下面是修改方法,就是在stdafx.h文件中修改相关的定义,修改完后的效果应该如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #ifndef WINVER ...
- mybatis源码配置文件解析之五:解析mappers标签
在上篇博客中分析了plugins标签,<mybatis源码配置文件解析之四:解析plugins标签>,了解了其使用方式及背后的原理.现在来分析<mappers>标签. 一.概述 ...
- 客官,来看看AspNetCore的身份验证吧
开篇 这段时间潜水了太久,终于有时间可以更新一篇文章了. 通过本篇文章您将Get: Http的一些身份验证概念 在AspNetCore中实现身份验证方案 JWT等概念的基础知识 使用Bearer To ...
- 缺少对公共可见类型或成员的XML注释
最近突然心血来潮,想清理下代码,结果看到了一堆这样的警告——缺少对公共可见类型或成员“XXX”的 XML 注释: 其实要想取消上面的警告,仅仅需要在项目属性里找到生成页签里的”错误和警告“项,在禁止显 ...
- 【学习随手记】kubeadm 查看创建集群需要的镜像版本,附拉取镜像脚本
查看创建集群需要的镜像版本 kubeadm config images list [--kubernetes-version <version>] 国内拉取镜像脚本 一般而言,直接使用ku ...
- Netty系列之源码解析(一)
本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 当前:Netty 源码解析(一)开始 Netty 源码解析(二): Netty 的 Channel ...
- P2034 选择数字——线性dp(单调队列优化)
选择数字 题目描述 给定一行 \(n\) 个非负整数 \(a[1]...a[n]\) .现在你可以选择其中若干个数,但不能有超过 \(k\) 个连续的数字被选择.你的任务是使得选出的数字的和最大. 输 ...