导图社区 javascript思维导图
Javascript基础导图,涵盖了ECMA语法及BOM和DOM,可以作为初学者的记忆手册。
编辑于2020-11-19 10:18:26javascript
单线程 弱语言 javascript高级编程语言 :自动执行垃圾回收机制
组成
ECMAscript
BOM
BOM 的核心对象是 window(所有window都可以省略),它表示浏览器的一个实例
打开窗口
window.open()
关闭窗口
window.close()
location地址栏对象
hash锚点

返回 URL 中的 hash(#号后跟零或多个字符),如果 URL 中不包含散列,则返回空字符串
"#contents"
href

返回当前加载页面的完整URL。而 location 对象的 toString() 方法也返回这个值
"http:/shijiajie.com"
search

返回URL的查询字符串。这个字符串以问号开头
"?q=javascript"
reload
DOM
document 文档 整个文档从<html></html>结束
节点
DOM(文档对象模型)可以将任何HTML、XML文档描绘成一个多层次的节点树。所有的页面都表现为以一个特定节点为根节点的树形结构。html文档中根节点为document节点。 所有节点都有nodeType属性,代表节点的不同类型,通过nodeType属性可以来判断节点的类型
nodeType

Element类型(元素节点):nodeType值为 1
Text类型(文本节点):nodeType值为 3
Comment类型(注释节点):nodeType值为 8
Document类型(document节点):nodeType值为 9
创建
document.createElement('标签名') 创建标签只能是document
插入
父级.appendChild(子级) 在最后追加
父级.insertBefore(把谁,谁的前面)
1、appendChild和insertBefore在操作已经存在的元素的时候,是剪切而不是复制 2、insertBefore(把谁,谁的前面),如果第二个参数是undfined或者null,默认变成appendChild
删除元素
父元素.removeChild(子元素)
修改替换节点
父级.replaceChild(新节点,旧节点)
查
获取父节点
obj.parentNode
 
获取的是结构的父级,最高级 document 再往上null 是w3c标准
obj.offsetParent
   
获取的是定位的父级,最高级 body 在往上null
获取子节点
childNodes
 包括文本节点
使用childNodes获取子节点的时候,childNodes返回的是子节点的集合,是一个数组的格式。他会把换行和空格也当成是节点信息。
obj.children
 
返回出一个数组。对其获取子元素的访问只需按数组的访问形式即可。
obj.firstChild
 
包含文本节点 但是低版本浏览器下只能获取元素节点
obj.firstElementChild
 
高级浏览器下能获取 低级浏览器下获取的是undefined 相当于obj.children[0]
obj.lastChild
同上
obj.lastElementChild
同上
获取上一个兄弟节点
obj.previousSibling
同上
obj.previousElementSibling
 
同上
下一个兄弟节点
nextSibling
同上
nextElementSibling
同上
克隆
obj.cloneNode() 只能克隆标签
 
obj.cloneNode(true)深度克隆
 
节点的内容
innerHTML
 
返回的是标签内的 html内容,包含html标签。
innerTEXT
  p标签的换行所以有空格 换成span就成了555512312
返回的是标签内的文本值,不包含html标签
outerHTML
 
是把当前标签的全部内容包括标签本身也全部取出来了
outerTEXT
只输出当前标签内的文本内容
与innerTEXT 几乎没区别
操作节点属性
.
[]
.后面不能跟变量,[]里面可以 他俩操作是存在(w3c规定)属性
data-xxx 自定义属性
dataset.xxx

自定义和固定属性都可以

getAttribute('属性名')
子主题
setAttribute('属性名','属性值')
removeAttribute('属性名)
操作样式
obj.style
获取行间样式,这个方法只能JS只能获取写在html标签中的写在style属性中的值(style=”…”),而无法获取定义在<style type="text/css">里面的属性。
getComputedStyle(要获取样式的元素).样式 只兼容高级浏览器

getComputedStyle(要获取样式的元素,false|null).样式
后面再加一个这样的参数是为了兼容火狐的低版本浏览器
计算过后的宽度 content 内容超出的时候就是内容宽高
元素.currentStyle.样式
只兼容ie
获取dom节点的方式
静态 css选择符模式
不是实时的,保存的是当时的状态,是一个副本,即:在以后的代码中通过方法使所选元素发生了变化,但该值依然不会改变,因此使用有局限性,一般不用,除非就想得到副本 ES6新出了两种获取方式 只兼容高级
document.querySelector()
返回结果为一个元素
document.querySelectorAll()
返回为一个数组
动态
document.getElementById();
document.getElementsByTagName();
返回为一个数组
document.getElementsByClassName()
返回为一个数组
document.getElementsByName();
返回为一个数组
元素大小 所取值都没有单位
偏移量计算

obj.offsetHeight
offsetWidth
包括content+padding+border
offsetLeft
offsetTop
某个元素在页面上的偏移量
function getElementLeft(element){ var actualLeft = element.offsetLeft; var current = element.offsetParent; while (current !== null){ actualLeft += current.offsetLeft; current = current.offsetParent; } return actualLeft; } //top同理
客户区大小
元素内容及其内边距所占据的空间大小 
clientHeight
浏览器视口大小:document.documentElement.clientWidth; 或document.body.XXX
clientWidth
content+padding滚动条不算
滚动大小
是包含滚动内容的元素的大小 
scrollHeight:在没有滚动条的情况下,元素内容的总高度
,带有 垂直滚动条的页面总高度就是 document.documentElement.scrollHeight。
scrollWidth
确定文档的总高度时(包括基于视口的小高度只有content和padding
,必须取得 scrollWidth/clientWidth 和 scrollHeight/clientHeight 中的大值,才能保证在跨浏览器的环境下得到精确的结果。下面就 是这样一个例子。 var docHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight); var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth); 注意,对于运行在混杂模式下的 IE,则需要用 document.body 代替 document.document- Element
scrollLeft:被隐藏在内容区域左侧的像素数。可以改变元素的滚动位置。
scrollTop
事件
JavaScript与html之间的交互是通过事件实现的
添加方法

html级
<div onclick="show()"></div>
DOM0级
oDiv.onclick=function(){}同一个元素不能加多个相同的事件
解除oDiv.onclick=null;
DOM2级
元素.addEventListener('不加on的事件名',函数名,是否事件捕获);同一个元素能加多个相同的事
删除:元素.removeEventListener('不加on的事件名',函数名,是否事件捕获);
IE添加方式
oBtn.attachEvent('加on的事件名',函数名)
删除:oBtn.detachEvent('加on的事件名',函数名)
事件流(从页面中接收事件的顺序)
事件冒泡(IE的事件流)
事件由文档中嵌套最深的节点接送然后逐级向上传播直到document对象
事件捕捉(网景)
元素事件触发后,从document开始逐层向下传播。如果遇到相同事件继续触发,没有继续向下传递,直达当前元素
取消冒泡(捕捉也有效)
event.cancelBubble=true;全部兼容
event.stopPropagation() //IE不支持
数据类型
复合数据类型
标识符
由数字字母下划线和$组成
不能以数字开头
区分大小写
异步
setTimeout(function,time)
设置延时 不会循环
setInterval(function,time)
设置间隔 会循环
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的Event Loop(事件循环)
面对对象(Object-Oriented,OO)
面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可 以创建任意多个具有相同属性和方法的对象。前面提到过,ECMAScript中没有类的概念,因 此它的对象也与基于类的语言中的对象有所不同。 ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来讲, 这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射 到一个值。正因为这样(以及其他将要讨论的原因),我们可以把 ECMAScript的对象想象成散列表:无 非就是一组名值对,其中值可以是数据或函数。 每个对象都是基于一个引用类型创建的,这个引用类型可以是第 5章讨论的原生类型,也可以是开 发人员定义的类型。
对象
一堆属性和方法的集合
属性
数据属性
四个描述其行为的特性
[[Configurable]] 表示能否通过 delete 删除属性重新定义属性 默认为true、 [[Enumerable]] for-in 循环返回属性 true [[Writable]]表示能否修改属性的值 true [[Value]]:包含这个属性的数据值 undefined
修改属性默认的特性
ECMAScript 5的 Object.defineProperty(对象,属性名,描述符对象)方法: 描述符对象:configurable、enumerable、writable 和 value

访问器属性
函数
函数的返回值
return xx 先执行return右边 函数会在执行完 return 语句之后停止并立即退出。因此,位于 return 语句之后的任何代码 都永远不会执行
return false; 阻止浏览器默认行为
函数的基本语法
function functionName(形参,,..){}:函数声明
var show=function(){ }:表达式函数
函数名()进行调用
匿名函数(自执行)
(function(index){ })();
优点
解决命名冲突
可以解决参数i问题

运行结束就会释放内存
变量,作用域和内存
变量
基本数据类型
基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中; 从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本; 引用类型的值是对象,保存在堆内存中; 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针; 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同 一个对象; 确定一个值是哪种基本类型可以使用 typeof 操作符,而确定一个值是哪种引用类型可以使用 instanceof 操作符 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链; 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全 局环境; 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据; 变量的执行环境有助于确定应该何时释放内存。 JavaScript 是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题。可 以对 JavaScript 的垃圾收集例程作如下总结。 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。 “标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然 后再回收其内存。 另一种垃圾收集算法是“引用计数”,这种算法的思想是跟踪记录所有值被引用的次数。JavaScript 引擎目前都不再使用这种算法;但在 IE 中访问非原生 JavaScript 对象(如 DOM 元素)时,这种 算法仍然可能会导致问题。 当代码中存在循环引用现象时,“引用计数”算法就会导致问题。 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回 收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。
基本类型值
数字 number
字符串 string
布尔值 boolean
undefined
undefined情况
变量声明了没有赋值
函数没有返回值
函数没有传参时
获取对象身上不存在的属性
null
一个变量向另一个变量复制基本类型值,会在变量对象上创建一个新值,然后把该值复制 到为新变量分配的位置上 两个变量相互不影响
var num1 = 5; var num2 = num1; 在此,num1 中保存的值是 5。当使用 num1 的值来初始化 num2 时,num2 中也保存了值 5。但 num2 中的 5与 num1 中的 5是完全独立的,该值只是 num1 中 5的一个副本。此后,这两个变量可以参与任 何操作而不会相互影响。图 4-1形象地展示了复制基本类型值的过程。 
引用类型值
object
当从一个变量向另一个变量复制引用类型的值时,会将存储在变量对象中的值(是指针而这个指针指向存储在堆中的对象)复制一份放到 为新变量分配的空间中。不同的是,
var obj1 = new Object(); var obj2 = obj1; obj1.name = "Nicholas"; alert(obj2.name); //"Nicholas" 首先,变量 obj1 保存了一个对象的新实例。然后,这个值被复制到了 obj2 中;换句话说,obj1 和 obj2 都指向同一个对象。这样,当为 obj1 添加 name 属性后,可以通过 obj2 来访问这个属性, 因为这两个变量引用的都是同一个对象。图 4-2展示了保存在变量对象中的变量和保存在堆中的对象之 间的这种关系。 
局部变量
在函数定义内声明的变量是局部变量。每当执行函数时,都会创建和销毁该变量,且无法通过函数之外的任何代码访问该变量。可以把函数参数看作是局部变量
全局变量
在函数定义之外声明的变量是全局变量,它的值可在整个程序中访问和修改。如果变量声明没有加关键字var 该值会被添加到全局即使在函数中执行结束也不会被删除
function add(num1, num2) { sum = num1 + num2; return sum; } var result = add(10, 20); //30 alert(sum); //30 这个例子中的变量 sum 在被初始化赋值时没有使用 var 关键字。于是,当调用完 add()之后,添 加到全局环境中的变量 sum 将继续存在;即使函数已经执行完毕,后面的代码依旧可以访问它。 function add(num1, num2) { var sum = num1 + num2; return sum; } var result = add(10, 20); //30 alert(sum); //由于 sum 不是有效的变量,因此会导致错误
检测
typeof()
var s = "Nicholas"; var b = true; var i = 22; var u; var n = null; var o = new Object(); alert(typeof s); //string alert(typeof i); //number alert(typeof b); //boolean alert(typeof u); //undefined alert(typeof n); //object alert(typeof o); //object
number->number,string->string,boolean->boolean
undefined->undefined
null->object,obj->obj
function->function
正则->function ie,firefox->obj
instanceof
xx instanceof Array;返回true,false
变量查询
从内到外(从局部到全局)
var color = "blue"; function getColor(){ return color; } alert(getColor()); //"blue" ; 
作用域
全局作用域
最外层函数 和在最外层函数外面定义的变量拥有全局作用域
var outVariable = "我是最外层变量"; //最外层变量 function outFun() { //最外层函数 var inVariable = "内层变量"; function innerFun() { //内层函数 console.log(inVariable); } innerFun(); } console.log(outVariable); //我是最外层变量 outFun(); //内层变量 console.log(inVariable); //inVariable is not defined innerFun(); //innerFun is not defined
所有末定义直接赋值的变量(由于变量提升使之成为全局变量)自动声明为拥有全局作用域
function outFun2() { variable = "未定义直接赋值的变量"; var inVariable2 = "内层变量2"; } outFun2();//要先执行这个函数,否则根本不知道里面是啥 console.log(variable); //未定义直接赋值的变量 console.log(inVariable2); //inVariable2 is not defined
变量提升:函数及变量的声明都将被提升到函数的最顶部变量(全局变量提升到script之后函数提升到该函数顶部),可以在使用后声明,也就是变量可以先使用再声明(仅限变量会提升 初始化不会提升) 应在每个作用域开始前声明变量
x = 5; // 变量 x 设置为 5 elem = document.getElementById("demo"); // 查找元素 elem.innerHTML = x; // 在元素中显示 x var x; // 声明 x 结果为5 var x = 5; // 初始化 x elem = document.getElementById("demo"); // 查找元素 elem.innerHTML = "x 为:" + x + ",y 为:" + y; // 显示 x 和 y var y = 7; // 初始化 y x 为:5,y 为:undefined
所有window对象的属性拥有全局作用域
一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等。
弊端: 污染全局命名空间, 容易引起命名冲突。
函数作用域
声明在函数内部的变量,和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。
块级作用域{}
ES6新加let和const使JavaScript存在块级作用域
let 和 var区别 const
相同
都用来声明变量。
不同
let
所声明的变量,只在let命令所在的代码块{}内有效。
var
在全局范围内都有效
“变量提升”let没有
会存在即变量可以在声明之前使用,值为undefined
// var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
let特性
暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。也意味着typeof不再是一个百分之百安全的操作
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)
if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 }
let不允许在相同作用域内,重复声明同一个变量。
// 报错 function func() { let a = 10; var a = 1; } // 报错 function func() { let a = 10; let a = 1; }
function func(arg) { let arg; } func() // 报错 function func(arg) { { let arg; } } func() // 不报错
let实际上为 JavaScript 新增了块级作用域
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
没有块级作用域会出现
内层变量可能会覆盖外层变量。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
用来计数的循环变量泄露为全局变量。
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
const
const声明一个只读的常量。一旦声明,常量的值就不能改变
const一旦声明变量,就必须立即初始化,不能留到以后赋值。
声明不赋值,就会报错
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
if (true) { console.log(MAX); // ReferenceError const MAX = 5; }
const声明的常量,也与let一样不可重复声明
var message = "Hello!"; let age = 25; // 以下两行都会报错 const message = "Goodbye!"; const age = 30;
本质
并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
ES6一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性
子主题
子主题
原本JavaScript没有块级作用域
if (true) { var color = "blue"; //并没有在结束后销毁 } alert(color); //"blue" for(var i=0;i<10;i++){ } alert(i);//10 在其他语言里从,c++,Java等 i 只能存在循环里
JavaScript垃圾回收(周期运行)
对没用的变量进行回收
标记清除
对存储在内存的变量进行标记,对‘进入环境’的变量和被引用的变量去除标记,对存在标记的值进行清除并回收它们所占的内存空间
引用计数
对引用次数进行统计,如果引用次数为0时收回所占内存空间,在下次垃圾回收时清除值所占有的内存 不常用 存在循环引用问题 (变量相互引用的情况等)需手动清除
引用类型
对象(引用类型的值)是某个特定引用类型的实例。新对象是使用 new 操作符后跟一个构造函数来创建的。 构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的
Object类型
声明
var obj = {name:qq}
var obj = new Object(); obj.name=qq;
访问对象
obj.name 除了变量一般推荐用这种方式
obj['name']
var a= ‘name’obj[a]
Array类型
声明
var colors = new Array(); var colors = new Array(20);//长度为20的数组 var colors = new Array("red", "blue", "green");
var colors = ["red", "blue", "green"];
var values = [1,2,];// 不要这样!这样会创建一个包含 2 或 3 项的数组
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组 colors[99] = "black"; // (在位置 99)添加一种颜色 alert(colors.length); // 100
cookie,localStorage和sessionStorage
cookie
设置
function setCookie(name,value,date){ var oDate = new Date(); oDate.setDate(oDate.getDate()+3); if(date){ document.cookie = name+'='+value+';expires='+oDate+';path=/;' }else{ document.cookie = name+'='+value+';path=/;' } } setCookie('aaa',111,3);
document.cookie = 'name=value;path=/;expires=date'
获取
function getCookie(name){ var str=document.cookie; var arr=str.split('; '); for(var i=0;i<arr.length;i++){ var arr2=arr[i].split('=');//arr2 [aaa,111] if(arr2[0]==name){ return arr2[1]; } } return ''; }
document.cookie
清除
function removeCookie(name){ setCookie(name,'',-2); }
特点
1、必须运行在服务器环境下 2、cookie是有过期时间的 默认的过期时间是一个session(一次会话),从浏览器的打开到关闭 过期时间可以设置 3、cookie是一条一条存的,取得时候是获取的全部 4、cookie是有容量大小的 同一个域里面 总量4k左右 条数 不一定 cookie比较珍贵的,一套网站只有一套cookie不能乱用 5、有目录区别 平常在项目中cookie全部设置目的 / 根目录 6、不管你存的是什么,取出来的都是字符串 7、不安全 8、在服务器环境下,每次请求都会伴随着cookie发送给后台
缺点
1、容量小 2、每次请求都会向服务器发送 3、存储和获取比较麻烦
localStorage
标准
设置
localStorage.setItem(name,value)
获取
localStorage.getItem(name)
如果没有是null
删除
localStorage.removeItem(name)
清空
localStorage.clear() 清除所有
不标准
设置
localStorage.name=value;
获取
localStorage.name 如果没有是undefined
删除
delete localStorage.name
特点
1、存储在浏览器中 2、容量5M 3、不会向服务器发送数据 4、没有过期时间 5、没有路径的限制
sessionStorage
操作 不是标准的 设置:sessionStorage.name=value; 获取:sessionStorage.name 如果没有是undefined 删除:delete sessionStorage.name 标准的 设置:sessionStorage.setItem(name,value) 获取 sessionStorage.getItem(name) 如果没有是null 删除 sessionStorage.removeItem(name) sessionStorage.clear() 清除所有
和localStorage用法基本相同就把local Storage变更成sessionStorage;
cookie和localStorage
区别
1、容量
2、会不会向后台发送
3、过期时间
4、路径不同
5、cookie查询到的结果查询不到是空字符串, localStorage返回的是undefined或者null
6、没有目录的限制
共同点
不安全 不能跨域 不能跨浏览器
localStorage和sessionStorage
区别
sessionStorage 叫做临时存储
关闭浏览器就消失
在函数传参也是一样的
//引用类型 function setName(obj) { obj.name = "Nicholas"; } var person = new Object(); setName(person); alert(person.name); //"Nicholas" person()发生变化 //基本类型 function addTen(num) { num += 10; return num; } var count = 20; var result = addTen(count); alert(count); //20,没有变化 alert(result); //30
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); new Object()局部变量 obj.name = "Greg"; } var person = new Object(); setName(person); alert(person.name); //"Nicholas"
这个例子与前一个例子的唯一区别,就是在 setName()函数中添加了两行代码:一行代码为 obj 重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的 name 属性。在把 person 传递给 setName()后,其name 属性被设置为"Nicholas"。然后,又将一个新对象赋给变量 obj,同时将其 name 属性设置为"Greg"。如果 person 是按引用传递的,那么 person 就会自动被修改为指向其 name 属性值 为"Greg"的新对象。但是,当接下来再访问 person.name 时,显示的值仍然是"Nicholas"。这说明 即使在函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写 obj 时,这 个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。