JS详细基础笔记

1 JavaScript 基本语法

1.1 JavaScript 在 HTML 中的三种使用方式

① 行内式
<button οnclick="js代码"></button>
② 内嵌式
<script>
	js代码...
</script>

注意: script 建议写在所有元素的后面!

③ 外链式
<script src="js文件的地址"></script>

注意: script 建议写在所有元素的后面!

1.2 javaScript 注释

// 单行注释

/* 
 多行注释
*/

1.3 输出内容

// 以弹框的形式输出
alert()

// 输出到控制台
console.log()

// 输出到页面
document.write()

2 变量

2.1 数据、直接量、变量

数据: 程序中使用的都是数据。

直接量: 直接使用数据,就是直接量

变量: 给数据取个名字,就是变量。使用变量就是使用数据。

2.2 变量的意义

  • 给数据取名字,用变量即是用数据
  • 变量可以把数据存储下来,作为存储数据的容器。保证前后使用的数据是一致的。

2.3 变量的特点

// 1. 定义变量使用 var 关键字, 使用变量的时候不需要加 var
var username = '啊你';

// 2. 可以先定义变量再赋值,也可以定义的同时去赋值
var age;
age = 200;

// 3. 可以同时声明多个变量
var num1 = 10, num2 = 20, num3 = 30;

// 4. 变量的值可以修改

2.4 变量命名规范

强制遵循:
	1. 变量名由数字、字母、下划线和 $ 组成,但是不能以数字开头。
	2. 变量名不能关键字和保留字。
	3. 变量名严格区分大小写。

建议遵循:
	1. 变量名应该是有意义的单词
	2. 如果变量名由多个单词组成,建议使用小驼峰命名法
	3. 不要英文和拼音混合使用

3 数据类型

3.1 数据类型分类

原始类型:
	1. number 数值
	2. string 字符串
	3. boolean 布尔值
	4. null 空
	5. undefined 未定义

对象类型:
	.......

3.2 判断数据的类型

typeof('hello world')
typeof(msg);

3.3 number 类型

① 整型表示
// 十进制表示
100

// 八进制表示
0100

// 十六进制表示
0x100
② 浮点数(小数)表示
// 常规的小数
10.23
0.5 //简写为 .5

// 科学计数法
12e23 // 12 * 10^23

注意: 浮点数的计算存在精度问题!0

③ 特殊的值 NaN
NaN 也是 number 的一个值,一般其他类型转为 number 类型的时候,如果无法转为正常的数字,就会转为 NaN

NaN 两个特点:
	1. NaN 与任何数据运算,结果都是 NaN
	2. NaN 与任何数据都不相等,包括自己
④ JS中可以表示的数字范围
如果超过范围,会表示为 Infinity(正无穷) 或者 -Infinity
⑤两个相关的函数
isNaN()判断一个数字是否是NaN,或者其他类型的数据是否可以转换为NaN
isFinite()判断一个数字是否在有效范围内

3.4string字符串

① 定义字符串
使用单引号或者双引号作为字符串的定界符
如果字符串的定界符是双引号,字符串内容中就不要出现双引号了,
如果字符串的定界符是单引号,字符串内容中就不要出现单引号了,
② 转义字符
\n 换行符
\'单引号转义
\"双引号转义
\uXXXX unicode 编码

3.5boolean布尔值

表示一种状态 ,两个值ture 或false

2.6null和undefined


null 表示的是空
	如果定义了变量暂时不知道赋什么值,可以先赋值为null
undefined 表示的是未定义
	定义了但是没有赋值,一般不需要主动定位为undefined

4数据类型转换

4.1 数据类型转换的规则

①其他类型的数据转换为数值
1. 字符串转为number
	纯数字字符串转为对应的数字,空字符串(或者纯空格字符串)转为0,其他字符串转为NaN
2.布尔值转为number
true->1
false->0
3.null转为number 转为0
4.undefined转为number,转为NaN

② 其他类型的数据转为字符串
1数值转为字符串
转为数字组成的字符串,NaN转为NaN
2.布尔值转为字符串
true->"true"
flase->"flase"
3.null->"null"
4.undefined->"undefined"
③ 其他类型的数据转换为布尔值
1. 数值转为布尔值
   0 和 NaN 转为 false,其他的转为 true

2. 字符串转为布尔值
   空字符串转为 false,其他的转为 true
   
3. null -> false

4. undefined -> false

4.2 强制类型转换

① 强制转为 number 的函数
Number()

parseInt()		截取字符串里面的数字
parseFloat()    截取字符串里面的数字

parseInt()、parseFloat() 与 Number() 转换规则的区别:

  1. parseInt()、parseFloat() 可以把以数字开头的字符串转为开头的数字(提取字符串中的数字)
  2. 空字符串、纯空格字符串和其他形式的字符串都是 NaN
  3. 布尔值、null、undefined 都会转为 NaN

parseInt 和 parseFloat 的区别:

  1. parseInt() 只提取字符串中数字里的整数部分
  2. parseFloat() 提取字符串中数字的整数部分加小数部分
② 强制转为 string 的函数
String()
③ 强制转为 boolean 的函数
Boolean()

4.3 自动类型转换

当某个数据处在某种运算环境下,而该数据不是该运算环境需要的类型,此时数据会进行自动类型转换,转为运算环境需要的类型。

数据会自动转为当前所处的运算环境需要的类型

5 运算符

5.1 运算符和表达式

① 运算符
  • 用于运算符的符号就是运算符

  • 与运算符一起参与运算的变量或者直接量,称之为操作数

② 表达式
  • 表达式是由运算符、直接量或者变量等组成,表达式用于运算所有有一个运算结果,称之为表达式的值。
  • 一个变量或者一个直接量也是表达式,称之为原始表达式
  • 多个简单的表达式可以组成复杂的表达式
  • 有些表达式有副作用,副作用指的是表达式不但有最后的运算结果,还会对参与运算的操作数(变量形式)进行修改;决定表达式有没有副作用的是运算符。

5.2 运算符的分类

① 安装运算符需要的操作数的个数
一元运算符(一目运算符)
二元运算符(二目运算符)
三元运算符(三目运算符)
② 安装运算符的功能
算术运算符
关系运算符 
逻辑运算符
位运算符
赋值运算符
其他运算符

5.3 运算符详解(安装功能)

① 算术运算符
运算符含义操作数个数操作数的类型要求组成的表达式的值的类型有无副作用
+数学加号2numbernumber
-数学减号2numbernumber
*数学乘号2numbernumber
/数学除号2numbernumber
%取余2numbernumber
+正号1numbernumber
-负号1numbernumber
++递增1numbernumber
递减1numbernumber

注意:

  1. 正号运算符通常可以用来把其他类型的数据转为 number。

  2. ++ 和 – 组成的表达式,运算符在操作数的前面或后买,表达式的值是不同的;副作用是相同的。

    运算符在前的,把操作数运算之后的结果作为表达式的值

    运算符在后的,把操作数没有运算之前的值作为表达式的值

② 关系运算符
运算符含义操作数个数操作数要求的类型表达式的值的类型是否有副作用
>大于2number / stringboolean
>=大于等于2number / stringboolean
<小于2number / stringboolean
<=小于等于2number / stringboolean
==相等2number / stringboolean
!=不相等2number / stringboolean
===全等2没有要求boolean
!==不全等2没有要求boolean

1. 字符串比较

如果进行比大小或者相等的时候,两个操作数都是字符串,会按照字符串的规则进行比较。

比大小:字符串会一个字符一个字符按照对应的ascii码进行比较。

比相等:两个字符串完全一致就相等。

2. == 和 === 的区别:

相等(==): 会对操作数进行自动数据类型转换

