-
2021-02-10 10:51:18
有同学问到了一个问题,python中存储变量是通过内存地址来存储,那么python又是如何去判断内存中的地址是什么数据类型的呢。经过查找,找到这篇文章:
原博客地址:http://www.cnblogs.com/aashui/p/9871009.html
1.Python是如何进行内存管理的?
答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制
一、对象的引用计数机制
Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:
1,一个对象分配一个新名称
2,将其放入一个容器中(如列表、元组或字典)
引用计数减少的情况:
1,使用del语句对对象别名显示的销毁
2,引用超出作用域或被重新赋值
sys.getrefcount( )函数可以获得对象的当前引用计数
多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
二、垃圾回收
1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
三、内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
由上述可以看出,当我们创建一个整数变量如,Num_int = 1 此时必定会有一个内存地址A(假设)指向1这个数据。此时Num_Int 指向的地址也是地址A。当我们创建这个整数对象时,实际上1这个数据已经存向了我们内存中指定存放整数的地方,如下图:
也就是说,在我们创建整数变量或者其他变量时,python已经帮你找到了固定的位置,然后你将数据存进去就可以了。不管你怎么存,只是地址变了,并且你的地址如果是相同的数据类型,那么应该是有相似点的,比如 A (内存地址) = 10001 那么可能你再创建一个变量 时 B(内存地址) = 10002 。本人理解是这样,若有不对请指出,谢谢!
Python 底层原理知识
1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都 ...
操作系统底层原理与Python中socket解读
目录 操作系统底层原理 网络通信原理 网络基础架构 局域网与交换机/网络常见术语 OSI七层协议 TCP/IP五层模型讲解 Python中Socket模块解读 TCP协议和UDP协议 操作系统底层原理 ...
Python多线程原理与实现
Date: 2019-06-04 Author: Sun Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了解线程池的使用 1 线程基本 ...
Docker底层原理介绍
1.docker介绍 1.1什么是docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻 ...
Android进程永生技术终极揭秘:进程被杀底层原理、APP应对技巧
1.引言 上个月在知乎上发表的由“袁辉辉”分享的关于TIM进程永生方面的文章(即时通讯网重新整理后的标题是:),短时间内 ...
Python底层socket库
Python底层socket库将Unix关于网络通信的系统调用对象化处理,是底层函数的高级封装,socket()函数返回一个套接字,它的方法实现了各种套接字系统调用.read与write与Python ...
Neo4j图数据库简介和底层原理
现实中很多数据都是用图来表达的,比如社交网络中人与人的关系.地图数据.或是基因信息等等.RDBMS并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘.NoSQL数据库的兴起,很好地解决了海 ...
【T-SQL进阶】02.理解SQL查询的底层原理
本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...
spring框架的IOC的底层原理
1.IOC概念:spring容器创建对象并管理 2.IOC的底层原理的具体实现: 1)所使用的技术: (1). dom4j解析xml配置文件 (2).工厂设计模式(解耦合) (3).反射 第一步:配置 ...
随机推荐
实现了IEnumerable接口的GetEnumerator 即可使用 Foreach遍历,返回一个IEnumerator对象
#region 程序集 mscorlib.dll, v4.0.0.0 // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framewor ...
win7自带windows media player 已停止工作
解决方法如下: 在计算机开始,菜单找到控制面板 ,然后打开程序和功能,选择打开或关闭window功能,媒体功能.再取消windows Media Center Windows MediaPlayer选 ...
R-Studio
R-Studio是一个功能强大.节省成本的反删除和数据恢复软件系列.它采用独特的数据恢复新技术,为恢复FAT12/16/32.NTFS.NTFS5(由 Windows 2000/XP/2003/Vis ...
PuTTY 信息泄露漏洞
漏洞名称: PuTTY 信息泄露漏洞 CNNVD编号: CNNVD-201308-380 发布时间: 2013-08-27 更新时间: 2013-08-27 危害等级: 低危 漏洞类型: 信息泄露 ...
IOS 推送原理
最近两天在研究ios的消息推送机制.研究这个东西,还是充满兴趣的. Push的原理: Push 的工作机制可以简单的概括为下图 图中,Provider是指某个iPhone软件的Push服务器,这篇文章 ...
简单购物车程序(Python)
#简单购物车程序:money_all=0tag=Trueshop_car=[]shop_info={'apple':10,'tesla':100000,'mac':3000,'lenovo':3000 ...
国内开源社区巨作AspectCore-Framework入门
前些天和张队(善友),lemon(浩洋),斌哥(项斌)等MVP大咖一块儿吃饭,大家聊到了lemon名下的AOP这个项目,我这小白听得一脸懵逼,后面回来做了一下功课,查了下资料,在lemon的Githu ...
TensorFlow函数:tf.reduce_sum
tf.reduce_sum 函数 reduce_sum ( input_tensor , axis = None , keep_dims = False , name = None , reducti ...
LeetCode题解:Flatten Binary Tree to Linked List:别人的递归!
总是在看完别人的代码之后,才发现自己的差距! 我的递归: 先把左侧扁平化,再把右侧扁平化. 然后找到左侧最后一个节点,把右侧移动过去. 然后把左侧整体移到右侧,左侧置为空. 很复杂吧! 如果节点很长的 ...
DPDK实例程序:testpmd
用户手册:https://doc.dpdk.org/guides/testpmd_app_ug/index.html 还不错的入门:http://syswift.com/188.html 我的运行情况 ...
更多相关内容 -
芯片的底层原理
2022-01-15 22:09:04芯片的底层就是逻辑门电路组成的,在逻辑门的基础上不断抽象,从而组成了我们使用的计算机。...上图中我们可以看到如果两个线圈通电的话,会分别把它们上面的开关吸下来,从而使得开关闭合,那么最终就会导致灯泡...芯片的底层就是逻辑门电路组成的,在逻辑门的基础上不断抽象,从而组成了我们使用的计算机。所以,首先我们先了解一下门电路的底层实现。
1. 门电路
1.1 与门
与门是两个输入,一个输出,当两个输入都是1的时候,输出才会是1,其他情况输出为0。下面通过继电器对与门的底层原理进行解释:
中学物理我们学过电磁感应,就是在线圈通电的情况下,会产生磁效应。上图中我们可以看到如果两个线圈通电的话,会分别把它们上面的开关吸下来,从而使得开关闭合,那么最终就会导致灯泡通电。
可以看到,连接灯泡的是有一个电源,这个电路上有两个开关,这两个开关是由另外两个电源控制的,所以整个电路中使用了三个电源,
简化之后的电路,是上面这个样子。可以看到,把灯泡本应该有的电源给忽略了,只剩了两个开关电源。
1.2 或门
或门也是两个输入,一个输出,两个输入中只有有至少一个为1,那么输出就是1.
或门是由四个电源组成的,两个电源是直连灯泡的,另外两个电源是连着继电器,每一个继电器控制一个灯泡电源的开关
1.3 非门
非门代表的含义是输出和输入相反,输入如果是1,那么输出就是0,如果输入是0,那么输出就是1。
非门就是继电器电源闭合,把灯泡的电源拉下来,进而灯泡电源断开;若继电器电源断开,则灯泡电源弹上去进而闭合。
1.4 异或门
上面的与或非门是最最基础的门电路,我们可以通过与或非门进行组合,产生新的门电路,比如现在讲的异或门。异或门的含义是两个输入不同的时候,输出为1,两个输入相同的时候输出为0.
2.加法器
学过计算机原理的都知道,早期的计算机的主要计算单元就是加法器,也就是说减法、乘法、除法都可以用加法器完成,那么怎么通过我们上面说的门电路组装出一个加法器呢?
我们知道,计算机的底层是通过二进制完成逻辑计算的,所以我们需要完成的加法器也是要实现二进制的加法。二进制的加法有以下几个场景:0+0=0、0+1=1、1+1=10。能看出什么迹象么?两个值相同时,输出为0,两个值不同时输出为1。是不是想到什么了?对,就是我们上面讲到的异或门的特性。说到加法,就会有进位,对于二进制来说,只有两个输入都是1的情况下,才会有进位,而这个特性刚好符合我们上面讲的与门。所以,二进制的和可以由异或门实现,而进位可以由与门实现,两者结合起来就可以完成两个二进制的加法运算。(该电路可以称为半加器)
下面是通过把半加器在继电器层级的电路画出来了,大家可以看下最基本的电路是怎么实现加法器的,这可能也是很多同学在初学计算机的时候都疑惑的地方:电路是怎么实现当前计算机这么复杂的计算的。这就是最基本的实现原理。
半加器是实现两个一位二进制数加法运算的器件,上图图就可以简化为一个半加器,如果考虑进位,就可以通过两个半加器结合实现,如下图:
3.触发器
3.1 振荡器
继电器可以实现门电路,下面我们再看一个通过继电器实现的比较骚的电路。
我们看到上面的这个电路,接通的电路使电磁铁把金属簧片拉下来,当金属簧片改变位置后,电路不再完整,电磁铁失去了磁性,金属簧片又弹回原来的位置。
电路的输出就是提供电压和不提供电压之间变换,这个电路被称为振荡器。也被称为时钟
3.2 R-S触发器
此电路有以下特性:
闭合上面的开关使灯泡点亮,当再断开时,灯泡仍然亮着。
闭合下面的开关使灯泡熄灭,当再断开时,灯泡仍然不亮。
电路的奇特之处是:有时当两个开关都断开时,灯泡亮着;而有时,当两个开关都断开时,灯泡却不亮。当两个开关都断开时,电路有两个稳定状态,这样的一个电路称为触发器。
这个电路可以记忆最近一次是哪个开关先闭合的。这种触发器被称为R-S(Reset-Set,复位/置位)触发器。
3.3 D型锁存器
这个电路被称为电平触发的D型触发器,D表示数据端输入。所谓电平触发 是指当保持位输入为某一特定电平(本例中为“ 1”)时,触发器才对数据端的输入值进行保存。它也可以称为1位存储器。
4.存储器
4.1 存储器原理
这是同一个触发器,但是现在Q输出端命名为输数输出,时钟输入端命名为写入。该电路也叫锁存器。
8个这样的锁存器连在一起,就是8为输入输出。
如果8个中选择一个输出,怎么办?看下图,这是8-1选择器。
下面这个是3-8译码器
8个锁存器的完整电路如下
简化图如下:
4.2 大内存实现原理
我们上一节看到,8位容量的锁存器就有很多条线。但是在真实的计算机中,我们的内存都是以G为单位的,如果按照上一节讲的方法,扩展出来真实可用的物理内存,那么线路复杂度是超过人的想象的。
为了解决大内存的布线问题,工程师们想到了矩阵的方式,也就是以矩阵的形式摆放一个一个锁存器,如下图所示:
也就是以地址线决定是否可写入读出,上图中,横着的地址线和纵向的地址线都是1的情况下,才能选中这个锁存器,这个时候再看write和read信号,来决定是否可写入或读出。
把内存布局抽象一层,我们可以由如下图示进行表示
以上的描述,一个地址只能写入或读出1位数据,如果想要同时写入或读出一个byte的数据,也就是8位,怎么办呢?很简单,把地址线同时连8个像上面的内存就行了,如下图:
4.3 真实物理内存条
该内存条有1M的容量,通过对内存条逐步放大,我们看下其工艺实现。
其中一个小黑条放大之后如下:
其中一个小四方块放大之后如下:
其中每个四方块放大之后如下:
参考:
1. 《编码》
2. 【计算机科学速成课】[40集全/精校] - Crash Course Computer Science_哔哩哔哩_bilibili
-
Javascript底层原理总结
2020-10-22 13:12:29Javascript底层原理、面试题、算法、浏览器、dom等相关文档持续更新~
目录
基础
-
数据结构
栈:一种遵从先进后出 (LIFO) 原则的有序集合;新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另一端为栈底。在栈里,新元素都靠近栈顶,旧元素都接近栈底。栈只是对原有数据进行了一次封装而已。而封装的结果是:并不去关心其内部的元素是什么,只是去操作栈顶元素,这样的话,在编码中会更可控一些
// 定义一个栈 class Stack { constructor() { this.items = [] } push(element) { // 入栈 this.items.push(element) } pop() { // 出栈 return this.items.pop() } get peek() { // 末位 return this.items[this.items.length - 1] } get isEmpty() { // 是否为空栈 return !this.items.length } get size() { // 尺寸 return this.items.length } clear() { // 清空栈 this.items = [] } print() { // 打印栈数据 console.log(this.items.toString()) } } const stack = new Stack() console.log(stack.isEmpty) // true // 添加元素 stack.push(5) stack.push(8) // 读取属性再添加 console.log(stack.peek) // 8 stack.push(11) console.log(stack.size) // 3 console.log(stack.isEmpty) // false
队列:与上相反,一种遵循先进先出 (FIFO / First In First Out) 原则的一组有序的项;队列在尾部添加新元素,并从头部移除元素。最新添加的元素必须排在队列的末尾。例如日常生活中的购物排队。与栈类比,栈仅能操作其头部,队列则首尾均能操作,但仅能在头部出尾部进
class Queue { constructor(items) { this.items = items || [] } enqueue(element){ // 向队列尾部添加一个(或多个)新的项 this.items.push(element) } dequeue(){ // 移除队列的第一(即排在队列最前面的)项,并返回被移除的元素 return this.items.shift() } head(){ // 返回队列第一个元素,队列不做任何变动 return this.items[0] } clear(){ // 清空队列 this.items = [] } get size(){ // 返回队列内元素个数 return this.items.length } get isEmpty(){ // 队列内无元素返回 true,否则返回 false return !this.items.length } print() { console.log(this.items.toString()) } }
链表:存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的;每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(指针/链接)组成。
集合:由一组无序且唯一(即不能重复)的项组成;这个数据结构使用了与有限集合相同的数学概念,但应用在计算机科学的数据结构中。
字典:以 [键,值] 对为数据形态的数据结构,其中键名用来查询特定元素,类似于 Javascript 中的
Object
。散列:根据关键码值(Key value)直接进行访问的数据结构;它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度;这个映射函数叫做散列函数,存放记录的数组叫做散列表。
树:由 n(n>=1)个有限节点组成一个具有层次关系的集合;把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的,基本呈一对多关系,树也可以看做是图的特殊形式。
图:图是网络结构的抽象模型;图是一组由边连接的节点(顶点);任何二元关系都可以用图来表示,常见的比如:道路图、关系图,呈多对多关系。
-
JS堆栈的概念
堆(heap)用于复杂数据类型(引用类型)分配空间,例如数组对象、object对象;它是运行时动态分配内存的,因此存取速度较慢。
栈(stack)中主要存放一些基本类型的变量和对象的引用,(包含池,池存放常量),其优势是存取速度比堆要快,并且栈内的数据可以共享,但缺点是存在栈中的数据大小与生存期必须是确定的,缺乏灵活性,先进后出,后进先出原则,所以 push 优于 unshift。
js的数据类型主要分为两种:基本类型值和引用类型值。
基本类型值 有6种:undefined,null,boolean,number,string,symbol。这六种数据类型是按值访问的,是存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。基本类型值的复制是值的传递,赋值以后二者再无关联,修改其中一个不会影响另一个。
引用类型值: 5种基本类型值以外的数据类型都可以看做是引用类型值,比如array,object等,是保存在堆内存中的对象。js不允许直接访问堆内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际是在操作对象的引用而不是实际的对象,是按地址访问的。
可以看到,直接传递引用类性值的时候,传递的只是引用,二者指向同一块内存,所以修改其中一个,必然会引起另一个变量的变化。 在日常的使用中,我们把对象赋值给一个变量时,通常希望得到的是一个跟原对象无关的副本,修改新的变量不影响原对象,因此就有了浅拷贝和深拷贝。
-
作用域链的理解
作用域链是由于js的变量都是对象的属性,而该对象可能又是其它对象的属性,而所有的对象都是window对象的属性,所以这些对象的关系可以看作是一条链
当
javascript
查找与变量相关联的值时,会遵循一定的规则,也就是沿着作用域链从当前函数作用域内逐级的向上查找,直到顶层全局作用域结束,若找到则返回该值,若无则返回undefined,这个链条是基于作用域的层次结构的,一旦当代码在坏境中执行时,会自动的创建一个变量对象的作用域链,其作用域链的用途也就是保证对执行坏境的全局变量和具有访问权限函数内的局部变量定制特殊的规则,由内到外有序的对变量或者函数进行访问,作用域链包含了在坏境栈中的每个执行坏境对应的变量对象,通过作用域链可以决定变量的访问与标识符的解析作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。
全局作用域:可以在代码的任何地方访问,一般来说,下面情况的对象会在全局作用域中:
最外层函数和在最外层函数外面定义的变量。
没有通过关键字"var"声明的变量。
浏览器中,window对象的属性。
局部作用域:函数作用域(Function scope),所有的变量和函数只能在作用域内部使用
-
变量提升、函数提升、浏览器解析变量的机制
JS预解析:
1.当浏览器加载html页面的时候,首先会提供一个全局JS代码执行的环境(全局作用域)
2.预解析(变量提升,浏览器的加载机制)
在当前的作用域中,js代码执行之前,浏览器首先会默认把所有带var和function的进行提前的声明或者定义
注意:对于变量只是进行了变量提前声明,而函数是提前声明并且定义
var num = 1; // 理解声明和定义 // 声明(declare):var num; --> 告诉浏览器在全局作用域中有一个num的变量了,如果一个变量只是声明了但是没有赋值,默认的值是undefined。 // 定义(defined):num = 1; --> 给变量进行赋值
// var ->在预解释的时候只是提前的声明 // function ->在预解释的时候提前的声明+定义都完成了 console.log(number); // num is not defined console.log(num); // undefined var num = 1; console.log(num); // 1 console.log(fn); // 打印出函数体 function fn (){ console.log('fn') }; console.log(fn); // 打印出函数体
变量和函数重名时:变量只是提前声明了,函数声明并且定义了,所以先打印的fn,然后开始执行时,变量开始赋值,函数不进行赋值。
console.log(fn) // fn(){console.log(4)} function fn(){ console.log(2) } console.log(fn) // // fn(){console.log(4)} var fn = 3 console.log(fn) // 3 function fn(){ console.log(4) } console.log(fn) // 3
函数表达式调用必须写到函数表达式的下面
fun(); // fun is not a function var fun = function () { console.log(22); } 相当于执行 var fun; fun(); fun = function () { console.log(22); }
3.预解析只发生在当前的作用域(全局作用域/局部作用域)下,例如:开始只对window下的进行预解释,只有函数执行的时候才会对函数中的进行预解析
var a = 10; function fn (){ console.log(a); // undefined var a = 11; console.log(a); // 11 } fn() console.log(a); // 10 相当于 var a = 10; // 全局变量 function fn (){ var a; // 局部变量 console.log(a); // undefined; var a = 11; console.log(a); // 11; } fn() console.log(a); // 10
-
理解上下文和作用域
上下文与作用域是两个不同的概念,有时我自己也经常混淆,把它们视为是同一个东西,我们知道函数的每次调用都会有与之紧密相连的作用域和上下文,从本质上说,
作用域其实是基于函数的
,而上下文
是基于对象的
,也就是说作用域是涉及到它所被调用函数中的变量访问,而调用方法和访问属性又存在着不同的调用场景(4种调用场景,函数调用,方法调用,构造器函数调用,call(),apply()间接调用),而上下文始终是this
所代表的值,它是拥有控制当前执行代码的对象的引用-
定义一个变量到这个变量被回收做了什么
-
进程与线程、什么是单线程?和异步有何关系
-
理解MVVM、MVC
-
理解AMD、commonjs
-
虚拟内存及缓冲区溢出
-
null和undefined的区别
-
ajax/axios/fetch的区别
-
Promise的原理
-
instanceof的原理
-
typeof的原理
-
数组的扁平化
-
xhr对象
-
ES6 Proxy的概念
-
闭包?运行时上下文里面包括什么?
-
结合作用域链看闭包
-
三栏布局
-
BFC布局原理
事件
-
even loop事件循环
-
DOM事件
DOM的级别Level DOM0:不是W3C规范。
DOM0事件绑定的原理
给当前元素的某一私有属性(onXXX)赋值的过程;(之前属性默认值是null,如果我们赋值了一个函数,就相当于绑定了一个方法)
当我们赋值成功(赋值一个函数),此时浏览器会把DOM元素和赋值的的函数建立关联,以及建立DOM元素的行为监听,当某一行为被用户触发,浏览器会把赋值的函数执行;
DOM0事件绑定的特点:
只有DOM元素天生拥有这个私有属性(onxxx事件私有属性),我们赋值的方法才叫事件绑定,否则属于设置自定义属性
移除事件绑定的时候,我们只需要赋值为null;
在DOM0事件绑定中,只能给当前元素的某一个事件行为绑定一个方法,绑定多个方法,最后一次的绑定的会替换前面绑定的DOM0分为两个事件:在标签内写onclick事件、在JS写onlicke=function(){}函数
<input type="button" onclick="alert(0);" /> <script> var btn = document.getElementsByClassName('button'); btn.onclick = function(){ alert(0); } </script>
打印一下root,root的onclick为null
给root添加onclick事件再打印 打印结果为fn(){}
DOM1:开始是W3C规范。专注于HTML文档和XML文档。
DOM2:对DOM1增加了样式表对象模型
2级DOM 监听方法:addEventListener()和removeEventListener(),IE下的DOM2事件是attachEvent和 detachEvent。
addEvenetListener()、removeEventListener() 有三个参数:
第一个参数是事件名(如click, IE是 onclick);
第二个参数是事件处理程序函数;
第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调用。addEventListener(‘onclick’, handle):可以为元素添加多个监听事件,触发时会按照添加顺序依次调用。
attachEvent 执行事件的顺序是从后往前的,跟addEventListener 刚好相反。
只有2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段, DOM0 不包含
DOM0 与DOM2区别
区别:
- 如果定义了两个dom0级事件,dom0级事件会覆盖
- dom2不会覆盖,会依次执行
- dom0和dom2可以共存,不互相覆盖,但是dom0之间依然会覆盖
- DOM0是私有属性赋值,DOM2是事件池的事件机制
DOM3:对DOM2增加了内容模型 (DTD 、Schemas) 和文档验证。
DOM3事件类型:UI事件、焦点事件、鼠标事件、滚轮事件、文本事件、键盘事件、合成事件、变动事件。
同时DOM3级事件也允许开发人员自定义一些事件。
-
js事件流
定义:"DOM2级事件"规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。以前面的例子,则会按下图顺序触发事件。
在DOM事件流中,事件的目标在捕获阶段不会接受到事件。这意味着在捕获阶段,事件从document到p后就定停止了。
下一个阶段是处于目标阶段,于是事件在p上发生,并在事件处理中被看成冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回document。
-
js防抖和节流
函数防抖(debounce):在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
场景:给按钮加函数防抖防止表单多次提交、对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数。
生活中的例子:坐电梯等。
函数节流(throttle):规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
场景:游戏中的刷新率、DOM元素拖拽、Canvas画笔功能。
生活中的例子:播放动画每一帧的频率等。
-
事件委托原理以及优缺点
事件委托就是基于js的事件流产生的,事件委托是利用事件冒泡,将事件加在父元素或者祖先元素上,触发该事件。
<body> <ul id="myLinks"> <li id="goSomewhere">Go somewhere</li> <li id="doSomething">Do something</li> <li id="sayHi">Say hi</li> </ul> <script type="text/javascript"> (function(){ var list = document.getElementById("myLinks"); EventUtil.addHandler(list, "click", function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); switch(target.id){ case "doSomething": document.title = "I changed the document's title"; break; case "goSomewhere": location.href = "http://www.wrox.com"; break; case "sayHi": alert("hi"); break; } }); })(); </script> </body>
上面的代码就是一个典型的事件委托案例。利用的原理就是事件冒泡,将事件加载父元素上,通过event参数来区别按钮的不同
优点:
-
减少事件注册,节省内存。比如,
- 在table上代理所有td的click事件。
- 在ul上代理所有li的click事件。
-
简化了dom节点更新时,相应事件的更新。比如
- 不用在新添加的li上绑定click事件。
- 当删除某个li时,不用移解绑上面的click事件。
缺点:
- 事件委托基于冒泡,对于不冒泡的事件不支持。
- 层级过多,冒泡过程中,可能会被某层阻止掉。
- 理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。
- 把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。
-
回流/重绘
回流(reflow):当DOM元素的结构或者位置发生改变都会引发回流,所谓回流,就是浏览器抛弃原有计算的结构和样式,从新进行DOM TREE或者RENDER TREE,非常非常非常...消耗性能。
回流会从html这个根节点开始递归往下,依次计算所有可见节点的几何信息,且回流是无可避免的
例子:容器尺寸的改变等、增加、删除 DOM节点
重绘(repaint):当某一个DOM元素样式更改浏览器会重新渲染这个元素。
例子:改变元素颜色、改变元素背景色 ……
注意:回流一定重绘,重绘不一定回流
关于display:none和visibility:hidden
- display:none 的节点是不可见的,因此不会被加入Render Tree的,而visibility:hidden的节点会被加入Render Tree
- display:none 改为 display:block 时,算是增加了一个可见节点,因此会重新渲染,所以触发回流,而visibility:hidden,节点是已经在Render Tree中的,所以会触发重绘
解决:采用虚拟dom、集中样式更改、元素批量修改、documentFragment文档碎片
浏览器相关
-
在地址栏输入url到最终展示界面期间发生了什么
-
http、https的区别
-
同源策略、跨域及原理
-
缓存及更新问题
-
新一代的前端存储方案--indexedDB
-
webview与原生应用交互
DOM
-
获取DOM节点的几个方法
-
如何给DOM节点上添加事件
服务器端知识
-
-
简单易懂的底层知识 —— 计算机的0和1是怎么产生的?
2020-04-09 22:46:24我们知道,在计算机的世界里,只有1和0。从简单的数学运算,到画面美爆的3D游戏,都是由数不清的0和1构成的。颇有点道家的 “ 一生二,二生三,三生万物” 的感觉。我们也大概知道,用高电位(如+5V)去表示1,用低...我们知道,在计算机的世界里,只有1和0。从简单的数学运算,到画面美爆的3D游戏,都是由数不清的0和1构成的。颇有点道家的 “ 一生二,二生三,三生万物” 的感觉。我们也大概知道,用高电位(如+5V)去表示1,用低电位(如+0V)去表示0。那么如何控制高低电位的输出呢?
相信很多人还记得小学时学的计算机基础课,第一台计算机ENIAC(埃尼阿克)于1946年在美国宾夕法尼亚诞生,它由将近18万个真空管(电子管)组成,重大30吨,耗电量惊人。
ENIAC使用真空管来完成高低电位的输出。真空管是二极管的前身。在一个真空玻璃管中放置两个电极,就构成了真空管。通过给阴极施加电压,使其温度上升来释放电子。
此时若阳极处于一个稍微高一点的电位,真空管内的自由电子就会被吸引过去,将电路联通。
可以通过对阴极施加不同大小的电压,来控制阴极释放的电子的数量,从而控制电路的联通与否。以此来产生01信号。
真空管的改进版,是在真空玻璃管中间添加一个栅极(Grid)。通过对栅极施加不同的电压,使得它阻断或加强电子的流动,从而得以实现对电流的快速控制。
然而,真空管体型比较笨重,并且它是通过对阴极加热,来使得阴极释放电子,所以它比较不稳定,容易出现故障,并且耗电还高(想象一下计算机里的每个01信号都是通过对一个电灯泡进行加热来控制,而ENIAC就由将近18万个这样的灯泡组成)。不禁想起了三体里所描绘的人形计算机阵列,吓死宝宝了。
后来,聪明的科学家就发现了晶体管。
它使用了半导体来代替电极。4价硅,掺杂一些5价磷,来制造一个电子发射极NMOS(Negative Metal Oxide Semiconductor);4价硅,掺杂一些3价硼,构成了电子接收极PMOS(Positive Metal Oxide Semiconductor)。将P和N排列在三个交替层,构成了NPN型晶体管。每一层都带有一个Terminal。构成电子发射极(Emitter),基极(Base),电子接收极(Collector)。
电子从Emitter流到Base,产生的电流,称为基极电流(Base Current)
电子从Emitter流到Collector,产生的电流,称为集电极电流(Collector Current)
当我们施加一个微弱的电压在Emitter和Base之间,让它们之间形成电流,就会导通这个晶体管,在Emitter和Collector之间产生一个很大的电流。通常来说,在Emitter和Base之间施加一个>0.7V的电压,即可导通晶体管,产生高电位,再通过模数转换,变为信号1;
施加一个<0.7V的电压,晶体管不导通,产生低电位,即为信号0。
通过这种微弱的电压变化,来控制输出1或0。相比于真空管,晶体管的优点在于它体积非常小,并且效率高(真空管需要通过加热阴极释放电子,而晶体管不需要加热,只需要控制微弱的电压变化,因为不需要加热,晶体管也更耐用,能耗也更低)。现代计算机的CPU芯片只有指甲盖大小,上面却布满了几十亿个晶体管,每秒可以进行上万亿次计算。一个主频为2.4GHz的CPU,简单地来讲,理论上每秒可以进行2,400,000,000次运算。
通过不断地断电,通电,来推动CPU一步一步地执行计算。一次通电断电,可以简单地认为是一个时钟周期,这个是通过时钟发生器来控制的,一个时钟发生器,每秒能振动多少次,就是他振动的频率,即时钟频率。时钟发生器也叫晶振,全称晶体振荡器,是从一块石英晶体上切下的薄片,再进行加工制成的。晶振为CPU提供了基本的时钟频率,它一下一下的振动,就像一颗搏动的心脏。
参考视频:
https://haokan.baidu.com/v?vid=16026741635006191272&pd=bjh&fr=bjhauthor&type=video -
快速把文件夹内所有底层照片合并到一个文件夹内
2018-12-23 16:36:16本来想用os.listdir遍历的,但发现用os.walk更好,通过内置遍历可以直接获得最底层的所有文件,简单粗暴我喜欢,以后如果有多层遍历的话就用os.walk了 另外还有个判断是否文件夹的代码: #判断是文件夹还是文件 ... -
趣话题:底层码农的心酸,那么我们 如何避免成为底层码农呢?
2021-03-16 14:24:53996的福报,007的办公室猝死,尤其是底层码农更为辛苦,接下来博文以亲身体会来告诉大家如何避免成为底层码农。喜欢博主的小伙伴,动动你的小手,一键三连吧. 端正心态 制定目标我们人人都会,当我们立下flag... -
AD如何仅显示顶层和顶层丝印,或仅显示底层和底层丝印。
2021-06-07 21:12:45右键单击下面层的选项卡。如图“层设定”->"Board Layer Sets" 选择“空掩膜” 新建个名字,如topshow,然后在右边勾选上需要显示的层。 像下面这样,就是显示顶层所有需要的层。 当你选择Topshow后,... -
这应该是把计算机网络五层模型讲的最好是文章了,看不懂你打我
2019-10-25 12:49:08在成千上万的计算机中,为什么一台计算机能够准确着寻找到另外一台计算机,并且把数据发送给它呢? 可能很多人都听说过网络通信的 5 层模型,但是可能并不是很清楚为什么需要五层模型,五层模型负责的任务也有可能... -
redis中zset底层实现原理
2020-07-14 12:00:27比如,一个节点随机出的层数是3,那么就把它链入到第1层到第3层这三层链表中。为了表达清楚,下图展示了如何通过一步步的插入操作从而形成一个skiplist的过程: 从上面skiplist的创建和插入过程可以看出,每一个节点... -
Python列表list底层源码实现及解析
2022-03-31 18:20:52Python底层是用C写的,因此列表在底层相当结构体变量,主要源码如下所示(实际上会有很多东西,后续的源码同理)。 前面之所以有两个指针,是因为一个list对象相当于双向链表中的一个节点,需要前指针和后指针进行... -
DL之DNN:利用numpy自定义三层结构+softmax函数建立3层完整神经网络全部代码实现(探究BP神经网络的底层思想...
2020-03-20 14:19:38DL之DNN:利用numpy自定义三层结构+softmax函数建立3层完整神经网络全部代码实现(探究BP神经网络的底层思想) 目录 输出结果 代码实现 输出结果 代码实现 #DL之NN:利用numpy自定义三... -
Synchronized底层实现
2019-05-28 22:34:08关于synchronized的底层实现,网上有很多文章了。但是很多文章要么作者根本没看代码,仅仅是根据网上其他文章总结、照搬而成,难免有些错误;要么很多点都是一笔带过,对于为什么这样实现没有一个说法,让像我这样的... -
@Transactional底层原理
2019-09-09 21:08:330 导致脏读 Read-Committed 1 避免脏读,允许不可重复读和幻读 Repeatable-Read 2 避免脏读,不可重复读,允许幻读 Serializable 3 串行化读,事务只能一个一个执行,避免了脏读、... -
HashMap底层实现原理详解
2021-03-01 21:36:44随着JDK版本的迭代,JDK1.8对HashMap底层的实现进行了优化,列入引入红黑树的数据结构和扩容的优化等。本文结合JDK1.7和JDK1.8的区别,深入探讨HashMap的数据结构实现和功能原理。 Java为数据结构中的映射定义了一个... -
MySQL底层原理综述
2019-02-02 23:17:17事务提交后所做的修改才会被另一个事务看见,可能产生一个事务中两次查询的结果不同。 REPEATABLE READ(可重读): 只有当前事务提交才能看见另一个事务的修改结果。解决一个事务中两次查询的结果不同的题。 ... -
Android Q消息循环:休眠、唤醒的底层原理及native层源码分析
2020-05-20 17:43:37本文将分析Handler消息机制的内核层实现,以及Handler机制native层源码分析。我们将讨论消息循环的休眠、唤醒的实现原理,以及它们依赖的epoll机制的使用介绍等内容。 -
最新Vue底层原理实现概述
2020-07-27 08:45:007.27—7.31前端限时0元课程 一、技巧:《让你精通JS—带你吃透JS两大底层》 1、JavaScript 代码的执行顺序 2、JavaScript 的内存机制 3、JavaScript 的性能监控 二、实战:《网易严选架构探析,如何打造中间层》 1... -
图解Redis底层数据结构实现原理
2020-06-26 11:58:38比如:一个节点随机出的层数是3,那么就把它链入到第1层到第3层这三层链表中。 skiplist中一个节点的层数(level)是随机出来的,而且新插入一个节点不会影响其它节点的层数。因此,插入操作只需要修改插入节点前后... -
前端必经之路:浏览器底层工作原理
2019-06-27 16:48:45今天要写的是一篇关于浏览器底层...今天我将带领大家,逐步剖析我们在使用浏览器访问网页的过程中,浏览器究竟为我们做了些什么。 在进入正文之前,先给大家引入一个话题。相信每个人都曾迷惑于互联网一些复杂难... -
Java 和C# 最大的不同是对底层的控制能力不同
2021-11-13 14:48:46我觉得抛开语法而谈,最主要的还是对底层的控制能力不同。 比如在 C# 里面你能干的: var x = new int[10]; fixed (int* p = x) { Console.WriteLine(*((long*)p - 1)); // 10 } 上述代码会输出 10,为什么?... -
程序员的底层思维:逻辑思维
2021-07-31 11:47:36“你的底层逻辑是什么?” “说说你的逻辑思维能力体现在哪儿?” 在日常交流中,我们会频繁的使用“逻辑”这个词。但能够清晰的说出逻辑的定义(什么是逻辑)应该不多,能够正确的掌握逻辑推理的人就应该更少了。... -
深入理解 AQS 底层实现原理
2020-11-25 15:57:23总结: 一个线程中的多个流程可以获取同一把锁,持有这把同步锁可以再次进入 自己可以获取自己的内部锁 可重入锁的种类: 隐式锁:关键字syncronized使用的锁,默认是可重入锁 (同步代码块,同步方法) 显式锁: 即... -
为什么要在MVC三层架构上再加一层Manager层?
2021-10-21 12:48:18Service层:主要是处理业务逻辑和事务 Dao层:负责与底层数据库MySQL,Oracle等进行数据交互 可是随着我们的业务逻辑越来复杂,代码写的越来越多,这种简单的三层架构的问题也越来越明显。 MVC架构弊端 传统的MVC... -
iOS之深入解析通知NSNotification的底层原理
2021-07-10 18:11:02} } @end 二、底层实现 ① 通知结构分析 NSNotification 是一个类蔟不能够实例化,当调用 initWithName:object:userInfo: 方法的时候,系统内部会实例化 NSNotification 的子类 NSConcreteNotification。... -
Redis的五种数据结构的底层实现原理
2021-01-31 02:49:22Redis的五种数据结构的底层实现原理: 1、String底层实现方式:动态字符串sds 或者 long; 2、Hash底层实现方式:压缩列表ziplist 或者 字典dict; 3、List在Redis3.2之前的底层实现方式:压缩列表ziplist 或者 双向... -
最详细HashMap底层详解(附常见面试题)
2020-05-01 23:59:08} //如果key为null,存储位置为table[0]或table[0]的冲突链上 if (key == null) return putForNullKey(value); int hash = hash(key);//对key的hashcode进一步计算,确保散列均匀 int i = indexFor(hash, table.... -
CAS底层原理 | JVM相关知识
2020-07-08 21:15:52(这个涉及计算机理论基础,本篇博客先不做解释) 3、ABA问题。(在图示第3步,尽管在比较值的时候是一样的,但其实在当前线程第一次读取到值之后第二次读取对比之前,可能已经被其他线程修改成其他值又修改回原值。... -
深入理解 MySQL 底层实现
2017-12-13 00:00:00本文来自作者 默默 在 GitChat 上分享 「深入理解 MySQL 底层实现」,「阅读原文」查看交流实录。「文末高能」编辑 | 哈比MySQL 的常用引擎1. InnoDBInnoDB 的存储文件有两个,后缀名分别是 .frm 和 .idb,其中 ... -
如何设置div在底层
2018-12-10 20:07:23通过设置div这两个position:relative;z-index:0可以调节