作用域
一个变量可以生效的范围
- 变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域
全局作用域
- 全局作用域是最大的作用域
- 在全局作用域中定义的变量可以在任何地方使用
- 页面打开的时候,浏览器会自动给我们生成一个全局作用域
window
- 这个作用域会一直存在,直到页面关闭就销毁了
局部作用域
- 局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域
- 在局部作用域中定义的变量只能在这个局部作用域内部使用
- 在 JS 中只有函数能生成一个局部作用域,别的都不行
- 每一个函数,都是一个局部作用域
var num2=300
function fn() {
// 下面这个变量就是一个 fn 局部作用域内部的变量
// 只能在 fn 函数内部使用 外面是否有相同的值与里面的值无关 两个分隔的区间他的改变不会改变外面的
//但是他可以 用外面的数 类似于公家不可以用私人的 私人可以用公家的
var num2 = 200
}
fn()
预解析
//代码执行之前 对代码进行通读并且解释
//只解析两部分内容
// 1. var 声明的变量名;
// => 仅仅是对var 声明的变量提前声明 暂时不赋值
// 2. 声明式的函数
// => 对函数名字提前声明 并且直接给这个函数名赋值了 一个函数
// => 赋值式的函数按照 var 变量的规则进行 解释
例
var num = 100
console.log(100)
// 预解析
// 第一步需要预解析 告诉浏览器 定义了一个叫做num的变量 但是不赋值
// 第二步.不需要预解析
//代码执行
// 1.num = 100
// 2.打印num的值
console.log(num);
var num = 100;
console.log(num);
// 预解析
// 1 .不需要
// 2. 需要预解析 告诉浏览器 定义了一个叫做num的变量 但是不赋值
// 3. 不需要
// 代码执行
// 1. console.log(num); 因为预解析的时候仅仅是 声明 但是没有赋值
//所以结果是undefined
// 2. num = 100
// 3 打印num 的值输出到控制台
例
fn()
var fn = function(){console.log('卧榻之侧岂容他人鼾睡')}
fn()
//预解析
// 1.不需要
// 2.需要
// 声明一个fn的变量 但是不赋值
// 3.不需要解析
// 代码执行
// 1.把fn 当做函数来调用
// => 预解析阶段我们已经声明了函数 但是没有赋值
// => 此时的fn是一个undefined,你把undefined当做一个函数来调用
// 2. 给fn 一个赋值 将函数赋值给fn
// 3.把 fn 当做一个正常的函数用 正常执行
function fn(){
var num = 100;
console.log(num)
}
// 如果仅仅写了上面代码 没有调用 也会预解析
// 声明变量 并且将 函数赋值给它 这时候不解析函数内部
// fn()
// 当调用的时候才解析函数内容
// 预解析
// 直接声明一个fn的变量 并且将一个函数赋值给它
//代码执行
// fn()
// 函数内部 预解析
// 解析var 变量 仅仅声明 没有赋值
// 函数内部执行
// num = 100
// 输出到控制台
函数两个阶段
var test = function(num){
alert(num);
}
var haha = test;
haha(100);
//函数定义阶段
// 1-1 现在堆内存中开辟空间
// 1-2 把函数体内的代码 原样复制到空间内(我们写代码写在硬盘上)
// 1-3 把内存的地址 赋值给栈内存的函数名
//函数调用阶段
// 2-1 按照函数名存的地址去找到对应的函数体
// 先判断栈内存中是否有这个变量
// 如果存在 也会判断里边是否存储的还一个函数体
// 2-2 在调用栈 内开辟一个新的 函数执行空间 (一个函数可以被多次调用为了避免一个调用出现的结果 影响所有的调用
//所以每次的调用都会申请一个执行空间)
// 2-3 在执行空间内 给形参赋值
// 2-4 在执行空间内 对函数体内的代码进行预解析
// 2-5 在执行空间内 对函数体内的代码 执行一遍
// 2-6 完成以后 这个执行空间被销毁 或者理解为空间被收回
获取变量的规则
- 首先,在自己的作用域内部查找,如果有,就直接拿来使用
- 如果没有,就去上一级作用域查找,如果有,就拿来使用
- 如果没有,就继续去上一级作用域查找,依次类推
- 如果一直到全局作用域都没有这个变量,那么就会直接报错(该变量 is not defined)
- 不能往下找
var num = 100
function fn() {
var num2 = 200
function fun() {
var num3 = 300
console.log(num3) // 自己作用域内有,拿过来用
console.log(num2) // 自己作用域内没有,就去上一级,就是 fn 的作用域里面找,发现有,拿过来用
console.log(num) // 自己这没有,去上一级 fn 那里也没有,再上一级到全局作用域,发现有,直接用
console.log(a) // 自己没有,一级一级找上去到全局都没有,就会报错
}
fun()
}
fn()
赋值规则
- 当你想给一个变量赋值的时候,那么就先要找到这个变量,在给他赋值
- 变量赋值规则: 与获取变量规则差不多
- 先在自己作用域内部查找,有就直接赋值
- 没有就去上一级作用域内部查找,有就直接赋值
- 还没有再去上一级作用域查找,有就直接赋值
- 如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,再给他赋值
function fn() {
num = 100
}
fn()
// fn 调用以后,要给 num 赋值
// 查看自己的作用域内部没有 num 变量
// 就会向上一级查找
// 上一级就是全局作用域,发现依旧没有
// 那么就会把 num 定义为全局的变量,并为其赋值
// 所以 fn() 以后,全局就有了一个变量叫做 num 并且值是 100
// num并不是在fn里面定义的 所以不是fn作用域里的东西 找不到所以定为全局变量
console.log(num) // 100
递归函数
自己调用自己
一个函数内部,调用了自己,循环往复
- 需要有初始化,自增,执行代码,条件判断的,不然就是一个没有尽头的递归函数,我们叫做 死递归
//n的阶乘
function fn(num) {
if (num == 1) return 1;
return num * fn(num - 1);//自己调用自己 一直到num==1
}
console.log(fn(10))
对象
// 万物皆对象
// 人 姓名:王* 年龄 19 身高:183cm 好人:true 唱歌: 跳舞 谈恋爱 打篮球
// 笔记本: 尺寸:15 价格:8888
// js对象跟这个也是一样
// 键值对的集合 键和值之间: 键值对之间逗号隔开
// 无序的数值集合 可以是任意类型
// 创建对象
// 两种方式
// 字面量的创建方式 1 100 wang
var wang = {
'username':'wang',
'age':18,
goodman:true,
singing:function(){
console.log('窗外的麻雀在电线杆上撒粮');
},
love:function(){
console.log('过了这个村我在下个村等你')
}
}
wangzhen.sex = 1;
alert(wang.sex)
// alert(typeof wang) // object
alert(wang.username) // 查看静态属性不用加()
wang.love() // 调用动态方法 需要加()
// 使用内置的工具(函数)来创建对象
var yinghao = new Object();
yinghao.name = 'ahao';
yinghao.age = 1;
yinghao.eating = function(){
console.log('正在吃')
}
//建议使用第一种来创建对象
// 键的名字按照变量的命名规则 规范
// 不要有重复 后边 会覆盖前面
// 可以使用纯数字 作为键名 自动把数字排到最前面
// 也可以使用特殊符号作为键名
// 键的 可加单引号 可不加单引号 但是如果用特殊符号作为键名 必须加单引号
// 建议使用字符串作为键名
对对象的操作
var song={
'username':'sunxiaotong',
'age':18,
ball:function(){
return '狗'
}
}
// 对对象的
//增
song.height='181cm';
alert(song.height);
// 删
delete song.age;
alert(song.age);
//改
song.username='tong';
alert(song.username);
//查
alert(song.name);//静态
alert(song.ball());//动态
// 增 对象名['键名'] = 值
// delete 对象名['键名'] = 值
// 对象名['键名'] = 值
//对象名['键名']
var pengpeng = {
name:'rock',
age:18,
1:666,
2:888,
'aaa^bbb':999,
'ccc-ddd':777
}
//alert(pengpeng.1);报错
alert(pengpeng['1']) // 弹窗666
// alert(pengpeng.aaa^bbb)
// alert(pengpeng['aaa^bbb'])
//当对象的键名字中有 纯数字 特殊符号
// 这个时候 增删改查 要使用 中括号的方式巧用
var pengpeng = {
name:‘rock’,
age:18,
1:666,
2:888,
‘aaa^bbb’:999,
‘ccc-ddd’:777
}
//alert(pengpeng.1);报错
alert(pengpeng['1']) // 弹窗666
// alert(pengpeng.aaa^bbb)
// alert(pengpeng['aaa^bbb'])
//当对象的键名字中有 纯数字 特殊符号
// 这个时候 增删改查 要使用 中括号的方式巧用