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第一大神兽:原型和原型链的更多相关文章

  1. JavaScript高级程序设计:第一章

    JavaScript简介: 1.JavaScript实现应该由以下三部分组成: (1)核心:ECMAScript (2)文档对象模型:DOM (3)浏览器对象模型:BOM 2.什么是ECMAScrip ...

  2. Javascript高级编程学习笔记(21)—— 对象原型

    JS中对象相关的最重要的恐怕就是原型链了 原型链也是JS中对象继承的实现的基础 接昨天的文章,我们使用构造函数创建对象的时候仍然存在一些问题 那就是所有的实例没法共用一个函数 这样无疑会造成极大的内存 ...

  3. javaScript系列 [02]-javaScript对象探析

    [02]-javaScript对象探析 题记:多年前,以非常偶然的方式关注了微信公众号“面向对象”,本以为这个公众号主要以分享面向对象编程的干货为主,不料其乃实实在在的猿圈相亲平台.通过查看公开资料, ...

  4. 《JAVASCRIPT高级程序设计》第一章

    在使用调制解调器的时代,频繁的表单验证对客户端来说是一个很大的负担,javascript,作为一种专门进行表单验证的客户端脚本语言诞生了.到今天,javascript早已超越了当初设定的角色.Java ...

  5. 《JavaScript 高级程序设计》第一章:简介

    JavaScript 历史 JavaScript的诞生的主要是当时的 netspace 公司谋求为自己的浏览器 Navigator 添加一种脚本语言,以便在本地客户端进行一些行为操作,而这一功能的需求 ...

  6. 《JavaScript高级程序设计》——第一章JavaScript简介

    第一章主要讲了JavaScript的诞生和发展.刚刚接触JavaScript的我,似乎对这些内容并不感兴趣,快速看了一遍就开始去看第二章了. 看完第一章,收获也就是了解到JavaScript由ECMA ...

  7. Javascript高级程序设计——javascript简介

    1.Javascript简史 javascript诞生于1995年,是由网景公司的Brendan Eich开发的,最初的目的是在客户端处理一些输入验证操作,自此后成为常见浏览器的特色功能,如今用途已经 ...

  8. Javascript高级程序设计——Javascript简史+使用Javascript

    一.Javascipt简史 1.了解Javascript历史 Netscape(Javascript1.0).Microsoft(JScript)到JS1.1,再到ECMA-262标准 2.知道ECM ...

  9. javaScript基础-02 javascript表达式和运算符

    一.原始表达式 原始表达式是表达式的最小单位,不再包含其他表达式,包含常量,直接量,关键字和变量. 二.对象和数组的初始化表达式 对象和数组初始化表达式实际上是一个新创建的对象和数组. 三.函数表达式 ...

  10. javaScript系列 [03]-javaScript原型对象

    [03]-javaScript原型对象 引用: javaScript是一门基于原型的语言,它允许对象通过原型链引用另一个对象来构建对象中的复杂性,JavaScript使用原型链这种机制来实现动态代理. ...

随机推荐

  1. Django模板templates

    1.模板文件的路径配置 2.模板中变量替换 3.变量渲染之深度查询 4.内置过滤器 过滤器的语法: {{obj|过滤器名称:过滤器参数}} 内置过滤器: 过滤器例子: 5.注释 6.多行注释 7.if ...

  2. Qt-FFmpeg开发-回调函数读取数据(8)

    音视频/FFmpeg #Qt Qt-FFmpeg开发-使libavformat解复用器通过自定义AVIOContext读取回调访问媒体内容 目录 音视频/FFmpeg #Qt Qt-FFmpeg开发- ...

  3. 使用python在k8s中创建一个pod

    要在Kubernetes (k8s) 中使用Python创建一个Pod,你可以使用Kubernetes Python客户端库(通常称为kubernetes或kubernetes-client).以下是 ...

  4. Golang基于Mysql分布式锁实现集群主备

    背景 集群中如果需要主备,可以基于Redis.zk的分布式锁等实现,本文将介绍如何利用Mysql分布式锁进行实现. 原理 数据库中包含数据字段(此处为Master的主机名).版本号和上一次更新时间. ...

  5. LLM技术全景图:技术人必备的技术指南,一张图带你掌握从基础设施到AI应用的全面梳理

    LLM技术全景图:技术人必备的技术指南,一张图带你掌握从基础设施到AI应用的全面梳理 LLM 技术图谱(LLM Tech Map)是将 LLM 相关技术进行系统化和图形化的呈现,此图谱主要特点是&qu ...

  6. 【VyOS-开源篇-3】- container for vyos 搭建 Halo 博客-vyos-开源篇

    文章说明:介绍在vyos软路由上配置container容器,vyos最新滚动版1.5已经支持在vyos命令行中启动docker容器,在vyos 官网介绍是说1.3版本之后就都有这个功能了,如果你的版本 ...

  7. PHP接入苹果支付

    Ios苹果支付流程: 客户端先从苹果获取内购Id. 客户端将内购id,金额.用户id等传给服务端获取一个自己服务端生成的订单号. 客户端向苹果发起支付. 支付成功后,客户端从本地拿支付凭证.将支付凭证 ...

  8. 基于 .net core 8.0 的 swagger 文档优化分享-根据命名空间分组显示

    前言 公司项目是是微服务项目,网关是手撸的一个.net core webapi 项目,使用 refit 封装了 20+ 服务 SDK,在网关中进行统一调用和聚合等处理,以及给前端提供 swagger ...

  9. 韦东山freeRTOS系列教程之【第十章】软件定时器(software timer)

    目录 系列教程总目录 概述 10.1 软件定时器的特性 10.2 软件定时器的上下文 10.2.1 守护任务 10.2.2 守护任务的调度 10.2.3 回调函数 10.3 软件定时器的函数 10.3 ...

  10. 韦东山freeRTOS系列教程之【第七章】互斥量(mutex)

    目录 系列教程总目录 概述 7.1 互斥量的使用场合 7.2 互斥量函数 7.2.1 创建 7.2.2 其他函数 7.3 示例15: 互斥量基本使用 7.4 示例16: 谁上锁就由谁解锁? 7.5 示 ...