全等(===):不会对操作数进行数据类型转换,如果两个操作数类型不同,直接返回 false (建议使用)

使用 == 进行判断运算,操作数中如果由 null,出现特殊情况:

  • null 和 0 不等
  • null 和 false 不等
  • null 和 空字符串 不等
  • null 和 undefined 相等
③ 逻辑运算符
运算符含义操作数个数操作数类型表达式值的类型是否有副作用
&&逻辑与2无要求其中一个操作数作为表达式的值
||逻辑或2无要求其中一个操作数作为表达式的值

逻辑与组成的表达式的值计算规则:

  1. 如果第一个操作数成立,取第二个操作数作为整个表达式的值。
  2. 如果第一个操作数不成立,取第一个操作数作为整个表达式的值。

逻辑或组成的表达式的值计算规则:

  1. 如果第一个操作数成立,取第一个操作数作为表达式的值。
  2. 如果第一个操作数不成立,取第二个操作数作为表达式的值。
④ 赋值运算符
运算符含义操作数的个数操作数的数据类型表达式的值的数据类型是否有副作用
=赋值2没有要求变量的值作为表达式的值
+=赋值求和2number变量的值作为表达式的值
-=赋值求差2number变量的值作为表达式的值
*=赋值求积2number变量的值作为表达式的值
/=赋值求商2number变量的值作为表达式的值
%=赋值取余2number变量的值作为表达式的值
+=赋值连接字符串2string变量的值作为表达式的值

注意:

  1. 赋值运算符左边的操作数必须是个变量。
  2. 赋值运算符更看重的是副作用
⑤ 其他运算符
运算符含义操作数的个数操作数的数据类型表达式的值的数据类型是否有副作用
+字符串连接符2stringstring没有
typeof类型判断1没有要求string没有
,逗号运算符2没有要求最后一组操作数作为表达式的值没有
?:比较运算符3第一操作数要求布尔值
后两个操作数没有于要求
如果第一个操作数成立,操作数2作为表达式的值,否则操作数3作为表达式的值没有

5.3 运算符优先级

最高: 一元运算

中间: 算符运算符 > 关系运算符

三低: 逻辑运算符 > 三元运算符 > 赋值运算符

使用 () 提高优先级

6 分支结构

6.1 单向分支

if (条件表达式) {
    语句;
    语句;
}

6.2 双向分支

if (条件表达式) {
	语句;
    语句;
} else {
	语句;
    语句;
}

6.3 多向分支 else if

if (条件表达式) {
  	语句;  
} else if (条件表达式) {
    语句; 
} else if (条件表达式) {
    语句; 
} else if (条件表达式) {
    语句; 
} else {
    语句;
}

6.4 多向分支 switch case

switch (表达式) {
    case 表达式可能的值: 
        语句;
        语句;
        break;
    case 表达式可能的值: 语句; break;
    case 表达式可能的值: 语句; break;
    case 表达式可能的值: 语句; break;
    case 表达式可能的值: 语句; break;
    default: 语句;
}

break 的作用:

进入到 case 之后,执行语句,遇到 break 才停止,如果没有break会继续执行下面的 case,直到碰到 break。

6.5 嵌套分支

if (条件表达式) {
	if (条件表达式) {
	}
} else {
	switch (表达式) {
		case ...
	}
}

7 循环结构

7.1 while 循环

while (条件表达式) {
    语句;
}
  1. 条件表达式不能永远成立,否则就会成为死循环。
  2. 随着循环次数的增加,条件表达式要越来越趋近于不成立。

7.2 do … while 循环

do {
    语句;
} while (条件表达式)

相对于 while,do … while 只有第一次没有判断就执行了循环里的语句,以后与 while 一样都是先判断才执行。

7.3 for 循环

for (循环标记变量初始化; 条件表达式; 循环标记变量的变化) {
    语句;
}

循环标记变量的变化 每次循环都会执行,且在大括号中的语句都执行完毕后才执行

1 数组

1.1 什么是数组

  • 数组是值的有序集合。
  • 数组中的每个值,称之为元素
  • 数组中的元素可以是任意类型的数据。
  • 数组中的元素有个位置,称之为索引
  • 数组索引从 0 开始, 依次递增,最大为 2^32-2,数组最大能容纳 4294967294 个元素。

1.2 声明数组的方式

① 数组直接量方式
[100, 200, 300, 400, 'hello', [1,2,3,4,5]];

[30];  

② Array 函数方式
Array(100,200,300,400);
Array('hello'); // 数组只有一个元素,值是 hello
Array(20);	    // 表示数组的长度是 20(元素的个数)

1.3 数组元素的读写

读写数组的元素,使用元素的索引,配合 [] 读写操作

arr[2];   // 读取数组中索引是 2 的元素
arr[3] = 100;  // 给数组中索引是 3 的元素重新赋值
所有的数组都有属性,length, 通过length 可以获取数组的长度(元素的个数)

arr.length; // 读取数组的长度

// length 是可以修改的,修改 length 可能会造成数组元素被截取

1.4 稀疏数组

  • 数组中元素的索引必须是连续的。
  • 为了保证元素索引的连续性,给数组元素赋值的时候,索引值是跳跃的,中间会补全空的元素,这样的数组我们称之为 稀疏数组
  • 要尽量避免稀疏数组
  • 读取空元素的值,得到 undefined; 读取不存在的元素,也会得到 undefined。

1.5 数组的遍历(迭代)

① 使用 for 循环
for (var i = 0; i < arr.length; i ++) {
    i; // 数组的元素的索引
    arr[i];  // 数组的元素的值
}
② for … in
for (var i in arr) {
    i; // 数组的元素的索引
    arr[i];  // 数组的元素的值
}

1.5 数组元素的添加和删除

① 给数组添加元素
1. 指定数组的索引,添加元素;要求索引必须是数组的下一个索引
2. 让数组当前的长度作为数组的下一个索引	arr[arr.length] = '元素的值'
3. 在数组的后面追加元素	arr.push(元素);  arr.push(元素1,元素2 ....);
4. 在数组的前面添加元素	arr.unshift(元素);  arry.unshift(元素1,元素2 ....)
5. 在指定的位置插入新元素	arr.splice(新元素的位置, 0, 新元素);
                       arr.splice(新元素的位置, 0, 新元素1, 新元素2 ....);
② 删除数组中的元素
1. 通过设置数组 length 的值实现删除数组元素的目的。  arr.length -= 2; // 删除后两个元素
2. 删除数组的最后一个元素。  arr.pop()
3. 删除数组的第一个元素。  arr.shift0
4. 删除指定位置指定数量的元素。  arr.splice(位置, 数量);

1.6 多维数组

如果数组的元素还是个数组,这样的数组就是多维数组!

1.7 字符串的数组特性

  • 字符串是一种类数组对象(伪数组对象)
  • 可以使用 [] 配合索引读取字符串中指定索引的字符的值,但是不能设置
  • 使用 for 循环遍历出字符串中的每一字符。
  • 字符串也有 length 属性,获取字符串的长度(字符的个数)

2 函数

2.1函数的概述

①函数的概念
  • 函数是具有特定的代码块,可以被反复使用
  • 函数在js中就是一种数据类型
② 函数的作用
  • 代码复用
  • 利用函数实现模块化
  • 函数可以封装内部代码使外部不可见
③函数的组成
  • 函数名本质上就是变量名
  • 函数体
  • 参数
  • 返回值

2.2声明函数的三种方式

①function 关键字方式(字面量方式)
function函数名([参数]){
	函数体
}
②表达式方式
var 函数名=function([函数]){
函数体
}

2.3函数调用

