✊总有人要成为第一,为什么不是你。
2021年08月05日
工作重点
1 | 工作重点事项 | 进度 | 已完成 |
---|---|---|---|
2 | 上午讲JavaScript函数 | 已完成 | - [x] |
|
| 3 | 下午讲JavaScript函数 | 已完成 |
- [x]
|
| 4 | 晚上总结 | 已完成 |
- [x]
|
遇到的问题和解决思路
遇到的问题
- 当知识点都理解后
-
解决思路
一定要细心细心细心,不要骄傲,不要大意
今日总结
(1)函数
### (2)参数伪数组 ### (3)函数的创建 ### (4)自执行函数 ### (5)参数的返回值 ### (6)函数的类型 ### (7)作用域的优先级 ### (8)变量的声明提前
(9)函数的参数
<script type="text/javascript"><br /> **/***<br />** * 定义一个用来求两个数和的函数**<br />** * 可以在函数的()中来指定一个或多个形参(形式参数)**<br />** * 多个形参之间使用,隔开,声明形参就相当于在函数内部声明了对应的变量**<br />** * 但是并不赋值**<br />** */**<br /> <br /> function sum(a,b){<br /> console.log("a = " + a);<br /> console.log("b = " + b);<br /> console.log(a+b);<br /> }<br /> **/***<br />** * 在调用函数时,可以在()中指定实参(实际参数)**<br />** * 实参将会赋值给函数中对应的形参**<br />** */**<br /> <br />// sum(3,4);<br /> <br /> ** /***<br />** * 调用函数时解析器不会检查实参的类型,**<br />** * 所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查**<br />** * 函数的实参可以是任意的数据类型**<br />** */**<br /> <br /> //sum(123,"hello");<br /> <br /> **/***<br />** * 调用函数时,解析器也不会检查实参的数量**<br />** * 多余实参不会被赋值**<br />** * 如果实参的数量少于形参的数量,则没有对应实参的形参将是undefined**<br />** * **<br />** */**<br />// sum(123,4343,"hello");<br /> //sum(123);//NaN<br /> </script>
JavaScript-函数(重点)
函数其实就是封装,把可以重复使用的代码放到函数中,如果需要多次使用同一段代码,就可以把封装成一个函数。这样的话,在你需要再次写这些代码的时候,你只需要调用一次函数就行了。
1.1 定函数的方式
1.1.1使用字面量的形式定义函数
ECMAScript中的函数使用function关键字来声明,后面跟一组参数及函数体。
函数的基本语法如下:
以下是一个函数的示例:
function sum(num1, num2) {
var num3 = num1 + num2;
return num3;
}
函数的调用:
这个函数的作用是把两个值加起来返回一个结果。函数必须通过调用才会执行,调用这个函数的代码如下:
var result = sum(5, 10); //15
1.1.2使用函数表达式声明函数(匿名函数)
1.1.3使用Function构造函数声明函数
1.1.4 自执行函数
先前咱们写的函数只有在调动的时候才会执行,如果像下面这样写的话,代码执行到这一行的时候,函数会自己执行(或者说自己调用自己)。
(function(a){
console.log(a);
})("abc")
1.2 函数的返回值
函数在执行完return语句之后停止并立即退出。因此,
- 位于return语句后面的任何代码永远都不会执行。
- 一个函数中可以有多个return语句。
- return语句也可以不带任何返回值。
1.3 函数的参数
ECMAScript函数不介意传递进来多少参数,也不在乎传进来的参数是什么数据类型。也就是说,即便你定义的函数只接收2个参数,在调用这个函数的时候也未必一定要传递2个参数。可以传递1个、3个甚至不传递参数,而解析器永远不会有什么怨言。
实际上,传递给函数的所有参数都被保存到了arguments对象中,arguments对象位于函数体内,与数组有点类似(但它并不是Array的实例),参数都被保存到了这个数组中。
有的人可能会问了,既然所有传递进来的参数都被保存到arguments数组中了,那么在声明函数的时候还声明参数干什么?
其实声明形参只是为了方便在函数体中引用传递进来的实参,但这不是必需的,在声明函数时也可以不声明形参。
函数是一种数据类型
function fn() {}
console.log(typeof fn);---返回值是function
- 函数作为参数
因为函数也是一种类型,可以把函数作为一个函数的参数,在一个函数中调用
function func1(theFunc){
var r1=arguments[1]
var r2=arguments[2]
theFunc(r1,r2)
}
function func2(a,b){
alert(a+"----"+b);
}
func1(func2,"aaa","bbb");
- 函数做为返回值
因为函数是一种类型,所以可以把函数可以作为返回值从函数内部返回,这种用法在后面很常见。
function fn(b) {
var a = 10;
return function () {
alert(a+b);
}
}
fn(15)();
1.4 作用域
在 Javascript 中,作用域分为 全局作用域 和 函数作用域
全局作用域
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
函数作用域
全局变量和局部变量
变量的作用域范围可分为全局变量和局部变量。
- 全局变量:
在最外层声明的变量叫全局变量。
在函数体内部,没有使用var关键字声明的变量也是全局变量。(不推荐)
- 局部变量:
在函数体内部,使用var关键字声明的变量叫作局部变量。
注意点: 局部变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁
词法作用域
变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。
在 js 中词法作用域规则:
- 函数允许访问函数外的数据.
- 整个代码结构中只有函数可以限定作用域.
- 作用域规则首先使用提升规则分析
- 如果当前作用规则中有名字了, 就不考虑外面的名字
var num = 123;
function foo() {
console.log( num );
}
foo();
if ( false ) {
var num = 123;
}
console.log( num ); // undefiend
作用域链(背会)
只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
将这样的所有的作用域列出来,可以有一个结构:在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
作用域链:采取就近原则的方式来查找变量最终的值。
// 案例1:
function f1() {
function f2() {
}
}
var num = 456;
function f3() {
function f4() {
}
}
// 案例2
function f1() {
var num = 123;
function f2() {
console.log( num );
}
f2();
}
var num = 456;
f1();
*我可以
什么是作用域和作用域链,请解释一下?
作用域(scope)
在 Javascript 中,作用域分为 全局作用域 和 局部作用域
全局作用域:代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
局部作用域:在固定的代码片段才能被访问。
作用域链(scope chain)
在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
1.5 预解析
JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
- 把函数的声明提升到当前作用域的最前面,函数声明代表函数整体,所以函数提升后,函数名代表整个函数
- 先提升var,再提升function。
- 预解析会把变量和函数的声明在代码执行之前执行完成。
- 变量预解析
预解析也叫做变量、函数提升。
变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
- 函数预解析
函数提升: 函数的声明会被提升到当前作用域的最上面,函数声明代表函数整体,所以函数提升后,函数名代表整个函数。
- 特殊情况—函数表达式声明函数问题
函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:
fn();
var fn = function() {
console.log('想不到吧');
}
结果:报错提示 ”fn is not a function"
解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用
举例
var x; console.log(x) x=3;
var a = 1; function test(){ console.log(a); var a = 1; } test();
var b = 1; function fun1() { b = 2; function fun2() { var b = 3; console.log(b); } fun2(); console.log(b); } fun1(); console.log(b);
var b = 1; function fun1(b) { b = 2; console.log(b); } fun1('yy'); console.log(b);
var b = 2; function test2() { window.b = 3; console.log(b); } test2(); console.log(b);
c = 5; function test3() { window.c = 3; console.log(c); var c; console.log(window.c); } test3(); console.log(c);
自己总结
在调用函数时,浏览器每次都会传递进两个隐含的参数:
1.函数的上下文对象 this
2.封装实参的对象 arguments
- arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
- 在调用函数时,我们所传递的实参都会在arguments中保存
- arguments.length可以用来获取实参的长度
- 我们即使不定义形参,也可以通过arguments来使用实参,
只不过比较麻烦
arguments[0] 表示第一个实参
arguments[1] 表示第二个实参 。。。
- 它里边有一个属性叫做callee,
这个属性对应一个函数对象,就是当前正在指向的函数的对象
function loop(num1, num2, num3) {
// 返回结果,renturn 后面的代码是不会执行的
return num1 + num2 + num3;
console.log(num1 + num2 + num3);
// 如果一个函数没有return 默认返回 undefined
}
// value 是函数的返回值
var value = loop(“红烧肉”, “大盘鸡”, “米饭”);
console.log(value);
函数的类型是function
* 函数作用域
* - 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
* - 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
* - 在函数作用域中可以访问到全局作用域的变量
* 在全局作用域中无法访问到函数作用域的变量
* - 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用
* 如果没有则向上一级作用域中寻找,直到找到全局作用域,
* 如果全局作用域中依然没有找到,则会报错ReferenceError
* - 在函数中要访问全局变量可以使用window对象
* 在函数作用域也有声明提前的特性,
* 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
* 函数声明也会在函数中所有的代码执行之前执行
变量的声明提前
- 使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值),
但是如果声明变量时不适用var关键字,则变量不会被声明提前
函数的声明提前
- 使用函数声明形式创建的函数 function 函数(){}
它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
变量提升在函数的提升前面
fun();//能执行
fun2();报错
//函数声明,会被提前创建
function fun() {
console.log(“我是一个fun函数”);
}
//函数表达式,不会被提前创建
// 符合变量的提升规则
var fun2 = function () {
console.log(“我是一个fun2函数”);
};
当形参与局部变量相同且局部变量有赋值时,局部变量的赋值会覆盖形参的值。
var a = 1;
function fun(a) {
console.log(a);//2
console.log(arguments[0])//2
var a = 3;
console.log(a);//3
// 这里,当改变函数形参的值时,arguments对象中的值也会一起变动。
console.log(arguments[0])//3
}
fun(2);
console.log(a);//1
当形参与局部变量相同且局部变量只有声明时,参数不会被局部变量覆盖。
var a = 1;
function fun(a) {
console.log(a);//2
console.log(arguments[0])//2
var a;
console.log(a);//2 不是undefined
console.log(arguments[0])//2
}
fun(2);
console.log(a);//1