【JavaScript高级02】JavaScript第一大神兽:原型和原型链
1,函数中的prototype属性
每个函数都会有一个属性prototy,该属性默认指向一个空Object对象,而这个空的Object对象被称之为原型对象。
 <script >
    console.log(typeof Date.prototype);
</script>打印结果:
会发现,Date的prototype中定义了很多的空方法,用于表示Date的结构,该Object并不是一个空的,使用es定义的,这也说明了,在默认情况指向一个空的原型对象。该情况如下所示:
<script >
    function fun(){}
    console.log(fun.prototype,typeof fun.prototype);
</script>打印结果为:
会发现,在这个fun函数中的Object原型对象中,只有两个属性,该两个属性为系统定义的,之后并无其他属性。可以看做是一个空的Object对象。该原型对象有一个属性constructor,指向它的函数对象。还有一个属性叫做__proto__,这个属性后面细说。向看看原型对象的的constructor属性是否指向函数对象。
<script >
  function fun(){}
  console.log(fun.prototype.constructor===fun,Date.prototype.constructor===Date);
</script>打印结果为:
结果都为true,表示是对的。
综合上述可以得出:一个函数都会有一个prototype对象,该对象默认指向一个空Object对象,称其为原型对象。在系统(js)定义的函数中,指向的原型对象不是空的,而是定义了很多的空方法,表示该函数的结构。在原型对象中有个属性为constructor,该属性指向其函数,示例图如下所示。
我们可以在原型对象中添加属性,一般情况我们只添加方法(变量也可以添加)。
<script >
    function Fun(){}
   fun.prototype.text=function(){
    console.log("ha")
  }
   var f=new Fun()
   f.text()
</script>2,显示原型属性和隐示原型属性
先给出定义:
每个函数function都有一个prototype,即显式原型属性。
 每个实例对象都有一个__proto__,可称为隐式原型属性。
显式原型属性和隐式原型属性的关系为:对象的隐式原型的值为其对应构造函数的显式原型的值。
显式原型属性就不说了,上面讲的和详细了,那就讲讲隐式原型属性吧。
__proto__隐式原型属性实在对象被创建时才被添加,其值为其对应构造函数的显式原型的值。其指向和显式原型属性一样。默认指向一个空Object对象。
 <script >
   function Fun(){}
   var f=new Fun();//隐含了this.__proto__=Fun.prototype
   console.log(f.__proto__===Fun.prototype)
</script>打印结果为true。在来一段代码,以此代码来画出内存示意图:
<script >
   function Fun(){}
   Fun.prototype.text=function(){
   }//隐含this.prototype={}
   console.log(Fun.prototype)
   var f=new Fun();//隐含this.__proto__=Fun.prototype
 console.log(f.__proto__===Fun.prototype)
   console.log(f.__proto__)
  f.text()
</script>内存示意图:
3,原型链
先来一段代码:
  function Fn() {
    this.test1 = function () {
      console.log('test1()')
    }
  }
  console.log(Fn.prototype)
  Fn.prototype.test2 = function () {
    console.log('test2()')
  }
  var fn = new Fn()
  fn.test1()
  fn.test2()
  console.log(fn.toString())
  console.log(fn.test3)运行结果为:
前面的输出结果在意料之中,我们在函数和原型中添加了方法,在调用之后,输出了test1()和test2()。当时函数中没有toString和test3,但是调用的时候,确输出了不同的结果,一个是输出[object Object],另一个输出undefined,是什么导致这个结果?这个就得引出一个知识点:原型链。
代码的内存示例图:
第一步:首先,Fn保存了Fn函数对象的地址值,Fn函数对象在堆内存中有块内存空间,Fn指向该内存空间。Fn函数对象有个属性prototype(显示原型),该属性指向一个原型对象(空Object对象)。
第二步:有个全局作用域对象Object在页面加载的时候也会被创建,指向Object的函数对象,Object的显式原型属性会指向其原型对象。
第三步:由于Object的原型对象的存在,空Object对象的隐式原型属性会指向Object的原型对象(对象的隐式原型的值为其对应构造函数的显式原型的值)。Object的原型对象会有个隐式原型属性,其值为null,表示原型链的尽头。
第四步:创建fn实例 对象,会在内存中开辟一个内存空间用来存放Fn的实例对象,函数的实例对象会有个隐式原型属性指向其构造函数的原型对象(对象的隐式原型的值为其对应构造函数的显式原型的值)。
第五步:添加函数,Fn添加函数是在其原型中添加,fn则是在实例函数中添加,查找是,查找test1会沿着内存为0x567这条查找,在其函数实例总找到并打印。查找test2时,会沿着内存为0x123这条找,最终在其原型对象中找到。查找toString时,在原型对象找不到,回到Object的原型对象查找,找到后打印。查找test3时,在原型链的尽头都没有,会放反回一个undefined。
总结为:
访问一个对象的属性时,先在自身属性中查找,找到返回,如果没有, 再沿着__proto__这条链向上查找, 找到返回,如果最终没找到, 返回undefined。可以看出,整条链是沿着隐式原型属性查找,所以也被称之为 隐式原型链。
注意:
a,函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
 console.log(Fn.prototype instanceof Object) // true
  console.log(Object.prototype instanceof Object) // false
  console.log(Function.prototype instanceof Object) // trueb, 所有函数都是Function的实例(包含Function)
console.log(Function.__proto__===Function.prototype)c, Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null4,原型链的属性问题
读取对象的属性值时: 会自动到原型链中查找。
 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值。
 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上。
无论对象创建多少次,其实例对象的隐式原型属性都不变。
function Fn() {}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a, fn1)
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a, fn2.a, fn2)
Person.prototype.setName = function (name) {
    this.name = name
  }
  var p1 = new Person('Tom', 12)
  p1.setName('Bob')
  console.log(p1)
  var p2 = new Person('Jack', 12)
  p2.setName('Cat')
  console.log(p2)
  console.log(p1.__proto__===p2.__proto__) // true5,instanceof的实现原理:利用原型链
表达式: A instanceof B
 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false。其中A是一个实例对象,B是一个构造函数对象。
 /*
  案例1
   */
  function Foo() {  }
  var f1 = new Foo()
  console.log(f1 instanceof Foo) // true
  console.log(f1 instanceof Object) // true
  /*
  案例2
   */
  console.log(Object instanceof Function) // true
  console.log(Object instanceof Object) // true
  console.log(Function instanceof Function) // true
  console.log(Function instanceof Object) // true
  function Foo() {}
  console.log(Object instanceof  Foo) // false【JavaScript高级02】JavaScript第一大神兽:原型和原型链的更多相关文章
- JavaScript高级程序设计:第一章
		JavaScript简介: 1.JavaScript实现应该由以下三部分组成: (1)核心:ECMAScript (2)文档对象模型:DOM (3)浏览器对象模型:BOM 2.什么是ECMAScrip ... 
- Javascript高级编程学习笔记(21)——  对象原型
		JS中对象相关的最重要的恐怕就是原型链了 原型链也是JS中对象继承的实现的基础 接昨天的文章,我们使用构造函数创建对象的时候仍然存在一些问题 那就是所有的实例没法共用一个函数 这样无疑会造成极大的内存 ... 
- javaScript系列 [02]-javaScript对象探析
		[02]-javaScript对象探析 题记:多年前,以非常偶然的方式关注了微信公众号“面向对象”,本以为这个公众号主要以分享面向对象编程的干货为主,不料其乃实实在在的猿圈相亲平台.通过查看公开资料, ... 
- 《JAVASCRIPT高级程序设计》第一章
		在使用调制解调器的时代,频繁的表单验证对客户端来说是一个很大的负担,javascript,作为一种专门进行表单验证的客户端脚本语言诞生了.到今天,javascript早已超越了当初设定的角色.Java ... 