函数名()才是函数的调用,只有调用被调用了,函数体才会执行
函数调用称之为“函数调用表达式”,表达式的值就是函数的返回值
函数名不加(),是在引用函数本身,本质上在使用一个变量

2.4 函数的返回值

1.返回值作为函数调用表达式的值

2.在函数体内,return的右边写个表达式,该表达式就是函数的返回值

3.在函数体内,没有写return函数默认返回值则是undefined

4.如果return右边什么都不写,函数默认值是undefined

5.return可以终止函数的执行,return语句执行之后,函数体内后面的代码不会执行

什么样的函数需要写返回值?

如果函数是进行某种计算的,通常会把计算的结果作为函数的返回值

如果函数进行某个功能操作,没有计算结果,一般不需要返回值

系统定义的函数:
Number() 返回转成 number 了的数据
String() 返回转成 string 了的数据
Boolean() 返回转成 boolean 了的数据
parseInt() 有返回值
parseFloat() 有返回值
isNaN() 有返回值
isFinite() 有返回值
typeof() 有返回值

2.5 函数的参数

① 形参和实参

形参:在声明函数的时候,设置的参数就是形参;形参相当于没有赋值的变量(仅限函数内使用),参数命名规范同变量

实参:在调用函数时,给的值就是实参;实参作为形参的值

②形参和实参的数量
1.正常情况,实参数量=形参数量
2如果实参数量>形参数量,多余的实参没有任何作用
3.如果实参数量<形参数量,靠后的形参没有被赋值默认取undefined
 
③ 函数参数的默认值

JS函数中,可以给形参设置默认值,有默认值的参数称之为可选参数

在函数调用的时候,可以不给有默认值的形参赋值,形参取默认值;如果调用的时候对有默认值的形参赋值了,就取调用时赋的值。

设置参数默认值,旧语法(ES5之前的)

function 函数名(a, b) {
    // 如果 参数b 的值是 undefined,说明调用函数的时候没有给 b 赋值
    if (b === undefiend) {
        b = '默认值'
    }
}

设置参数默认值,新版语法:

function 函数名(a, b='默认值') {
	
}

注意:

可选参数(有默认值的参数)一定要写在后面。

④ arguments

arguments 是一个类数组对象(伪数组)。

argument 能够得到调用该函数时所有的实参,每个参数都会作为 arguments 内部的元素

arguments 可以用于声明可变参数数量的函数。

2.6 作用域

① 变量的作用域

1.作用域就是变量的可作用范围

2.函数可以产生作用域,函数内部定义的变量,只能在函数内可以使用

②作用域分类

局部:在函数内声明的变量,作用域仅限于所在的函数是局部的。这样的变量称之为局部变量

全局:在函数外声明的变量,作用域是全局,任何地方都可以用。这样的变量称之为全局变量

注意

1.函数内参数本质是局部变量,作用域是所在函数

2.在函数内不使用var声明的变量是全局变量(不建议使用)

③ 作用域链

什么是作用域链?

函数的嵌套形成作用域链

在使用变量的时候,会沿着作用域链向上找

变量的查找过程:

1.先从本作用域查找该变量是否定义,如果定义过直接使用

2.如果本作用域没有定义要使用的变量,去上层作用域查找;从哪里找到从哪里停止如果到全局也没有则报错

注意: 作用域只与函数的声明的位置有关,与函数调用的位置无关

2.7 变量提升

① 变量提升
1. 程序在正式执行之前,会进行预解析;
2. 在预解析的时候,会进行变量的提升; 只提升变量的声明,变量的值不会提升。
3. 变量提升提升到本作用域的最前面。
如果在变量声明的代码之前,使用变量,得到 undefined
② 函数提升
1. function 关键字方式声明的函数,除了声明提升值也提升。可以在函数声明代码之前调用函数。
2. 函数名与变量名如果冲突,优先提升函数名。
3. 表达式方式声明的函数与普通变量提升的规则是一致的。

1自调用函数

① 匿名函数

没有名字的函数 用途1用于自调用函数2回调函数

②自调用函数

函数声明完就立即调用

特点:自调用函数一般用于匿名函数也可以进行传参也可以是有名字的函数作为自调函数

用途:模块划分,避免全局变量污染

注意:连续两个自调用函数一前一后解决方案

1给第一个自调用函数后面加分号

2.给第二个自调用函数前面加叹号

1.2回调函数

①什么是回调函数

三个条件:我定义的,我没有调用,函数被执行了

②回调函数的使用场景
  • 事件

  • 定时器

  • ajax请求

  • 生命周期钩子

    一般来说,回调函数通常作为其他函数的参数

1.3 递归函数

① 什么是递归函数?

一个函数的内部如果又调用了自己,称作是函数的递归调用,这样的函数就是递归函数

② 递归函数成功的条件

1)必须有一个明显的结束条件

2)必须有一个趋近于结束条件的趋势

③ 递归的缺点

1)函数递归调用很容易发生灾难(内存泄漏)而调用失败。

2)函数递归调用效率不高,能不用就不用。

④ 递归的应用场景

后端的操作中有些场景必须要递归函数来完成,如:

1)删除文件夹以及里面的内容,需要递归删除(操作系统的原始接口只能删除文件和空文件夹)

2)复制文件夹以及里面的内容。

3)剪切文件夹以及里面的内容。

1 Object 对象

1.1 什么是对象

  • 对象是值的无序集合
  • 对象由属性组成
  • 属性有属性名也有属性值(键值对)
  • 如果属性的值的数据类型是 function, 该属性也可以称之为方法。

1.2 如何声明 Object 对象

① 直接量方式 {}
{
    name: '安妮',
    age: 19,
    'user-grade': 100,
    say: function(){
        
    },
    sleep: function(){
        
    }
}
② Object 构造函数方式
var obj = new Object();  // 声明空的对象

obj.name = '安妮';
obj.say = function(){
    
}

1.3 Object 对象属性的读写

① 语法
. 语法   obj.name; obj.say()
[] 语法	obj['name']   obj['say']();
② 什么情况下必须使用 [] 语法读写属性
1. 属性名不符合标识符命名规范。
2. 用变量来表示属性名。
③ 注意事项
1. 读取对象中不存在的属性,返回 undefined
2. 给对象属性设置值的时候,如果属性存在就修改值,如果属性不存在,添加该属性。

1.4遍历对象中的属性

for(var i in obj){
console.log(i,obj[i]);
}

1.5删除对象中的属性

delete 对象.属性名 delete 对象[‘属性名’]

1.6 判断对象中是否存在某个属性

'属性名'in 对象;//返回值
true表示该属性存在

2构造函数

2.1什么是构造函数?

构造函数就是对对象的描述(js中相同数据类型的构造函数一样)

对象是构造函数的实例,构造函数就是对对象的描述

对象都有构造函数,一个对象对应一个构造函数构造函数对应多个对象

2.2 判断对象的构造函数

①运算符 instanceof

对象instanceof构造函数;//返回布尔值

注:原始类型(字符串,number,布尔)使用instanceof判断返回false

②constructor 属性

所有的对象都有constructor属性,返回对象的构造函数对原始类型的数据调用constructor属性时,原始类型切换为对象类型

2.3 自定义构造函数

 function User(name, age, address) {
     // 设置属性
     this.name = name;
     this.age = age;
     this.address = address;

     // 设置方法
     this.login = function(){
         console.log('我是 ' + this.name + ', 我今年' + this.age + '岁了,我来自' + this.address + ',啊,我登录了');
     }
     this.logout = function(){
         this.login();
         console.log('啊,我退出登录了!');
     }
 }

2.4 实例化

new 构造函数();
没实例化一次,就会产生一个新的对象

