【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) // true
b, 所有函数都是Function的实例(包含Function)
console.log(Function.__proto__===Function.prototype)
c, Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null
4,原型链的属性问题
读取对象的属性值时: 会自动到原型链中查找。
设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值。
方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上。
无论对象创建多少次,其实例对象的隐式原型属性都不变。
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__) // true
5,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使用原型链这种机制来实现动态代理. ...
随机推荐
- Django模板templates
1.模板文件的路径配置 2.模板中变量替换 3.变量渲染之深度查询 4.内置过滤器 过滤器的语法: {{obj|过滤器名称:过滤器参数}} 内置过滤器: 过滤器例子: 5.注释 6.多行注释 7.if ...
- Qt-FFmpeg开发-回调函数读取数据(8)
音视频/FFmpeg #Qt Qt-FFmpeg开发-使libavformat解复用器通过自定义AVIOContext读取回调访问媒体内容 目录 音视频/FFmpeg #Qt Qt-FFmpeg开发- ...
- 使用python在k8s中创建一个pod
要在Kubernetes (k8s) 中使用Python创建一个Pod,你可以使用Kubernetes Python客户端库(通常称为kubernetes或kubernetes-client).以下是 ...
- Golang基于Mysql分布式锁实现集群主备
背景 集群中如果需要主备,可以基于Redis.zk的分布式锁等实现,本文将介绍如何利用Mysql分布式锁进行实现. 原理 数据库中包含数据字段(此处为Master的主机名).版本号和上一次更新时间. ...
- LLM技术全景图:技术人必备的技术指南,一张图带你掌握从基础设施到AI应用的全面梳理
LLM技术全景图:技术人必备的技术指南,一张图带你掌握从基础设施到AI应用的全面梳理 LLM 技术图谱(LLM Tech Map)是将 LLM 相关技术进行系统化和图形化的呈现,此图谱主要特点是&qu ...
- 【VyOS-开源篇-3】- container for vyos 搭建 Halo 博客-vyos-开源篇
文章说明:介绍在vyos软路由上配置container容器,vyos最新滚动版1.5已经支持在vyos命令行中启动docker容器,在vyos 官网介绍是说1.3版本之后就都有这个功能了,如果你的版本 ...
- PHP接入苹果支付
Ios苹果支付流程: 客户端先从苹果获取内购Id. 客户端将内购id,金额.用户id等传给服务端获取一个自己服务端生成的订单号. 客户端向苹果发起支付. 支付成功后,客户端从本地拿支付凭证.将支付凭证 ...
- 基于 .net core 8.0 的 swagger 文档优化分享-根据命名空间分组显示
前言 公司项目是是微服务项目,网关是手撸的一个.net core webapi 项目,使用 refit 封装了 20+ 服务 SDK,在网关中进行统一调用和聚合等处理,以及给前端提供 swagger ...
- 韦东山freeRTOS系列教程之【第十章】软件定时器(software timer)
目录 系列教程总目录 概述 10.1 软件定时器的特性 10.2 软件定时器的上下文 10.2.1 守护任务 10.2.2 守护任务的调度 10.2.3 回调函数 10.3 软件定时器的函数 10.3 ...
- 韦东山freeRTOS系列教程之【第七章】互斥量(mutex)
目录 系列教程总目录 概述 7.1 互斥量的使用场合 7.2 互斥量函数 7.2.1 创建 7.2.2 其他函数 7.3 示例15: 互斥量基本使用 7.4 示例16: 谁上锁就由谁解锁? 7.5 示 ...