- 《JavaScript 高级程序设计》第一章:简介
		JavaScript 历史 JavaScript的诞生的主要是当时的 netspace 公司谋求为自己的浏览器 Navigator 添加一种脚本语言,以便在本地客户端进行一些行为操作,而这一功能的需求 ... 
- 《JavaScript高级程序设计》——第一章JavaScript简介
		第一章主要讲了JavaScript的诞生和发展.刚刚接触JavaScript的我,似乎对这些内容并不感兴趣,快速看了一遍就开始去看第二章了. 看完第一章,收获也就是了解到JavaScript由ECMA ... 
- Javascript高级程序设计——javascript简介
		1.Javascript简史 javascript诞生于1995年,是由网景公司的Brendan Eich开发的,最初的目的是在客户端处理一些输入验证操作,自此后成为常见浏览器的特色功能,如今用途已经 ... 
- Javascript高级程序设计——Javascript简史+使用Javascript
		一.Javascipt简史 1.了解Javascript历史 Netscape(Javascript1.0).Microsoft(JScript)到JS1.1,再到ECMA-262标准 2.知道ECM ... 
- javaScript基础-02 javascript表达式和运算符
		一.原始表达式 原始表达式是表达式的最小单位,不再包含其他表达式,包含常量,直接量,关键字和变量. 二.对象和数组的初始化表达式 对象和数组初始化表达式实际上是一个新创建的对象和数组. 三.函数表达式 ... 
- javaScript系列 [03]-javaScript原型对象
		[03]-javaScript原型对象 引用: javaScript是一门基于原型的语言,它允许对象通过原型链引用另一个对象来构建对象中的复杂性,JavaScript使用原型链这种机制来实现动态代理. ... 
随机推荐
- mysql 命令行安装方式
			一:下载 先到 mysql 官方网站下载:https://dev.mysql.com/downloads/mysql/ 点击直接下载: 解压到目录:D:\mysql-8.0.19-winx64 如图 ... 
- conda错误  创建新环境conda create -n TF117 python=3.5时报错 An unexpected error has occurred. Conda has prepared the above report.
			创建新环境conda create -n TF117 python=3.5时报错 An unexpected error has occurred. Conda has prepared the ab ... 
- kubeadm部署高可用版Kubernetes1.21[基于centos7.6]
			1. 基础环境规划: 主机名 IP地址 节点说明 k8s-node01 192.168.1.154 node1节点 k8s-node02 192.168.1.155 node2节点 master01 ... 
- Swift 属性装饰器
			import ArgumentParser @propertyWrapper struct WrapperTest { internal var innerValue: Int { didSet { ... 
- wordpress博客系统报错
			第一种,只显示nginx的默认网页 说明wordpress的网页配置文件没有被系统读取 我们就需要去查看nginx的配置文件/etc/nginx/conf.d/default.conf 首先,查看是不 ... 
- minos 2.1 中断虚拟化——ARMv8 异常处理
			首发公号:Rand_cs 越往后,交叉的越多,大多都绕不开 ARMv8 的异常处理,所以必须得先了解了解 ARMv8 的异常处理流程 先说一下术语,从手册中的用词来看,在 x86 平台,一般将异常和中 ... 
- 微信实名认证申请单报错:请求中含有未在API文档中定义的参数
			完整错误: {"code":"PARAM_ERROR","detail":{"location":null," ... 
- k8s配置文件管理
			1.为什么要用configMap ConfigMap是一种用于存储应用所需配置信息的资源类型,用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件. 通过ConfigMap可以方便的 ... 
- 请写出常用的linux指令
			a.cd /home 进入 '/ home' 目录' b.cd .. 返回上一级目录 c.cd ../.. 返回上两级目录 d.mkdir dir1 创建一个叫做 'dir1' 的目录' e.mkdi ... 
- Java接口签名和验签
			Java接口签名和验签 import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.StringUtils; import ja ... 