3 this

3.1 this 的含义

  • this 可以认为是内置的变量,该变量的值是对象,但是不固定。
  • this 在函数或构造函数中使用

3.2 this 的指向

① 在构造函数使用 this

this 指向构造函数所生成的对象。

② 在方法(或函数)使用 this

谁调用指向谁!

如果函数的前面没有 对象. ,就是 window 在调用该方法!

3.3 window

  • window 是浏览器端 JS 的全局对象。
  • 在浏览器窗口打开的那一刻,window 对象就创建。
  • 全局变量、全局函数其实是 window 的属性。
  • 使用window的属性和方法的时候,window 可以省略。
  • 系统函数,如 alert、prompt、Number、String、parseInt 等等其实都是 window 的方法。

4 原型

4.1 原型的概念

原型也是一个对象

所有的对象都有一个原型,对象可以从原型上继承属性和方法

4.2 如何获取对象的原型

① 隐式原型方式
对象.__proto__
② 显示原型方式
对象的构造函数.prototype

4.3 对象、构造函数、原型之间的关系

① 对象和构造函数

对象是构造函数的实例,构造函数是对象的描述。

② 对象和原型

对象可以从原型上继承属性和方法

③ 构造函数和原型

对象可以通过它的构造函数来获取原型

构造函数相同的对象,原型也相同。

4.4 原型的应用

// 自定义构造函数
function User(name, age, address) {
    // 属性
    this.name = name;
    this.age = age;
    this.address = address;
}

// 把方法添加到实例的原型上
User.prototype.login = function(){
    console.log(this.name + ' 登录了');
}
User.prototype.logout = function() {
    console.log(this.name + ' 退出登录了');
}

自定义构造函数的时候,通常通过 this 对象设置属性,方法添加到原型上; 得到实例之后,属性会存储在对象本身上,方法存储在原型对象上。

一般,相同类型的对象属性的值往往是不同的,但是方法的语句是一致的。

这么做可以减少内存存储空间。

4.5 判断属性是否属于对象本身

对象.hasOwnProperty('属性名');  // 返回布尔值

/*
如果属性是在对象本身上的,返回true
如果属性不在对象本身上(不论在原型上还是原型上没有),返回 false
*/

4.6 创建对象的同时指定原型

Object.create(对象);  // 返回一个新的对象, 参数会作为新对象的原型

Object.create(null); // 返回一个没有原型的对象,真正意义上的空对象

5 原型链

5.1 原型链的概念

任何对象都有原型对象,原型还是一个对象,既然是一个对象就会有自己的原型,那原型的原型仍然还有原型,可以依次向上找原型,直到找到一个没有原型的对象。这样就形成了一条原型链。

5.2 属性查找过程

原型链 描述的就是是对象查找属性或者方法的过程。

属性的查找会遵循如下过程:

1)对象在查找找属性的时候,先从自身去找看有没有这个属性,如果有,直接使用这个属性的值。

2)如果没有,会沿着原型链向上找,如果找到就使用这个属性的值且停止查找,如果没找到继续向上找直到原型链的终点。

3)如果找到原型链的终点还没有找到,就返回undefined(代表已经找到顶了)

5.3 构造函数和原型

  1. 构造函数本身也是对象,是 function 类型的对象; 函数对象的构造函数是 Function。
  2. 函数对象的原型是一个 Object 类型的对象, 原型的原型就是顶层原型对象了(Object.prototype)。
  3. Function 作为一个构造函数,也是对象; Function 的构造函数还是 Function, 所以 Function.__proto__ === Function.prototype

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zl3tQe7Y-1604558343644)(C:\Users\Admin\Desktop\原型链和构造函数.png)]

6值类型和引用类型

6.1 值类型和引用类型的概念

原始类型就是值类型,也可以称为不可变类型

对象类型就是引用类型,也可以称为可变类型

6.2 值类型和引用类型的存储方式

**值类型: ** 变量名和数据都存储在栈区域内。

引用类型: 栈中存储的是变量名和地址,真正的数据在堆里。

6.3 不可变和可变

**不可变类型:**原始类型(值类型),整个数据就是一个整体,无法修改其中的一部分。

**可变类型:**对象类型(引用类型),由很多属性组成,可以修改其中的属性,修改了对象的属性,对象还是原来的对象。

1 Boolean(内置对象)

// 第一种 直接量方式
var b1 = true;
// 第二种 Boolean 函数
var b2 = Boolean(true);
// 第三种 Boolean 构造函数方式
var b3 = new Boolean(0);

console.log(b1, typeof b1);	 // true 'boolean'
console.log(b2, typeof b2);  // true 'boolan'
console.log(b3, typeof b3);  // false 'object'   // 布尔值的对象形式

2 Number

实例的属性:

实例的方法:
	toFixed([n])	保留指定位数的小数,按照四舍五入;不指定参数,取整
	toString([n])	转为字符串,可以转为几进制


构造函数本身的属性:
	Number.MAX_VALUE	JS中最大可表示的数字
	Number.MIN_VALUE	JS中最小可表示的数字


构造函数本身的方法:

3 String

实例的属性:
	length	字符串的长度(字符的个数)

实例的方法:
	indexOf(value [,fromIndex])	返回value在字符串中第一次出现的索引位置;第二个可选参数指定从哪开始查找。 可以用来判断字符串中是否包含某个值。
	lastIndexOf(value [,fromIndex])	返回value在字符串中最后一次出现的索引位置;第二个可选参数指定从哪开始向前查找。
	slice(start [,end])	截取字符串,第一个参数开始截取的位置,第二个参数结束的索引,不指定第二个参数,截取到最后; 截取规则:顾头不顾尾
	substring(start [,end]) 同 slice。
	substr(start [,length]) 截取字符串,第一个参数是开始索引,第二个是截取长度;不指定第二个参数,截取到最后。
	split([sep])  把字符串分割为数组;可以指定分隔符。
	toUpperCase()	把字符串转为大写
	toLowerCase()  把字符串转为小写
	
	
	
	


构造函数本身的属性:

构造函数本身的方法:
String.formCharcode(编码)指定返回Unicode编码对应的字符

4math

(本身)方法  Math.abs()取绝对值
Math.sqrt()取平方根
Math.pow(n,m)幂运算N的M次方
Math.Max()取所有参数的最大值
Math.Min()取所有参数的最小值
Math.round()四舍五入取整
Math.floor()舍1取整
Math.ceil进一取整 
Math.random()取随机数 返回0到1 的小数 (顾头不顾尾)
随机取0~16 Math.floor(Math.random()*15);

5date

5.1创建date实例

var today = new Date();
var birthday = new Date('December 17, 1995 03:24:00');
var birthday = new Date('1995-12-17T03:24:00');
var birthday = new Date(1995, 11, 17);
var birthday = new Date(1995, 11, 17, 3, 24, 0);

5.2方法

实例的方法:
getFullYear()年
getMonth()月 返回的值时0~11
getDate()日
getDay()星期几
getHours()小时
getMinutes()分钟
getSeconds()秒
getMilliseconds()毫秒
getUTC...获取标准时区的日期和时间

	set...		设置日期和时间
	setUTC...	设置标准时区日期和时间
	
	getTime()	返回时间戳
	setTime()	根据时间戳设置日期时间
	


构造函数本身的方法:	
	Date.now()	返回此时此刻的时间戳
	ate.UTC(year,month[,date[,hrs[,min[,sec[,ms]]]]])	返回指定日期的时间戳

注意:

给参数的时候,月份的数字范围 0~11, Date 构造函数 和 Date.UTC()

6 Array

实例的属性:
	length	数组的长度
	
