函数
函数的概念
-
先看一段代码
// 这个是我们以前写的一段代码 for (var i = 0; i < 10; i++) { console.log(i) } // 函数,这个 {} 就是那个 “盒子” function fn() { // 这个函数我们以前写的代码 for (var i = 0; i < 10; i++) { console.log(i) } } //函数分为两种 // 系统函数 比如 prompt() alert() // 自定义函数 当系统函数不满足我们的需求 我们可以自己定义函数
函数的两个阶段(重点)
函数定义阶段
-
定义阶段就是我们把代码 放在盒子里面
-
我们有两种定义方式 声明式 和 赋值式
1-1 现在堆内存中开辟空间
1-2 把函数体内的代码 原样复制到空间内(我们写代码写在硬盘上)
1-3 把内存的地址 赋值给栈内存的函数名
// 变量的定义 // 定义在哪个作用域下 这个变量就是哪个作用域的私有变量 // 只能在这个作用域下或者这个作用域的子级作用域内使用 // 不能在父级作用域使用 = > 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 fn2(){ var n = 200; function fn3(){ var n = 300; console.log(n); } fn3(); } //fn2() //fn3() fn2() // 变量的赋值 // 先在自己的作用域内部查找 如果有直接赋值 // 如果没有自动到父作用域查找 父作用域有 那么就使用 停止查找 // 父作用域如果没有再往上到父级 直到 全局作用域 // 那么就把这个变量定义为全局变量 再进行赋值 var n = 100; function fn1(){ var n = 200; console.log('前',n); n = 500 console.log('后',n); } console.log('全局',n); fn1() console.log('全局后',n);
声明式
<script> //声明式 function story(){ document.write('一言之美,贵于千金.——葛洪') document.write('人无忠信,不可立于世.——程颐') document.write('诚信为⼈之本。——鲁迅') document.write('⾔必信,⾏必果。——⼦路') }// function: 声明函数的关键字,表示接下来是一个函数了 // story: 函数的名字,我们自己定义的(遵循变量名的命名规则和命名规范) // (): 必须写,是用来放参数的位置(一会我们再聊) // {}: 就是我们用来放一段代码的位置(也就是我们刚才说的 “盒子”) </script>
赋值式
<script> //赋值式 var storle=function(){ document.write('不信不⽴,不诚不⾏。——晁说之') document.write('读书贵精不贵多。——书摘') document.write('真诚是⼀种⼼灵的开放。——拉罗什富科') document.write('腹有诗书⽓⾃华,读书万卷始通神。——苏轼') }// 不需要在 function 后面书写函数的名字了,因为在前面已经有了 </script>
先判断栈内存中是否有这个变量
2-2 在调用栈 内开辟一个新的 函数执行空间 (一个函数可以被多次调用为了避免一个调用出现的结果影响所有的调用
2-3 在执行空间内 给形参赋值
2-6 完成以后 这个执行空间被销毁 或者理解为空间被收回
-
// 声明式函数 function fn() { console.log('我是 fn 函数') } // 调用函数 fn() // 赋值式函数 var fn2 = function () { console.log('我是 fn2 函数') } // 调用函数 fn()
调用上的区别
-
虽然两种定义方式的调用都是一样的,但是还是有一些区别的
-
// 可以调用 fn() // 声明式函数 function fn() { console.log('我是 fn 函数') } // 可以调用 fn()
-
// 会报错 fn() // 赋值式函数 var fn = function () { console.log('我是 fn 函数') } // 可以调用 fn()
函数的参数(重点)
-
现在我们就来说一下这个
()
的作用 -
就是用来放参数的位置
-
参数分为两种 行参 和 实参
// 声明式 function fn(行参写在这里) { // 一段代码 } fn(实参写在这里) // 赋值式函数 var fn = function (行参写在这里) { // 一段代码 } fn(实参写在这里)
行参和实参的作用
-
行参
-
实参
-
function fn(num) { // 函数内部可以使用 num } // 这个函数的本次调用,书写的实参是 100 // 那么本次调用的时候函数内部的 num 就是 100 fn(100) // 这个函数的本次调用,书写的实参是 200 // 那么本次调用的时候函数内部的 num 就是 200 fn(200)
-
多个参数的时候,是按照顺序一一对应的
function fn(num1, num2) { // 函数内部可以使用 num1 和 num2 } // 函数本次调用的时候,书写的参数是 100 和 200 // 那么本次调用的时候,函数内部的 num1 就是 100,num2 就是 200 fn(100, 200)
参数个数的关系
-
行参比实参少
-
因为是按照顺序一一对应的
-
行参少就会拿不到实参给的值,所以在函数内部就没有办法用到这个值
-
行参比实参多
-
因为是按照顺序一一对应的
-
所以多出来的行参就是没有值的,就是
undefined
函数的return(重点)
终断函数
返回值
-
function fn() { // 执行代码 return 100 } // 此时,fn() 这个表达式执行完毕之后就有结果出现了 console.log(fn()) // 100
预解析
-
只解析两部分内容
-
var 声明的变量名; => 仅仅是对var 声明的变量提前声明 暂时不赋值
-
声明式的函数
=> 对函数名字提前声明 并且直接给这个函数名赋值了 一个函数
=> 赋值式的函数按照 var变量的规则进行 解释
<script> function fn(){ var num = 100; console.log(num) } // 如果仅仅写了上面代码 没有调用 也会预解析 // 声明变量 并且将 函数赋值给它 这时候不解析函数内部 // fn() // 当调用的时候才解析函数内容不 // 预解析 // 直接声明一个fn的变量 并且将一个函数赋值给它 //代码执行 // fn() // 函数内部 预解析 // 解析var 变量 仅仅声明 没有赋值 // 函数内部执行 // num = 100 // 输出到控制台 </script>
-
作用域
变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域
全局作用域
-
全局作用域是最大的作用域
-
在全局作用域中定义的变量可以在任何地方使用
-
/全局作用域 // 一个html 页面打开这就是一个全局作用域 // => window (了解) // 私有作用域 局部作用域 // 只有函数才有 if while do while for 他们都没有局部作用域 // 作用域的上下级关系 // 定义在哪个作用域内的函数 就是哪个作用域的子级作用域
// 下面两个变量都是存在在全局作用域下面的,都是可以在任意地方使用的 var num = 100 // 私人可以使用公家的东西 var num2 = 200 // 公家不能随便使用私人的东西
局部作用域
-
局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域
-
在局部作用域中定义的变量只能在这个局部作用域内部使用
-
// 这个 num 是一个全局作用域下的变量 在任何地方都可以使用 var num = 100 function fn() { // 下面这个变量就是一个 fn 局部作用域内部的变量 // 只能在 fn 函数内部使用 var num2 = 200 } fn()
变量使用规则(重点)
-
有了作用域以后,变量就有了使用范围,也就有了使用规则
-
变量使用规则分为两种,访问规则 和 赋值规则
变量的定义
//定义在哪个作用域下 这个变量就是哪个作用域的私有变量 // 只能在这个作用域下或者这个作用域的子级作用域内使用 // 不能在父级作用域使用 = > var n1 = 100; function fn1(){ var n2 = 200; // n2是fn1的私有变量 只能在fn1下 或者fn1的子级下面使用 console.log(n2); console.log(n1); } fn1() // console.log(n2);
访问规则
-
获取变量的规则:
-
首先,在自己的作用域内部查找,如果有,就直接拿来使用
-
如果没有,就去上一级作用域查找,如果有,就拿来使用
-
如果没有,就继续去上一级作用域查找,依次类推
-
如果一直到全局作用域都没有这个变量,那么就会直接报错(该变量 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() var n = 100; function fn2(){ var n = 200; function fn3(){ var n = 300; console.log(n); } fn3(); } //fn2() //fn3() fn2()
-
-
变量的访问规则 也叫做 作用域的查找机制
-
作用域的查找机制只能是向上找,不能向下找
function fn() { var num = 100 } fn() console.log(num) // 发现自己作用域没有,自己就是全局作用域,没有再上一级了,直接报错
赋值规则
-
当你想给一个变量赋值的时候,那么就先要找到这个变量,在给他赋值
-
变量赋值规则:
-
先在自己作用域内部查找,有就直接赋值
-
没有就去上一级作用域内部查找,有就直接赋值
-
还没有再去上一级作用域查找,有就直接赋值
-
如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,再给他赋值
function fn() { num = 100 } fn() // fn 调用以后,要给 num 赋值 // 查看自己的作用域内部没有 num 变量 // 就会向上一级查找 // 上一级就是全局作用域,发现依旧没有 // 那么就会把 num 定义为全局的变量,并为其赋值 // 所以 fn() 以后,全局就有了一个变量叫做 num 并且值是 100 console.log(num) // 100 var n = 100; function fn1(){ var n = 200; console.log('前',n); n = 500 console.log('后',n); } console.log('全局',n); //100 fn1() console.log('全局后',n);//100
-
递归函数
-
// 下面这个代码就是一个最简单的递归函数 // 在函数内部调用了自己,函数一执行,就调用自己一次,在调用再执行,循环往复,没有止尽 function fn() { fn() } fn()
-
其实递归函数和循环很类似
<script>//.求斐波那契数列列中第n个数的值:1,1,2,3,5,8,13,21,34.... 前两个相加 function feibo(n){ var a=1 var b=1 var c=0 if(n<=2){ return 1 }else{ while(n>2){ c=a+b a=b b=c n-- } return c } } document.write(feibo(6)) </script> <script> //递归版 function age(num){ if(num<=2)return 1 return age(num-1)+age(num-2) } document.write(age(6)) </script>
对象
-
对象是一个复杂数据类型 万物皆对象
-
其实说是复杂,但是没有很复杂,只不过是存储了一些基本数据类型的一个集合
var obj = { num: 100, str: 'hello world', boo: true }
-
这里的
{}
和函数中的{}
不一样 -
对象就是一个键值对的集合
-
也就是说,我们可以把一些数据放在一个对象里面,那么他们就互不干扰了
创建一个对象
-
字面量的方式创建一个对象
var wangzhen = { 'username':'wangzhen', 'age':18, goodman:true, singing:function(){ console.log('窗外的麻雀在电线杆上撒粮'); }, love:function(){ console.log('过了这个村我在下个村等你') } } wangzhen.sex = 1; alert(wangzhen.sex) // alert(typeof wangzhen) // object alert(wangzhen.username) // 查看静态属性不用加() wangzhen.love() // 调用动态方法 需要加() // 使用内置的工具(函数)来创建对象
-
内置构造函数的方式创建对象
var yinghao = new Object(); yinghao.name = 'ahao'; yinghao.age = 1; yinghao.eating = function(){ console.log('正在吃') }
建议使用第一种来创建对象
键的名字按照变量的命名规则 规范
不要有重复 后边 会覆盖前面
可以使用纯数字 作为键名 自动把数字排到最前面
也可以使用特殊符号作为键名
键的 可加单引号 可不加单引号 但是如果用特殊符号作为键名 必须加单引号
建议使用字符串作为键名
var jianzeng = {
name:'jiangjiang',
age:18,
ball:function(){
return '千锋白巧克力'
}
}
// 增
// jianzeng.height = '181cm';
// alert(jianzeng.height)
减 delete
// alert(jianzeng.age);
// delete jianzeng.age;
// alert(jianzeng.age);
// 改
//重新赋值就是改的过程
// alert(jianzeng.name);
// jianzeng.name = 'xiaojiang'
// // alert(jianzeng.name);
// //查
// alert(jianzeng.age) // 查看静态属性
// alert(jianzeng.ball())//调用动态方法
当对象的键名字中有 纯数字 特殊符号
这个时候 增删改查 要使用 中括号的方式巧用