1.JavaScript的构成
虽然 JavaScript 和 ECMAScript 通常都被人们用来表达相同的含义,但 JavaScript 的含义却比 ECMA-262 中规定的要多得多。没错,一个完整的 JavaScript 实现应该由下列三个不同的部分组成。
-
核心(ECMAScript)
-
文档对象模型(DOM)--document Object Module
-
浏览器对象模型(BOM)--Browser Object Module
ECMAScript:是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,但实际上后两者是ECMA-262标准的实现和扩展
BOM: Browse Object Model,提供与浏览器交互的方法和接口
DOM: Document Object Model,提供访问和操作网页内容的方法和接口
2.JavaScript的特点
JS 运行在客户端--浏览器
JS 解释器,负责js 的执行; V8 引擎负责js 的执行,把js 代码编译成机器码; JS 定位成弱类型,脚本语言:在运行的时候,不需要编译。
(1) JavaScript是一种脚本编程语言
这里要解释一下什么是脚本语言,也许很多读者之前已经接触过脚本语言,其实脚本语言是一种简单的程序,它是由一些ASCII字符构成,可以直接用记事本等文本编辑器编写,事先也不用编译,只需要利用解释器就可以解释执行。
前面已经介绍过JavaScript是一种脚本语言,是采用小程序段的方式实现编程。正如其它脚本语言一样,JavaScript也是一种解释性语言,它提供了一个容易的开发过程。JavaScript的基本结构形式与其它高级语言类似(如C、C++、VB、Delphi等),但它与这些高级语言不同的是,其它高级语言需要先进行编译然后才能被执行,JavaScript则是在程序运行过程中一条一条被解释执行。JavaScript与HTML结合在一起,极大地方便了用户的使用操作。
(2) JavaScript是面向对象的语言
JavaScript是一种面向对象的语言,那就是说,它本身也可以创建对象,以及调用对象的操作。因此,JavaScript的诸多功能可以来自于脚本环境中各种对象的调用。
(3) JavaScript的简单性
之所以说JavaScript是简单的,首先是因为它是一种基于Java的基本语句和控制流之上的简单而紧凑的设计,这对于更进一步学习Java是一个非常好的过渡,其次是因为它的所有变量都是弱类型,并且都没有像其它需要编译的高级语言那样使用严格的数据类型。
(4) JavaScrip的安全性
JavaScrip就像Java一样是一种非常安全的语言,它不允许访问本地的硬盘,并且不允许把数据存入到服务器上,还不允许对网络文档进行修改和删除,只允许通过浏览器实现信息浏览和动态交互,这样确保了对数据的安全化操作。
(5) JavaScript的动态性
之所以说JavaScript是动态的,是因为它可以直接对用户或客户的输入操作做出响应,而不必经过web服务器或web服务器程序。
JavaScript对用户的响应是采用事件驱动的方式进行的。简单地说,事件驱动是指在页面中执行了某种操作后产生相应的动作,例如,按下鼠标、选择菜单以及移动窗口等都可以被视为事件,当事件发生后,就会有相应的事件响应该事件。
(6) JavaScript的跨平台性
JavaScript同Java一样是与操作环境无关的,它只依赖于浏览器,只要客户的计算机浏览器支持JavaScrip,它就可以被正确解释执行。从而实现一次编写,到处运行。
3.事件
事件三要素:事件源 事件 事件处理函数
事件源:标签
事件:click dblclick mousemove...
事件处理函数: 干什么
事件源.on事件 = 事件处理函数
(1)标签的获取:
通过类名获取:document.getElementsByClassName("类名")
通过id获取:document.getElementById("id名")
通过标签名获取document.getElementsByTagName("标签名")
通过name属性获取:document.getElementsByName("name属性值")
通过css选择器获取:document.querySelector("css选择器")
(2)标签属性的相关操作:
<div class="box box1">box1</div>
<form>
账号:<input type="text" name="account">
密码:<input type="text" name="pwd">
<input type="submit">
</form>
<img src="https://img1.baidu.com/it/u=917108111,1107211158&fm=253&fmt=auto&app=138&f=JPEG?w=650&h=274" alt="">
<script>
let box1 = document.querySelector(".box1");
box1.setAttribute("id","mybox1");
box1.setAttribute("newAttr","newAttr");
box1.setAttribute("class",box1.getAttribute("class")+" newclass");
box1.removeAttribute("newAttr");
// 对标签属性直接进行操作: 标签.属性 = 属性值;
box1.id = "newid";
document.querySelector("img").src = "https://img1.baidu.com/it/u=1294011985,3019794183&fm=253&fmt=auto&app=138&f=JPEG?w=631&h=405";
document.querySelectorAll('input')[0].value = "123456";
console.log(document.querySelector("img").src);
console.log(document.querySelectorAll('input')[0].value);
// 注意:类名不能直接操作(class属性不能直接操作)
// box1.class = "myNewclass";
</script>
(3)标签类名的相关操作:
<div class="box box1" id="mybox1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<span>我是span</span>
<form>
账号:<input type="text" name="account">
密码:<input type="text" name="pwd">
<input type="submit">
</form>
<script>
let box2 = document.querySelector('.box2');
console.dir(box2);
console.log(box2.className);
console.log(box2.classList);
// 类名的添加
box2.classList.add("newclass");
box2.classList.add("newclass");
// 判断标签是否包含某个类名
console.log(box2.classList.contains("newclass123"));
// 类名的移除
box2.classList.remove("newclass");
// 判断某个标签是否拥有某个类名,有就删除,没有就添加
box2.classList.toggle("box");
// 标签类名的替换
// box2.classList.replace("box2","bbb");
</script>
(4)标签内容的获取和修改:
<div class="box box1" id="mybox1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">box3</div>
<div class="box box4">box4</div>
<span>我是span</span>
<form>
账号:<input type="text" name="account">
密码:<input type="text" name="pwd">
<input type="submit">
</form>
<script>
let box1 = document.getElementById('mybox1');
console.dir(box1);
box1.onclick = function(){
// console.log(document.getElementsByTagName('span'));
document.getElementsByTagName('span')[0].classList.toggle("active");
}
console.log(box1.innerHTML);
console.log(box1.innerText);
console.log(box1.outerHTML);
// 修改
// box1.innerHTML = `<h2>修改后的内容</h2>`;
box1.innerText = `<h2>修改后的内容</h2>`;
</script>
(5)标签的删除 、复制和替换:
<div class="box box1" id="mybox1">box1</div>
<div class="box box2">box2</div>
<div class="box box3">
<p>我是box3里面的p</p>
</div>
<div class="box box4">box4</div>
<span>我是span</span>
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
</ul>
<form>
账号:<input type="text" name="account">
密码:<input type="text" name="pwd">
<input type="submit">
</form>
<script>
// 标签的删除
let box2 = document.querySelector('.box2');
// box2.remove();
let form = document.querySelector('form');
let account = document.getElementsByName('account')[0];
console.log(form,account);
// form.removeChild(account);
console.log("=======================");
// 标签的克隆
let ul = document.querySelector('ul');
// console.log(ul.cloneNode());
console.log(ul.cloneNode(true));
let box1 = document.querySelector('.box1');
box1.append(ul);
console.log("=======================");
// 替换
let box3 = document.querySelector('.box3');
let img = document.createElement("img");
img.src = 'https://img1.baidu.com/it/u=2645923382,3836110976&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500'
// box3.replaceChild(newNode,oldNode);
box3.replaceChild(img,document.querySelector('.box3 p'));
</script>
4.事件的绑定与移除
<div class="box1">box1</div>
<!-- <div class="box2" οnclick="box2()">box2</div> -->
<div class="box3">box3</div>
<!-- <div class="box4" οnclick="alert('点了box4一下')">box4</div> -->
<script>
function box2(){
alert("点了box2一下");
}
var box1 = document.querySelector('.box1');
// 事件的绑定
// box1.onclick = function(){
// alert("点了box1一下");
// }
// 事件的移除
// box1.onclick = null;
// 事件的绑定: box1.addEventListener(事件,事件处理函数)
// box1.addEventListener('click',box1_click);
// 事件的移除: box1.removeEventListener(事件,事件处理函数)
// box1.removeEventListener('click',box1_click);
function box1_click(){
alert("点了box1一下");
}
// 事件的绑定:box1.attachEvent(on事件,事件处理函数);
// box1.attachEvent('onclick',box1_click);
// 事件的移除:box1.detachEvent(on事件,事件处理函数);
// box1.detachEvent('onclick',box1_click);
// 事件绑定兼容性处理的封装
function addEvent(el,ev,fn){
if(el.addEventListener){
el.addEventListener(ev,fn);
}else if(el.attachEvent){
el.attachEvent('on'+ev,fn);
}else{
el['on'+ev] = fn;
}
}
addEvent(box1,'click',box1_click);
// 事件移除兼容性处理的封装
function removeEvent(el,ev,fn){
if(el.removeEventListener){
el.removeEventListener(ev,fn);
}else if(el.detachEvent){
el.detachEvent('on'+ev,fn);
}else{
el['on'+ev] = null;
}
}
</script>
5.事件三阶段和事件委托
事件三阶段:捕获、目标、冒泡(先捕获、再目标、最后冒泡)
事件委托:又叫事件代理
原理:利用了事件冒泡
事件委托就是当多个标签需要绑定相同的一个事件的时候,就可以把这个事件委托给他们的某个祖先
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
<li>列表4</li>
</ul>
<script>
let ul = document.querySelector('ul');
ul.addEventListener('click',function(){
// console.log(this);
console.log(event.target);
})
</script>
6.重绘和回流
1.先进行域名解析
2.进行http请求,三次握手四次挥手
3.加载解析html:代码就是从上往下一行一行的执行,在执行的过程中,会解析html标签创建一个DOM树,
解析css创建CSSOM,将DOM树和CSSOM结合,合并成一个Render Tree(渲染树),根据渲染树,去布局绘制并显示。
浏览器的渲染过程:
1.解析html创建DOM树
2.解析css创建CSSOM (css rule true css规则树)
3.将DOM树和CSSOM结合,合并成一个Render Tree(渲染树)
4.根据渲染树,去布局绘制并显示
DOM CSSOM Render Tree
重绘:
当元素样式的改变不会影响布局时,浏览器将会使用重绘对元素进行更新,此时只需要UI层面的重新像素绘制,所以损耗较少
常见的重绘操作:
改变元素的颜色、改变元素的背景颜色等
回流(重排):
当元素的尺寸、结构发生改变或者出发某些属性时,浏览器会重新计算渲染页面内,发生回流
比如让标签隐藏或者改变标签的宽高、还有就是通过js往页面中添加DOM元素以及通过js获取元素的尺寸大小或者偏移量
重绘不一定会引起回流,但是回流一定会引起重绘
常见的回流操作:
DOM的添加和删除;
页面的加载;
元素尺寸改变——边距、填充、边框、宽度和高度;
元素位置的改变;
内容变化,比如用户在input框中输入文字;
浏览器窗口尺寸改变——resize事件发生时;
获取某些属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、
scrollHeight、 clientTop、clientLeft、clientWidth、clientHeight。(浏览器为了返回最精确的值,需要flush队列,
因为队列中可能会有影响到这些值的操作)
减少重绘与回流:
css
使用 transform 替代 top、left
使用 visibility 替换 display: none ,因为前者只会引起重绘,后者改变了布局会引发回流。
避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。
避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。
js
避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
避免触发同步布局