实例的方法:
	修改器方法:(可以修改调用方法的对象)
        pop()	删除最后一个元素
        push()	在最后面添加元素
        shift()	删除第一个元素
        unshift()	在最前面添加运算
        splice()	添加、删除、替换元素
        sort()	数组排序
        reverse()	数组翻转
   	访问方法: (不会修改调用方法的对象本身,计算结果已返回值的形式得到)
        concat()	连接数组
        slice(start [,end])	截取数组,指定开始索引和结束索引,顾头不顾尾
        join([sep])	把数组合并成字符串,可以指定分隔符,不指定默认逗号。是字符串split方法的逆运算
ES5方法
    	forEach()	用于遍历数组
    	filter()	过滤数组;回调函数返回布尔值,filter返回过滤后的新数组
    	map()		返回回调函数的返回值组成的数组
    	every()		每一个都要满足条件; 只有所有回调函数返回true,every才返回true
    	some()		只要有一个满足条件; 只要一个回调函数返回true,some就返回true
		reduce()		用于累计运算, 回调函数第一个参数接收上一个回调函数的返回值
		reduceRight()   用于累计运算,从后向前运算, 回调函数第一个参数接收上一个回调函数的返回值
		indexOf()		返回指定元素在数组中第一次出现的位置
		lastIndexOf()	返回指定元素在数组中最后一次出现的位置


7 Function

实例的属性
	length	返回函数必须的参数的数量
	
实例的方法
	call()	调用函数并设置函数内this的指向, 参数数量不固定(至少一个)
	apply() 调用函数并设置函数内this的指向,参数数量两个
	bind()	设置函数内this的指向,把修改了this指向的函数返回;参数形式同call

8 JSON

方法:
JSON.parse()	把 json 格式的字符串解析为数组或对象
JSON.stringify()	把对象或数组转为json格式的字符串

9 全局对象

方法:
	parseInt(str [,进制])  从字符串中提取数字,可以指定数字的进制
	parseFloat(str [,进制])  从字符串中提取数字,可以指定数字的进制

1 BOM

1.1 window

属性:
	name	获取或设置窗口的名字
	window.innerWidth	获取视口的宽度
	window.innerHeight	获取视口的高度
	history
	location
	navigator
	screen

方法:
	alert()	警告框
	confirm()	确认框	返回布尔值
	prompt()	输入框	返回输入的内容
	window.open()	打开新窗口
	window.close()	关闭窗口
	window.print()	调用打印程序
	scrollTo()	滚动到页面指定的位置
	scrollBy()	滚动多少距离
	setInterval()	开启定时器(多次定时)
	clearInterval()	清除定时器
	setTimeout()	开启定时器(单次定时)
	clearTimeout()	清除单次定时器

1.2 history

属性:
	length	当前窗口中历史记录的个数

方法:
	back()	后退一步
	forward()	前进一步
	go(n)	前进/后退 n 步;n 是负数表示后退

1.3 location

属性:
	href	完整的URL
	protocol	协议部分
	host	主机名+端口号
	hostnmae		主机名
	port		端口号
	path	路径部分
	search	查询字符串
	hash	锚点部分
	
方法
	reload()	重新加载
	assign(url)	页面跳转,就业面会存在历史记录中
	replace(url)	页面跳转;旧页面会在历史记录中抹除
	

1.4 navigator

属性:
	userAgent	获取客户端信息

1.5 screen

属性:
	width	屏幕的宽度
	height	屏幕的高度

2 DOM

**MDN 文档对象模型手册:**https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model

2.1 Node 节点

① 五大节点类型
document 文档对象节点
element 元素节点
attribute	属性节点
text	文本节点
comment	注释节点
① 节点的属性
nodeName	节点名		元素节点的nodeName返回标签名
nodeValue	节点值		
nodeType	节点类型	document:9; element:1; attribute:2; text:3; comment:8

2.2 获取元素

① 通过 ID 名
document.getElementById('id名');
// 返回元素对象
// 获取不到元素,返回 null
// 元素 id 名由重复的,只获取第一个
② 通过标签名
document.getElementsByTagName('标签名');
element.getElementsByTagName('标签名');

// 返回 HTMLCollection 对象,由元素对象组成的一个伪数组
// 获取不到元素,返回空的 HTMLCollection 对象
③ 通过类名 (了解)
document.getElementsByClassName('类名');
element.getElementsByClassName('类名');

// 返回 HTMLCollection 对象,由元素对象组成的一个伪数组
// 获取不到元素,返回空的 HTMLCollection 对象
④ 通过 name 属性值 (了解)
document.getElementsByName('name属性值');

// 返回 NodeList 对象,由元素对象组成的一个伪数组
// 获取不到元素,返回空的 NodeList 对象
⑤ 通过选择器获取元素 (推荐)
document.querySelector('选择器');
element.querySelector('选择器');
// 返回的是元素对象,获取不到返回 null


document.querySelectorAll('选择器');
element.querySelectorAll('选择器');
// 返回 NodeList 对象, 获取不到返回空的 NodeList 对象

需要 IE8 以上浏览器,如果兼容性要求高,可有使用 getElementById() 和 getElementsByTagName()

⑥ 获取所有的元素
document.all;   // 获取 HTMLCollection 对象,由文档中所有元素组成的伪数组

document.all 作为语法糖,判断IE还是非IE

if (document.all) {
  document.write('我是 IE 浏览器!');
} else {
  document.write('我不是 IE 浏览器!');
}

2.3 文档结构

① 作为节点树
childNodes	获取所有的子节点,返回 NodeList 对象
firstChild	获取第一个子节点
lastChild	获取最后一个子节点
parentNode	获取父节点
previousSibling	获取上一个兄弟节点
nextSibling	获取下一个兄弟节点
② 作为元素树
children	获取所有子元素,返回 HTMLCollection 对象
firstElementChild	获取第一个子元素
lastElementChild	获取最后一个子元素
parentElement	获取父元素
previousElementSibling	获取上一个兄弟元素
nextElementSibling 获取下一个兄弟元素

2 DOM 操作 - 操作元素的属性

2.1 内置属性

element.属性名;  // 赋值或者读取都可以
  1. 可能会对代码中写的值进行处理,如 img 元素的 src 属性
  2. 如 checked、selected、disabled 这样的属性,是布尔值

2.2 自定义属性(data-* 形式)

element.dataset.属性名;   // 赋值或者读取都可以

属性名指的是 - 后面的部分

2.3 自定义属性 (了解)

element.getAttribute('属性名')
element.setAttribute('属性名', '值')

这种方式实际上是操作写在代码中标签上的属性,不会区分内置属性还是自定义属性

3 DOM 操作 - 操作元素的样式

3.1 style 属性

element.style.属性名;  // 读写操作都可以

作用在元素上的 css 属性映射到 element.style 对象中

CSS 属性名中有 - 的,转为小驼峰的形式

使用 element.style 方式读取某个 css 属性值的时候,css 属性必须是设置在 行内

使用 element.style 方法设置某个 css 属性的值,直接设置在行内

3.2 读取计算样式(只读)

计算样式: 所有作用在元素上的 css 样式,不论在哪里设置的,称之为计算样式!

// IE9 以及以上 和 其他浏览器
getComputedStyle(元素对象)   // 返回一个对象,包含所有作用在该元素上的css样式

// IE8 以及以下
元素对象.currentStyle.属性名
 // 定义函数获取元素计算样式
function getStyle(ele, attr) {
    if (window.getComputedStyle) {
        // IE9+ 或 其他浏览器
        return getComputedStyle(ele)[attr];
    } else {
        // IE8 -
        return ele.currentStyle[attr];
    }
}

3.3 元素的类名操作

