day07
预解析
在代码执行之前 对代码进行通读且解释
预解析只解析两部分内容
- var声明的变量(只对声明的变量提前声明 暂时不赋值
- 声明式函数(赋值式函数按照var变量的规则进行解释)
- 打开浏览器时 只会解析全局代码
- 函数里的代码 只有在调用时才会预解析
预解析重名
<script>
// fn();
function fn(){
console.log('hello world')
}
// fn();
var fn=100;
// fn();
function fn(){
console.log('no')
}
//函数在预解析阶段会覆盖同名函数
//而同名函数的变量 会在执行阶段覆盖函数 所以函数覆盖不了同名变量
fn()
var fn = 100;
fn()
function fn(){console.log('你长的好像一个人,我妈妈的儿媳妇')}
fn()
// 预解析
// 1.不需要
// 2.声明一个fn变量 但是没有赋值
// 3.不需要
// 4.需要 在浏览器声明一个fn的变量 并且直接给他赋值一个函数
// 5.不需要
// 预解析结束 fn被声明 并且是个函数
// 执行阶段
// fn() 正常调用
// fn = 100 把变量赋值给fn ()
// fn() 把fn当做一个函数来调用 而fn已经是个变量了 所以
// 会报错 fn is not a function
作用域
-
一个变量可以生效的范围
-
变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域
全局作用域
- 全局作用域是最大的作用域
- 一个html页面打开就是一个全局作用域
- 在全局作用域定义的变量,可以在任何地方使用。
局部作用域
-
只有函数才有局部作用域
-
定义在哪个作用域内的函数,就是哪个作用域的子级作用域
-
在局部作用域中定义的变量只能在这个局部作用域内部使用。
-
// 变量的定义 // 定义在哪个作用域下 这个变量就是哪个作用域的私有变量 // 只能在这个作用域下或者这个作用域的子级作用域内使用 // 不能在父级作用域使用 = >
// function test(){
// var haha = 666;
// }
// alert(haha) // haha is not defined
//变量的访问
// 首先在自己的作用域查找 如果有 那么直接使用
// 如果没有自动到父作用域查找 父作用域有 那么就使用
// 如果还没有 再往上一级 直到全局作用域 发现还没有 那么 报错
// xx is not defined
// 变量的赋值
// 现在自己的作用域内部查找 如果有直接赋值
// 如果没有自动到父作用域查找 父作用域有 那么就使用 停止查找
// 父作用域如果没有再往上到父级 直到 全局作用域
// 那么就把这个变量定义为全局变量 再进行赋值
## 函数在两个阶段做的
```js
// 函数定义阶段
// 1-1 现在堆内存中开辟空间
// 1-2 把函数体内的代码 原样复制到空间内(我们写代码写在硬盘上)
// 1-3 把内存的地址 赋值给栈内存的函数名
//函数调用阶段
// 2-1 按照函数名存的地址去找到对应的函数体
// 先判断栈内存中是否有这个变量
// 如果存在 也会判断里边是否存储的还一个函数体
// 2-2 在调用栈 内开辟一个新的 函数执行空间 (一个函数可以被多次调用为了避免一个调用出现的结果影响所有的调用
//所以每次的调用都会申请一个执行空间)
// 2-3 在执行空间内 给形参赋值
// 2-4 在执行空间内 对函数体内的代码进行预解析
// 2-5 在执行空间内 对函数体内的代码 执行一遍
// 2-6 完成以后 这个执行空间被销毁 或者理解为空间被收回
内存
栈内存
存放哪些
- 基本数据类型
- 函数名在 栈内存
堆内存
- 复杂数据类型 引用数据类型
- 函数体
变量三大机制
变量的定义
- 定义在哪个作用域下,这个变量就是哪个作用域的私有变量
- 只能在这个作用域或这个作用域的子级作用域使用
例
var n1 = 100;
function fn1(){
var n2 = 200; // n2是fn1的私有变量 只能在fn1下 或者fn1的子级下面使用
console.log(n2);
console.log(n1);
}
fn1()
console.log(n2);
变量的访问
- 在访问一个变量时,先在自己的作用域查找,如果有直接使用
- 如果没有就往上到父作用域查找
- 一直往上找 一直到全局作用域 如果没有,就报错
- xx is not defined
变量的赋值
- 在给一个变量赋值时,需要查找变量定义的地方
- 先在自己的作用域查找,如果有直接赋值
- 如果没有就到父级找,父级没有就继续往上找
- 到全局作用域时,就自动把这个变量定义为全局变量 再进行赋值。
例
var n = 100;
function fn1(){
var n = 200;
console.log('前',n);
n = 500
console.log('后',n);
}
// console.log('全局',n);
// fn1()
// console.log('全局后',n);
//子元素 光赋值如n=100; 则没有var定义,就往父级上找
// 如果父级有,就替换掉父级的
//如果父级也没有 就直接定义成全局变量
面试题例
var a=b=10;
a = 20;
b = 20;
console.log(a)
console.log(b)
//预解析
// 仅仅是声明一个全局变量a
//执行代码
// 1. b = 10 标准的变量赋值
// 这时候 全局没有b 那么b当做了一个全局变量 并赋值
// 2. a = b
递归函数
即自己调用自己
注意:一定要设置好结束条件
- 写一个函数
- 写好结束条件
- 没达到结束条件 不要忘了return
例
//求哪个数的阶乘
// function fn(num){
// if(num==1){return 1}
// return num*fn(num-1);
// }
// var num = prompt('输入数字')
// document.write(fn(num));
对象
- 对象是一个复杂数据类型
var obj = {
num: 100,
str: 'hello world',
boo: true
}
- 对象的{}是写一些数据的
- 对象是一个键值对的集合
创建一个对象
-
字面量的方式创建一个对象
// 创建一个空对象 var obj = {} // 像对象中添加成员 obj.name = 'Jack' obj.age = 18
-
内置构造函数的方式创建对象
// 创建一个空对象 var obj = new Object() // 向对象中添加成员 obj.name = 'Rose' obj.age = 20
对象的操作
- 增
var obj = {
num: 100,
str: 'hello world',
boo: true
}
obj.height ='181cm';
- 删
delete obj.height;
- 改
//重新赋值就是改
obj.num=200;
- 查
alert(obj.num)
另一种写法
// 增 对象名['键名'] = 值
// delete 对象名['键名'] = 值
// 对象名['键名'] = 值
//对象名['键名']
//当对象的键名字中有 纯数字 特殊符号
// 这个时候 增删改查 要使用 中括号的方式巧用