复习上周五内容
1、变量内存情况
1、基本类型
变量的值是直接存储在栈区
2、引用类型
变量的值是存储在堆区,栈区中存储的是堆区的地址
总结:
1、变量直接赋值时永远赋值的是栈区存储的值,如果栈区存储的是内容 就直接赋值内容,如果栈区存储的是地址 就直接赋值地址
2、如果变量赋值
基本类型:一个变量修改不会影响到另外一个变量
引用类型:一个变量修改会影响到另外一个变量
2、函数
1、函数作用:函数就是对代码的封装,一次封装多次调用
2、函数语法
创建函数
声明式
function 函数名称([形参]){
//函数体代码
//可选return
}
赋值式
var 变量名称 = function ([形参]){
//函数体代码
//可选return
}
区别在于函数调用 同一个script标签中 声明式 任何位置都可以调用 赋值式只能在之后才可以调用
调用函数
函数名称(实参)
3、函数参数
1、形参与实参:函数创建时使用的参数就是形参,调用函数使用的参数就是实参
2、函数调用时形参赋值
一旦调用函数,系统自动将实参的值按照顺序赋值给形参变量
调用函数时需要注意形参在函数体中修改是否会影响到外面的实参
3、可变参数
就是函数中内置存在arguments变量,arguments 记录着调用函数实所传递的所有的实参并且是按照实参的顺序记录的一个伪数组
建议:在封装函数时避免arguments使用
伪数组转换为真数组的方式
function sum() {
var arr = [];
for (var i = 0; i < arguments.length; i++) {
arr[i] = arguments[i]
}
}
4、函数的返回值
1、终止函数体中后续代码执行
2、将函数结果返回
---
typora-root-url: img
---
# 函数的本质(重点)
1、创建函数的本质
```javascript
// 1、每次创建函数就是在当前创建了一个同名变量
function fn(){
console.log('fn');
}
// 查看fn变量的值 能看到输出证明 函数名称其实就是变量
console.log(fn);
```
2、调用函数
```javascript
// 调用函数 通过变量名称找到函数地址,在将函数的代码运行起来。()表示执行代码的意思
fn()
```
3、内存情况
![1659922740507](/1659922740507.png)
4、赋值式的函数
```javascript
// 赋值式函数 将函数在堆区的内容地址赋值给fn2变量
var fn2 = function(){
console.log('fn2');
}
fn2();
// fn2本质就是一个内存地址 但是在输出时,显示的是代码,因为js不容许操作到内存
console.log(fn2);
```
>总结:每次创建函数时返回的就是内存地址(一定要与return区分)
# 自调用匿名函数
1、匿名函数
```javascript
// 匿名函数 就是函数没有名称
// function(){} =>0X333
// 每次使用匿名函数就等价于直接写了一个内存地址
// 自调用匿名函数
```
2、自调用匿名函数
```javascript
// var fn = function(){} fn()
// 自调用匿名函数中最后一个括号 表示调用,传递的参数 为实参 b变量就是实参 a变量就是形参
// 自调用匿名函数结尾记得打分号
var b = 10;
(function(a){
// 指定函数体的代码
})(b);
```
3、自调用匿名函数的作用
```javascript
//防止变量污染(当使用同名变量时会出现冲突,也需要考虑作用域的问题)
//一旦当自己写第三方的插件时都会使用自调用匿名函数
```
# 函数的执行时机
1、手动调用 明确使用函数名称() 调用函数执行
2、自调用函数 只有一次执行机会
3、系统调用 例如后面事件中,函数就是系统在调用
# 回调函数(暂时了解)
## 回调函数基本语法
将函数作为另外一个函数的参数使用
1、函数参数基本类型
```javascript
// 1、函数传递基本类型 在形参赋值时 将n变量的10赋值给a
function fn(a){
console.log(a);
}
var n = 10;
fn(n);
```
2、函数参数引用类型
```javascript
// 2、函数传递引用类 在形参赋值是 将arr变量的内存地址赋值给a变量
function fn2(a){
console.log(a);
// 因为传递过来的是数组,所以可以按照数组的语法将0号元素的值取出使用
console.log(a[0]);
}
var arr = [1,2,3];
fn2(arr);
```
3、回调函数
```javascript
// 3、函数传递函数作为参数
function fn3(cb){
// var cb = callback;
console.log(cb);
// 因为现在cb变量是内存地址 并且内存地址对应的值存储的是函数代码
cb()
}
var callback = function(){
console.log('回调函数');
}
// callback 变量是函数地址。函数传递参数都可以使用数组(引用类型)
fn3(callback)
```
4、回调函数
```javascript
// 4、回调函数的常规写法
function fn4(cb){
// var cb = callback;
console.log(cb);
// 因为现在cb变量是内存地址 并且内存地址对应的值存储的是函数代码
cb()
}
fn4(function(){
console.log('回调函数的运行');
})
```
5、回调函数携带参数
```javascript
// 5、回调函数携带参数
function fn5(cb){
var arr = [1,2,3]
console.log(cb);
// 因为现在cb变量是内存地址 并且内存地址对应的值存储的是函数代码
// 调用函数传递实参
cb(arr)
}
// arr2是形参 可以设置任意名称
fn5(function(arr2){
console.log(arr2);
console.log('回调函数的运行');
})
```
## 回调函数的使用场景
一般当你需要封装函数给别人使用,碰到有些使用无法决定了(如果正常实现,功能会过于单一)就使用回调。使用
回调后功能具体如何实现交给了使用者来决定
# 作用域(重点重点)
## 作用域介绍
**作用域是用于限制当前是否可以使用到这个变量**。目前作用域分两种分别为全局作用域与局部作用域。以函数作为
分割。函数体中创建的变量就是局部作用域变量。排除局部其他的位置都叫做全局(全局是相对而言)
## 全局与局部作用域
1、局部作用域
```javascript
function fn(){
// 只要在fn函数体中创建的变量 就是局部作用域变量
var n = 20;//局部变量
m = 30;//没有 var 不是在函数体中创建变量 所以m不是 局部作用域变量
}
fn();
console.log(m)
console.log(n);
```
2、全局作用域
```javascript
function fn2(){
var m = 1;// m变量相对于fn2外面是局部变量 但是相对于fn3是全局变量
// 将 函数地址赋值给fn3变量 fn3就是一个局部变量
var fn3 = function(){
var n = 2;//局部变量
}
}
// 在页面上存在一个最大的全局变量 叫做window 也叫做window作用域
var f = 3;//全局变量
// window是浏览器自动所提供的 只要打开一个页面 就有一个window变量可以使用
console.log(window);
```
## 作用域访问规则
```javascript
var m = 20;//全局变量
function fn(){
var n = 10;
console.log(n);//10
console.log(m);// 能够输出证明 当前作用域找不到变量 就到上级作用域去找
}
fn();
var j = 30;
function fn2(){
var k = 20;
function fn3(){
console.log(k);//当前作用域 没有的 往上找到fn2中有k变量 所以直接输出20
console.log(j);//当前作用域 没有 到上级fn2中找,也没有找到,继续向上,找到window下找到了 就直接使用
console.log(p);//当前作用域 没有 到上级fn2中找,也没有找到,继续向上,直到window 都还没找到
}
fn3();
}
fn2();
```
![1659930155823](/1659930155823.png)
## 作用域赋值规则
```javascript
// 1、修改当前作用域下的变量
function fn() {
var n = 10;
n = 20; //当前作用域下是存在n变量 所以直接修改
console.log(n);
}
fn();
// 2、当前作用域下不存在 但是上级作用域下存在
var m = 10;
function fn2(){
m = 30;//当前作用域下没有这个变量 就到上级下寻找 找到了这个变量就直接修改
console.log(m);
}
fn2();
console.log(m);
// 3、当前、以及上级作用域都不存在这个变量
function fn3(){
var fn4 = function(){
// 当前作用域下找i找不到、到fn3里面寻找,也找不到,继续到上层window下寻找,到window下还找不到就在window下创建这个变量并且赋值
i = 2;
}
fn4();
}
fn3();
console.log(i)
```
>总结:
>
>1、当访问变量时,如果当前作用域下找到这个变量的创建,就直接使用对应的值,否则就到上级中寻找,如果上级找到了直接用否则继续向上,如果到window下还找不到最后报错
>
>2、当修改变量时,如果当前作用域下找到这个变量就直接修改,否则到上层作用域下寻找,找到了就修改没找到继续向上,直到到了window下 还没有找到就在window下自动创建这个变量并且赋值
# 预解析
## 预解析介绍
编程语言分两类 编译型与解释型。编程语言是人所编写代码,对于计算机是无法识别的。为了让计算机可以识别
编程代码,就必须将编程代码使用工具转换为计算机可以识别的二进制内容。转换工具可以理解为引擎
编译型:代码写完之后 手动进行转换,转换之后就可以直接执行代码 典型代表 c/c++ 、java
解释型:代码一边转换一边执行。典型代表javascript、Python、PHP
**预解析就是代码在解释之前 先将代码的顺序进行调整**
## 全局代码的预解析
1、预解析的现象
```javascript
// 1、预解析现象
console.log(number);
var number = 1;
/*
按照代码的执行顺序分析 先输出number变量 但是此时 根本就不存在该变量。所以应该要报错
原因解释,因为在js中存在预解析功能,会将var的变量与声明式的函数提前
上面的代码预解析之后结果
var number;
console.log(number);
number = 1;
*/
```
2、声明式函数的提前
```javascript
// 2、声明式函数的提前 :将整个函数全部提前
fn();
function fn(){
console.log('fn')
}
/*
预解析之后代码
var fn = function(){console.log('fn')} ;
fn();
*/
```
3、赋值式预解析
```javascript
// 3、赋值式函数预解析
var number = 20;
console.log(fn)
var fn = function(){
console.log('fn');
}
/*
预解析之后的代码
var number;
var fn;
number = 20;
console.log(fn)
fn = function(){console.log('fn')}
*/
```
4、var与函数同名情况
```javascript
// 4、var与函数同名情况
var fn = 200;
function fn(){
console.log('fn');
}
fn();//fn is not a function
/*
当var的变量名称与函数名称不同名,确实是会预解析提前代码
一旦同名时就需要注意先后顺序,
遇到同名变量与函数名称 函数先解析
var fn = function(){console.log('fn')}
fn = 200;
fn()
*/
```
5、预解析的面试题
```javascript
fun();//输出
var fn = function(){
console.log('fn函数调用');
}
function fun(){
console.log('fun函数调用');
}
fn();//输出
fn = 100;
fn();//报错
/*
var fn;
var fun = function(){console.log('fun函数调用');}
fun()
fn = function(){console.log('fn函数调用');}
fn();
fn = 100; 修改fn为数字
fn();
*/
var fun = 200;
fun();
var fun = function () {
console.log('fun函数调用')
}
fun();
/*
var fun;
fun = 200;
fun();//报错 后面什么代码都不执行了
*/
```
## 函数的预解析
```javascript
/*
函数体内部代码的执行顺序 是调用时触发的,并且规则与全局预解析规则一致,唯一的区别在于 形参赋值与预解析的先后顺序
如果形参先赋值 然后在预解析
1、形参赋值
var a = 10;
2、预解析
var a = function(){console.log('a')}
3、执行代码
a();
如果先预解析,再形参赋值
1、预解析
var a = function(){console.log('a')}
2、形参赋值
a = 10;
3、执行代码
a()
*/
function fun(a){
// var a = 10;
function a(){
console.log('a');
}
var n = 10;
a();
}
fun(10);
</script>
```
注意事项
```html
<script>
// js执行时 安装script的段执行,遇到一段script标签将内部代码预解析,在执行,再同样方式处理下一段script
show();//报错 show is not defined
</script>
<script>
function show(){
console.log('show')
}
</script>
```
# 递归
## 递归要素
递归就是函数中自己调用自己
1、分析单个事情(你要做什么)
2、找到退出的条件
3、启动递归
## 使用递归实现计算阶乘
```javascript
// 2、使用递归实现计算阶乘
/*
5! = 5 * 4 * 3 * 2 * 1 = 5 * 4!
4! = 4 * 3!
3! = 3 * 2!
2! = 2 * 1!
1! = 1
getNumberJc(5) = 5 * getNumberJc(4);
getNumberJc(4) = 4 * getNumberJc(3);
getNumberJc(3) = 3 * getNumberJc(2);
getNumberJc(2) = 2 * getNumberJc(1);
getNumberJc(1) = 1;
*/
function getNumberJc(number){
if(number == 1){
return 1;
}
return number * getNumberJc(number -1);
}
console.log(getNumberJc(5));
```
建议能够用循环实现的就使用循环 避免是递归
# 初识对象
## 对象类型介绍
以前有基本类型字符串、数字、布尔、也有引用类型数组。但是这些数据类型都有自己的特点,基本类型 只能取
描述单个信息。数字只能存储一类相同的数据,但是如果需要使用代码表示出一个个体的情况目前数据类型不太合
适。例如介绍一个人可以从多方面来进行描述,例如颜值、身高、存款等。虽然可以使用数组表示,但是时刻需要
记忆每一个元素是什么信息。比较麻烦 需要使用对象完成
## 字面量方式创建对象
```javascript
// {} 表示对象的字面量
// 对象中每一层信息叫做属性,属性区分名称与值。每个属性直接使用逗号分割 名称叫什么自己设置(如果存在特殊符号就需要使用引号包裹),值可以是任意数据类型
var obj = {
name:'渣渣辉',
age:18,
marry:true,
like:['sing','jump','rap'],
son:{
name:'辉渣渣'
},
play:function(){
console.log('一刀999');
}
}
// 1、对象属性的获取
// 对象访问属性的方式一 对象名称.属性名称
// 表示获取到obj变量下的like属性
console.log(obj.like);
// 对象访问属性的方式二 对象名称[变量名称]
var attr = 'son';
// 将变量attr对应的值作为属性名称 取出
console.log(obj[attr]);//这个形式一定要记下来 以后经常用
// 2、对象属性的修改 需要先找到值在修改获取方式与前面以前
// obj.age = 38;
attr = 'age';
obj[attr] = 38;
// 3、删除
delete obj.age;
console.log(obj);
```
## new获取对象
```javascript
// var number = 10;
// 实例化Number的构造函数得到对象
// Number 是系统内置"模板"
var number = new Number(10);
console.log(typeof number)
console.log(number+10)
// 在系统中还内置很多 模板 例如 有 Array String Object等
```
## Dom对象
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="message">提示内容</div>
<input type="text" id="mobile">
<input type="button" id="btn" value="ok">
<script>
// js 控制页面上元素的,控制方式就是通过使用dom对象
// 不常规的作用,直接使用元素的id值变量。系统会自动找
console.log(btn);
// 点击事件
btn.onclick =function(){
console.log('点击事件')
// 获取元素的值
// 1、表单元素
console.log(mobile.value);
// 2、非表单元素
console.log(message.innerHTML);
}
</script>
</body>
</html>
```