① className
element.className  可以设置或读取标签中的 class 属性
② classList
element.classList 是一个类名列表对象
方法:
add()	添加一个类名 (原先的类名还在)
remove() 删除指定的类名 
toggle() 切换类名(没有类名添加,有类名删除)

需要 IE9 +

4 DOM 操作 - 操作元素的文本内容

把元素内的 html 代码都作为内容:
	innerHTML
	outerHTML
	
只把文本作为元素的内容:
	innerText
	textContent

只有双标签元素才能有文本内容!

5 DOM 操作 - 获取元素的尺寸 (只读)

offsetWidth / offsetHeight		内容+内边距+边框
clientWidth / clientHeight		内容+内边距
scrollWidth	/ scrollHeight		内容溢出,考虑溢出内容的宽度;如果内容不溢出同 client 系列一致。

getBoundingClientRect()	返回对象,对象中有 width 和 height 属性,值同 offset 系列一致。

获取视口的尺寸:

window.innerWidth
window.innerHeight

document.documentElement.clientWidth
document.documentElement.clientHeight

// 二者区别
1. 如果窗口没有滚动条,二者获取的结果一致
2. 如果出现了滚动条, window 系列会加上滚动条的宽度/高度; documentElement 系列不计算滚动条

获取整个页面的高度:

document.body.scrollHeight
或者
document.documentElement.scrollHeight

6 节点的创建添加删除替换克隆

6.1 创建元素节点

document.createElement('tagName');

6.2 添加子节点

parentElement.appendChild(node)// 追加子节点
parentElement.insertBefore(newNode, oldNode);  // 在指定位置添加子节点,newNode 会在 oldNode 的前面

6.3 删除子节点

parentElment.removeChild(node);		// 参数是要删除的节点

6.4 替换子节点

parentElement.replaceChild(newNode, oldNode);  //  newNode 会把 oldNode 替换掉

6.5 节点克隆

cloneNode()	 节点克隆,参数 默认是 false 表示浅克隆, 设置为 true 表示深克隆(推荐)

7 document 对象

属性:
	document.documentElement	快速获取 html 元素  只读
	document.body	快速获取 body 元素 只读
	document.head	快速获取 head 元素 只读
	document.all	获取所有的元素组成的集合 只读
	document.referrer	获取历史记录中上一个页眉 只读
	document.lastModified	获取页面最后一次修改时间 只读
	document.title	页面标题  可读可写

方法:
	document.write()

8 documentFragment 对象

8.1 特点

1. documentFragment 对象也是一种节点, nodeType 值是 11
2. 不会作为 dom 结构一部分,不会在页面中渲染
3. 通常用来作为元素的临时容器

8.2 创建

document.createDocumentFragment()

8.3 应用场景

1. 优化,同时添加多个元素; 可以先把元素添加到 df 对象中,最后统一添加到 dom 结构中
2. 实现一组元素顺序反转

1 HTML DOM

1.1 表单相关元素

① form 元素
方法:
submit();		调用该方法可以让表单提交
reset();		调用该方法可以让表单重置
② 文本输入框和文本域(input 和 textarea)
方法:
focus()		调用该方法可以获取焦点
blur()		调用该方法可以失去焦点
select()	可以选中里面的文字
③ select 元素
属性:
	options	所有 option 的集合
	selectedIndex	当前选中的选项的索引
	
方法:
	add()	添加选项,参数是要添加的option对象
	remove() 删除选项,指定要删除选项的索引
	blur()
	focus()
	
创建 option 元素:
	new Option('中间的文本内容', ‘value 值’);

1.2 表格相关元素

① table 元素
属性:
	rows	返回所有行元素的集合
	cells	返回所有单元格元素的集合
	
方法:
	insertRow()	向表格中添加一行,指定新行的索引,返回新添加的行元素
	deleteRow()	从表格中删除一行,指定索引;
② tableRow 元素(tr 元素)
属性:
	cells	返回该行中所有单元格元素的集合
	rowIndex	返回当前行的索引
	
方法:
	insertCell()	添加一个单元格,需要指定索引; 返回新的单元格元素
	deleteCell()	删除一个单元格,需要指定索引;
③ tableCell 元素 (td 或 th)
属性:
	cellIndex	返回单元格在行内的索引

2 事件的绑定方式

① 第一种方式 把事件作为标签的属性
<button onclick="代码..."></button>
② 第二种方式 把事件作为元素对象的方法
// ① 获取元素对象

btn.onclick = function(){
 
}

③ 第三种方式 事件监听方式
btn.addEventListener('click', 回调函数);

可以给一个元素添加多个相同的事件

3 解除事件的绑定

① 第一种方式和第二种方式绑定的
// 重新给元素绑定事件,覆盖前面

btn.onclick = null;
② 第三种方式 事件监听方式
btn.removeEventListener('click', 回调函数名)

注意: 事件如果以后需要解除绑定,在添加事件的时候,回调函数就不要使用匿名函数。

4 事件流

事件的触发过程分为三个节点: 捕获阶段、目标阶段、冒泡阶段。

事件默认在冒泡阶段触发,addEventListenre 第三个参数设置为 true,事件会在捕获阶段触发。

目标元素指的是具体发生了事件的元素,不能再细分了。

当发生了事件之后,先从 window 开始,到 document 一层一层的向下寻找目标元素,这个过程称之为捕获阶段
找到目标元素,称之为目标阶段,目标阶段是捕获阶段的结束
找到目标元素之后开始冒泡,从目标元素开始一直到window,一层一层的冒泡,称之为冒泡阶段

5 事件回调函数中 this 的指向

this 指向绑定事件的元素

6 常用事件列表

6.1 鼠标事件

click	单击
dblclick	双击
contextmenu		右击
mousedown	鼠标按键按下
mouseup		鼠标按键抬起
mousemove	鼠标在元素上移动
mouseover	鼠标悬停在元素上
mouseout	鼠标离开元素
mouseenter	鼠标悬停在元素上,代替 mouseover (推荐)
mouseleave	鼠标离开元素,代替 mouseout (推荐)

6.2 键盘事件

keydown	键盘按键按下
keyup	键盘按键抬起
keypress	键盘按键按下,控制按键无法触发,只有可输入字符按键可以触发。

keydown 和 keyup 任何一个按键都可以触发,字母按键是无法区分大小写

keypress 只有可输入字符按键能触发,且能区分大小写

6.3 文档事件

load		文档中所有的一切加载完毕
unload		文档关闭
beforeunload	文档关闭之前,用来实现窗口关闭的时候确认是否关闭
DOMContentLoaded  文档加载完毕,用来替换 load 事件的; 页面中所有的元素加载完毕就触发; 建议使用
window.onbeforeunload = function(){
	return '您确定要关闭吗?';
}

文档事件通常绑定给 window

load 事件和 DOMContentLoaded 事件的区别:

① load 事件三种绑定方式都可以绑定;DOMContentLoaded 事件只能使用 addEventListener 绑定

② load 等到页面中所有的一切(包括外部的图片文件、视频文件等)加载完毕才触发; DOMContentLoaded 只要页面中的元素加载完毕就触发。

6.4 表单事件

submit 	表单提交的时候,绑定给 form 元素
reset	表单重置的时候,绑定给 form 元素
blur	失去焦点,绑定给表单控件元素
focus	获取焦点,绑定给表单控件元素
select	文本被选中,绑定给可输入元素
change	对于输入框元素,内容改变并且失去焦点才会触发; 对于复选框、单选按钮、下拉选项,只有修改就触发

6.5 图片事件

load	图片文件加载完毕
error	图片加载错误
abort	图片加载中断(了解)

6.6 其他事件

