JS的组成
JavaScript 包括 ECMAScript、DOM、BOM
ECMAScript
ECMAScript 是由ECMA 国际( 原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript 或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。
DOM文档对象模型
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
BOM浏览器对象模型
BOM (Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
js的加载过程
JS加载时,首先会优先加载function,但仅限于function xxx(){}这种声明方式的,像var b = function() {};又或者匿名函数等是不会优先加载的(注意匿名函数是什么时候用,什么时候加载,和懒加载有得一 拼),这是第一步。
其次会加载script元素,按照script中的标签从上往下执行,当遇到错误时会返回,结 束当前标签的执行,执行下一个script。
js引擎会把js里面所有的 var 还有 function 提升到当前作用域的最前面
普通函数在调用时可以放在任意位置,而匿名函数的调用必须写在声明之后
因为普通函数在浏览器加载js文件时会将函数的声明提到最前面,称为函数提升
同步和异步
-
同步
- 前一个任务结束后再执行后一个任务
-
异步
-
在做这件事的同时,你还可以去处理其他事情
异步任务有以下三种类型
- 普通事件,如
click
,resize
等 - 资源加载,如
load
,error
等 - 定时器,包括
setInterval
,setTimeout
等
- 普通事件,如
-
异步任务相关回调函数添加到任务队列中
- 先执行执行栈中的同步任务
- 异步任务(回调函数)放入任务队列中
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
同步任务放在执行栈中执行,异步任务由异步进程处理放到任务队列中,执行栈中的任务执行完毕会去任务队列中查看是否有异步任务执行,由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop)。
JS书写位置
- 行内式JS
- 内嵌式JS
- 外部JS
实参形参
参数 | 说明 |
---|---|
形参 | 形式上的参数 函数定义的时候 传递的参数 当前并不知道是什么 |
实参 | 实际上的参数 函数调用的时候 传递的参数 实参是传递给形参的 |
// 带参数的函数声明
function 函数名(形参1, 形参2 , 形参3...) { // 可以定义任意多的参数,用逗号分隔
// 函数体
}
// 带参数的函数调用
函数名(实参1, 实参2, 实参3...);
arguments的使用
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参。
-
arguments存放的是传递过来的实参
-
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点
①:具有 length 属性
②:按索引方式储存数据
③:不具有数组的 push , pop 等方法
全局变量和局部变量
全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)
- 全局变量在代码的任何位置都可以使用
- 在全局作用域下 var 声明的变量 是全局变量
- 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
- 局部变量只能在该函数内部使用
- 在函数内部 var 声明的变量是局部变量
- 函数的形参实际上就是局部变量
区别
- 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
数组方法(不熟悉的)
方法名 | 说明 | 是否修改原数组 |
---|---|---|
reverse() | 颠倒数组中元素的顺序,无参数 | 该方法会改变原来的数组,返回新数组 |
sort() | 对数组的元素进行排序 | 该方法会改变原来的数组,返回新数组 |
其他方法
方法名 | 说明 | 返回值 |
---|---|---|
concat() | 连接两个或多个数组 不影响原数组 | 返回一个新的数组 |
slice() | 数组截取slice(begin,end) | 返回被截取项目的新数组 |
splice() | 数组删除splice(第几个开始要删除的个数) | 返回被删除项目的新数组,这个会影响原数组 |
从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉。
element.innerText
起始位置到终止位置的全部内容,包括HTML标签,同时保留空格和换行
element.innerHTML
三种动态创建元素的区别
document.write() 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
冒泡和捕获
事件冒泡
** IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。**
**事件捕获 **
网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
加深理解:我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。
-
JS 代码中只能执行捕获或者冒泡其中的一个阶段
-
onclick 和 attachEvent只能得到冒泡阶段
-
addEventListener(type,listener[,useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false (不写默认就是false),表示在事件冒泡阶段调用事件处理程序
-
实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
-
有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
阻止事件冒泡
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点
事件冒泡本身的特性,会带来的坏处,也会带来的好处,需要我们灵活掌握。
标准写法
e.stopPropagation();
非标准写法: IE6-8 利用对象事件 cancelBubble属性
e.cancelBubble = true;
load与DOMContentLoaded
接收两个参数:
DOMCountentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等
如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间
交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded事件比较合适。
区别
load 等页面内容全部加载完毕,包括页面dom元素,图片,flash,css等
DOMContentLoaded 是DOM加载完毕,不包含图片 flash css 等就可以执行,加载速度比load更快一些
this指向
-
函数内this的指向
this指向,是当我们调用函数的时候确定的,调用方式的不同决定了this的指向不同,一般我们指向我们的调用者 -
调用方式 this指向 普通函数调用 window 构造函数调用 实例对象,原型对象里面的方法也指向实例对象 对象方法调用 该方法所属对象 事件绑定方法 绑定事件对象 定时器函数 window 立即执行函数 window
改变函数内部this指向
JavaScript 为我们专门提供了一些函数方法来帮我们处理函数内部 this 的指向问题,常用的有 bind(),call(),apply()三种方法
call() 方法
- call()方法调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向
- fun.call(thisArg,arg1,arg2,…)
- thisArg: 在 fun 函数运行时指定的 this 值
- arg1,arg2: 传递的其他参数
- 返回值就是函数的返回值,因为它就是调用函数
- 因此当我们想改变 this 指向,同时想调用这个函数的时候,可以使用 call,比如继承
apply()方法
- apply()方法调用一个函数,简单理解为调用函数的方式,但是它可以改变函数的 this指向
- fun.apply(thisArg,[argsArray])
- thisArg: 在 fun 函数运行时指定的 this 值
- argsArray : 传递的值,必须包含在数组里面
- 返回值就是函数的返回值,因为它就是调用函数
- 因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值
bind()方法
bind()
方法不会调用函数。但是能改变函数内部 this
指向
fun.bind(thisArg,arg1,arg2,....)
返回由指定的 this
值和初始化参数改造的 原函数拷贝
因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind
call apply bind 总结:
相同点:
都可以改变函数内部的 this指向
区别点:
call和apply会调用函数,并且改变函数内部的this指向
call和apply传递的参数不一样,call 传递参数,apply 必须数组形式
bind不会调用函数,可以改变函数内部this指向
主要应用场景
call经常做继承
apply经常跟数组有关系,比如借助于数学对线实现数组最大值与最小值
bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向
location对象
- window 对象给我们提供了一个
location
属性用于获取或者设置窗体的url,并且可以解析url。因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
构造函数
constructor() 方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过 new 命令生成对象实例时,自动调用该方法。如果没有显示定义, 类内部会自动给我们创建一个constructor()
<script>
// 1. 创建类 class 创建一个 明星类
class Star {
// constructor 构造器或者构造函数
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
}
// 2. 利用类创建对象 new
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 20);
console.log(ldh);
console.log(zxy);
</script>
- 构造函数是一种特殊的函数,主要用来初始化对象(为对象成员变量赋初始值),它总与
new
一起使用 - 我们可以把对象中的一些公共的属性和方法抽取出来,然后封装到这个函数里面
严格模式
变量
- 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量
- 严格模式禁止这种用法,变量都必须先用var 命令声明,然后再使用
- 严禁删除已经声明变量,例如,``delete x` 语法是错误的
this指向问题
- 以前在全局作用域函数中的this指向window对象
- 严格模式下全局作用域中函数中的this 是 undefined
- 以前构造函数时不加 new 也可以调用,当普通函数,this指向全局对象
- 严格模式下,如果构造函数不加 new 调用,this指向的是 undefined ,如果给它赋值,会报错
- new 实例化的构造函数指向创建的对象实例
- 定时器this 还是指向window
- 事件、对象还是指向调用者
函数
- 函数不能有重名的参数
- 函数必须声明在顶层,新版本的JavaScript会引入“块级作用域”(ES6中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数
闭包
闭包指有权访问另一个函数作用域中的变量的函数
简单理解:一个作用域可以访问另外一个函数内部的局部变量
闭包的作用
延伸变量的作用范围!
API
API,英文全称Application Programming Interface,翻译为“应用程序编程接口”。
原型原型链
原型
原型的概念:每一个javascript对象(除null外)创建的时候,就会有一个与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
原型链
简单的回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?
显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。
Promise
Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。
Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:
var、let、const之间的区别
一、var
在ES5中,顶层对象的属性和全局变量是等价的,用var
声明的变量既是全局变量,也是顶层变量
二、let
let
是ES6
新增的命令,用来声明变量
用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效
三、const
const
声明一个只读的常量,一旦声明,常量的值就不能改变
四、区别
变量提升
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let
和const
不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
块级作用域
var
不存在块级作用域
let
和const
存在块级作用域
重复声明
var
允许重复声明变量
let
和const
在同一作用域不允许重复声明变量
修改声明的变量
var
和let
可以
const
声明一个只读的常量。一旦声明,常量的值就不能改变
使用
能用const
的情况尽量使用const
,其他情况下大多数使用let
,避免使用var
异同之处
1:var 和 let 声明的是变量,可更改值,const 不可,
2:var 声明的变量只具有函数作用域, let 和 const 声明的变量和常量具有块级作用域
3:ar 和 let 变量的声明可以不做赋值操作,const 不可,
4:let 不可以重复声明一个变量,重复声明会报错,var 则不会
5:let 不存在变量提升,var存在