resize	 视口大小发生变化触发事件,绑定给 window
scroll	 元素中的内容发生滚动就可以触发事件; 监听整个页面内容滚动绑定给 window

获取页面内容滚动了多少:

document.documentElement.scrollTop || document.body.scrollTop;

7 event对象

7.1event对象的获取

事件的回调函数自动获取形参,可以得到event事件

7.2鼠标事件对象mouseEvent

clientX/clientY 获取鼠标在视口上的位置
pageX/pageY 获取鼠标在页面(根元素)上的位置
scrennX/screenY 获取鼠标在屏幕上的位置
offsetX/offsetY获取鼠标在目标元素上的位置
button  获取鼠标的按键 : 0:左键 1:滚轮键 2:右键

7.3 键盘事件对象 KeyBorardEvent

keyCode  获取按键的ascii值(数字)
which   同keycode
key 获取按键的值 (字符串)

7.4 所有的事件对象都有的属性

type 获取事件的类型(事件的名字)
timestamp获取触发事件的时刻与打开页面的时刻相距的毫秒数
target 获取目标元素
stopPropagation()阻止冒泡
preventDefault()阻止浏览器默认行为

7.5 浏览器的默认行为

① 浏览器有哪些默认行为
所有的元素右击默认出现系统菜单
超连接点击默认会跳转
提交按钮和重置按钮点击默认触发表单的提交和重置
表单与元素默认有提交行为和重置行为
②阻止浏览器默认行为
在事件的回调函数内;
event.preventDefault()或者return  false

8 事件委托

事件委托:把某个元素的事件,委托到其他元素上(通常是祖先元素)

实现方式:

把事件添加到元素的祖先元素上,触发事件的时候,判断目标元素是否是我们要监听事件的元素,如果是就执行相关操作,否则什么都不干

//如果目标元素是li,执行相关操作
if(event.target.nodeName.toUpperCase()==='LI'){
//切换active类名
event.target.classListtoggle('active');
}

事件委托的优势:

①减少内存消耗;如果需要给很多元素添加某个事件,可以委托到他们共同的祖先元素上

②让动态的添加元素也有事件

9 DOM 对象深入分析

9.1 元素对象的原型链关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sCRAaJbh-1604558343647)(G:/SH200910SH/02阶段_JavaScript/Day17/图例/01-元素对象原型链.png)]

9.2 事件对象的原型链关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lE1TfbZ-1604558343649)(G:/SH200910SH/02阶段_JavaScript/Day17/图例/02-事件对象原型链.png)]

9.3 HTMLCollection 和 NodeList 的区别

  1. HTMLCollection 是所有元素的集合; NodeList 是所有节点的集合。
  2. HTMLCollection 对象没有 forEach 方法; NodeList 具有 forEach 方法。
  3. HTMLCollection 是动态的,获取了集合之后再在页面中添加元素,集合会动态变化;NodeList 是静态的,获取了之后就不会改变了。

1 基础深入总结

1.1 null 和 undefined

1. null 和 undefined 区别?
undefined 表示变量没有赋值
null 变量有值,值是 null

2. 什么时候得到的是 undefined
① 定义变量,没有赋值
② 使用对象中不存在的属性
③ 函数中的形参没有对应的实参
④ 函数没有返回值

3. 什么时候得到是 null
① 定义变量或对象中的属性,暂时不知道赋什么值,可以先赋值为 null
② dom中,获取元素对象的时候,如果没有满足条件的元素,得到就是 null

2 JavaScript 中的垃圾回收机制(GC)

① 垃圾回收相关概念
1. 什么是垃圾对象(数据)
   对象(数据)没有被引用,就是垃圾
   
2. 垃圾回收
   清除掉垃圾对象,就是垃圾回收
   JS/Java/Python/php 等自动垃圾回收
   C/C++手动垃圾回收
   
3. 内存泄漏
   如果内存中的垃圾对象没有被及时回收,就会常驻内存;长时间会造成内存存储空间不足,导致数据泄漏。
   
4. 垃圾回收的常见算法
	引用计数	老版本IE
	标记清除	新版本IE和其他浏览器
	
5. JS中变量的生命周期
   全局变量,所有代码执行完毕,会被清除。
   局部变量,函数调用结束,会被清除。
② 引用计数
引用计数的原理:
	每个对象都有一个标记来记录引用次数,初始值是0
	一个对象如果被引用(被变量或者属性),引用标记 +1;每被引用一次,引用标记就 +1
	如果取消对该对象的引用(变量或属性被销毁或者被该值),引用标记 -1
	当对象的引用标记为 0 的时候,说明没有人引用该对象,该对象会被回收
优缺点:
-优点: 垃圾对象回收得比较及时
-缺点: 对象如果互相引用,会造成内存泄漏
③ 标记清除
原理:
	系统定时执行标记清除操作;
	每次执行标记清除操作的时候,分为两个阶段:
		标记阶段:从跟对象通过属性向下查找,一层一层查找,能被指向的对象称之为可到达对象,可到达对象被添加一个标记,表示可以被引用。
		清除阶段:遍历内存中所有的对象,没有标记的对象都会被清除。 清除结束后,会重置标记,为了下一次的标记清除。
		
优缺点:
-优点: 相对于引用计数,不会造成内存泄漏
-缺点: 需要深度递归,计算量大;定时进行标记清除,垃圾对象不会被立即回收。

3 执行上下文和执行栈

3.1 执行上下文

① 全局执行上下文
1. 在执行全局代码之前,确定 window 为全局执行上下文
2. 全局执行上下文进行预处理操作
	全局变量提升,全局变量添加为 window(全局执行上下文) 的属性,值是 undefined
	全局函数提升,全局函数添加为 window(全局执行上下文) 的方法。
	设置 this 的指向 window (全局执行上下文)
3. 正式执行全局代码
② 函数内的执行上下文
1. 当调用函数的时候,创建一个函数内的执行上下文对象
2. 执行上下文对象进行预处理
	给形参赋值,形参添加为执行上下文对象的属性
	给arguments 赋值,argument 添加为执行上下文对象的属性
	局部变量提升,添加为执行上下文对象的属性,值是 undefined
	局部的函数提升,添加为执行上下文对象的方法
	设置 this 指向调用该函数的对象
3. 执行函数体内的语句	

注意:

  1. 函数每调用一次,就会在函数内创建一个执行上下文对象。 函数如果被调用多次,每次产生的局部变量各自属于各自的执行上下文对象。
  2. JS 没有提供获取函数内执行上下文对象的方式,但是该执行上下文对象是确实存在。

3.2 执行栈

JS 引擎在开始执行 js 脚本的时候,首先会创建一个执行栈,也叫调用栈,用来存储执行过程中产生的执行上下文对象。

是一种经典的数据结构,特点是先进后出或者后进先出。

数据放入栈称之为进栈或者压栈(创建数据); 数据从栈中移除称之为出栈(销毁数据)。

JS 引擎先执行 执行栈里栈顶的上下文。

JS执行过程:
1. 在执行脚本之前先创建一个执行栈。
2. 首先创建全局执行上下文对象,并压栈;
3. 当调用函数的时候,会创建函数的执行上下文对象,并压栈。
4. 函数调用结束,函数的执行上下文对象出栈。
5. 最后执行栈只剩下全局执行上下文对象,最后才出栈。

3.3 作用域和执行上下文的关系

区别:
	1. 作用域是用来描述变量的特性的;变量会作为执行上下文对象的属性。
	2. 变量的作用域在声明函数的时候就确定了,静态的; 在函数调用的时候会创建执行上下文对象,是动态的。
	
联系:
	执行上下文对象也有作用域,全局执行上下文对象有全局作用域,函数内的执行上下文对象有局部作用域

4. 闭包

4.1 什么是闭包?

某个函数中可以使用其他函数作用域内的变量
在函数B的外部调用函数A,但是函数A中可以使用函数B作用域内的变量,就产生闭包

4.2 如何产生闭包

1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A
2. 函数A要使用函数B作用域内的变量
3. 在函数B中把函数A返回
   或者
   把函数A作为一个回调函数被使用(通常作为事件或定时器的回调函数)
//  1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A
function B(){
    var x = 100;
    var y = 200;
    
    function A(){
        // 2. 函数A要使用函数B作用域内的变量
        console.log(x + y);
    }
    
    // 3. 在函数B中把函数A返回
    return A;
}

var f = B();
f();  // 在函数B的外部调用函数f,可以使用函数B作用域内的x和y

4.3 闭包和作用域

1. 调用函数B,返回值值赋值给了 f,调用了 f。
2. 执行 f 函数体内的语句, f 指向的是函数 A,函数体内使用了变量 x 和 变量 y
3. 本作用域下并没有声明变量 x 和 y,根据作用域链的规则,读取上层作用域中的变量 x 和 y(函数 B 的作用域内)

作用域只与函数声明的位置有关系!与函数调用位置无关!

4.4 闭包和垃圾回收

1. 函数函数B,函数B调用结束之后,检查局部变量 x、y 和 A 是否还被引用,如果没有被引用,就销毁
2. A 被返回,赋值给了 f,而 A 的内部又引用了 x 和 y,所以虽然函数B调用结束了,但是变量x、y和函数A都没有被销毁
3. 等到变量 f 被销毁,变量x、y和函数A才会失去引用被清除

闭包延长了局部变量的生命周期!

4.5 闭包的缺点

缺点:
导致局部变量常驻内存,有内存泄漏的风险

解决方式:
1. 能不闭包就不闭包
2. 不要多次引用
3. 必要时可以手动解除引用关系,赋值为 null

4.6 闭包的应用

利用闭包实现JS模块
1. 把实现某个功能所有的代码封装成一个模块
2. 把代码全部写入一个自调用函数,不对外暴露
3. 模块还需要对外暴露一个方法(全局变量)
4. 对外暴露的方式:
   ① 返回,使用一个全局变量接收
   ② 把要暴露的方法赋值给 window 的属性

5对象高级

5.1创建对象的方式

① Object构造函数
new Object()
② 直接量/字面量方式
{}
③工厂模式
function factory(name,age){
	//对属性值进行处理
    return {
        name:name,
        age:age
    }
}
④自定义构造函数
function Foo(){
    
}
new Foo()
⑤自定义构造函数和原型结合
function Foo(name,age){
    this.name=name;
    this.age=age;
}
Foo.portotype.say=function(){
    
}

5.2面向对象继承

//定义父类
class Animal{
	public weight;
	public height;
}
//定义子类
class Dog extends Animal{
    public chishi;
}
//定义子类
class Cat extends Animal{
    public chilaoshu;
}
d=new Dog();
c= new Cat();

1.3js 中继承关系的特点

1.构造函数A的实例的原型指向构造函数B的一个实例,可以说A继承了B
2.如果一个对象想要作为其他对象的原型,建议给该对象设置constructor属性,指向以他为原型的对象的构造函数

1.4 实现js中构造函数和构造函数之间继承

//父类
function Animal(weight,height){
    this.weight =weight;
    this.height=height;
}
Animal.prototype.eat =function(){}
//子类
function Person(name,weight,height){
    this.name=name;
    //调用父类,把父类设置的属性添加到子类实例
    Animal.call(this,weight,height);
}
//设置Person实例的原型是Animal的一个实例
Person.prototype=new Animal();
//设置Person实例的原型上的constructor属性指向Person
Person.prototype.constructor=Person;
Person.prototype.say=function(){}

内的执行上下文对象有局部作用域




## 4. 闭包

### 4.1 什么是闭包?

某个函数中可以使用其他函数作用域内的变量
在函数B的外部调用函数A,但是函数A中可以使用函数B作用域内的变量,就产生闭包


### 4.2 如何产生闭包

  1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A
  2. 函数A要使用函数B作用域内的变量
  3. 在函数B中把函数A返回
    或者
    把函数A作为一个回调函数被使用(通常作为事件或定时器的回调函数)

```js
//  1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A
function B(){
    var x = 100;
    var y = 200;
    
    function A(){
        // 2. 函数A要使用函数B作用域内的变量
        console.log(x + y);
    }
    
    // 3. 在函数B中把函数A返回
    return A;
}

var f = B();
f();  // 在函数B的外部调用函数f,可以使用函数B作用域内的x和y

4.3 闭包和作用域

1. 调用函数B,返回值值赋值给了 f,调用了 f。
2. 执行 f 函数体内的语句, f 指向的是函数 A,函数体内使用了变量 x 和 变量 y
3. 本作用域下并没有声明变量 x 和 y,根据作用域链的规则,读取上层作用域中的变量 x 和 y(函数 B 的作用域内)

作用域只与函数声明的位置有关系!与函数调用位置无关!

4.4 闭包和垃圾回收

1. 函数函数B,函数B调用结束之后,检查局部变量 x、y 和 A 是否还被引用,如果没有被引用,就销毁
2. A 被返回,赋值给了 f,而 A 的内部又引用了 x 和 y,所以虽然函数B调用结束了,但是变量x、y和函数A都没有被销毁
3. 等到变量 f 被销毁,变量x、y和函数A才会失去引用被清除

闭包延长了局部变量的生命周期!

4.5 闭包的缺点

缺点:
导致局部变量常驻内存,有内存泄漏的风险

解决方式:
1. 能不闭包就不闭包
2. 不要多次引用
3. 必要时可以手动解除引用关系,赋值为 null

4.6 闭包的应用

利用闭包实现JS模块
1. 把实现某个功能所有的代码封装成一个模块
2. 把代码全部写入一个自调用函数,不对外暴露
3. 模块还需要对外暴露一个方法(全局变量)
4. 对外暴露的方式:
   ① 返回,使用一个全局变量接收
   ② 把要暴露的方法赋值给 window 的属性

5对象高级

5.1创建对象的方式

① Object构造函数
new Object()
② 直接量/字面量方式
{}
③工厂模式
function factory(name,age){
	//对属性值进行处理
    return {
        name:name,
        age:age
    }
}
④自定义构造函数
function Foo(){
    
}
new Foo()
⑤自定义构造函数和原型结合
function Foo(name,age){
    this.name=name;
    this.age=age;
}
Foo.portotype.say=function(){
    
}

5.2面向对象继承

//定义父类
class Animal{
	public weight;
	public height;
}
//定义子类
class Dog extends Animal{
    public chishi;
}
//定义子类
class Cat extends Animal{
    public chilaoshu;
}
d=new Dog();
c= new Cat();

1.3js 中继承关系的特点

1.构造函数A的实例的原型指向构造函数B的一个实例,可以说A继承了B
2.如果一个对象想要作为其他对象的原型,建议给该对象设置constructor属性,指向以他为原型的对象的构造函数

1.4 实现js中构造函数和构造函数之间继承

//父类
function Animal(weight,height){
    this.weight =weight;
    this.height=height;
}
Animal.prototype.eat =function(){}
//子类
function Person(name,weight,height){
    this.name=name;
    //调用父类,把父类设置的属性添加到子类实例
    Animal.call(this,weight,height);
}
//设置Person实例的原型是Animal的一个实例
Person.prototype=new Animal();
//设置Person实例的原型上的constructor属性指向Person
Person.prototype.constructor=Person;
Person.prototype.say=function(){}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值