目录
函数: 允许封装一系列代码,当想要完成某一任务时,只需要调用相应的代码即可。
函数
// 函数声明
function 函数名(形参列表){
函数体
return 返回值;
// return 后面的代码就不会生效了
}
//或者也可以通过下列的方式进行定义函数
//函数表达式
var 函数名 = function(形参列表){
函数体
return 返回值;
// return 后面的代码就不会生效了
}
函数声明提前
函数也是有变量声明提前的
// 函数也是有变量声明提前的
fpp(20000); //我是函数fpp20000
function fpp(a){
console.log('我是函数fpp' + a);
}
fpp(10000); //我是函数fpp10000
//基本等于
function fpp(a){
console.log('我是函数fpp' + a);
}
fpp(20000);
fpp(10000);
函数内部属性
arguments
当传递的实参超过形参的个数的时候 不会报错 所有的实参都会保存在 arguments 里 arguments类数组
function foo(a, b){
console.log(arguments);
console.log(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]); // 1 2 3 4 5
return console.log(a, b)
}
foo(1, 2, 3, 4, 5) // 1 2
// 获取一个函数形参的长度
console.log(foo.length) // 2
callee 属性是 arguments 对象的一个成员,当前相关函数正在执行时才可使用
callee 属性的初始值就是正被执行的 Function 对象。
// 实现匿名的递归函数
var sum = function (n) {
if (n == 1) {
return 1;
} else {
return n + arguments.callee(n - 1);
}
}
console.log(sum(6));//输出结果:6+5+3+2+1 = 21
this的指向
面向对象语言中this的指向,都是指向当前调用的对象
然而在JavaScript中不同,this的指向随着环境的变化而变化
1.在函数中this指向全局对象 global window
2.在对象中 this指向拥有该方法得调用者
3.在当前模块 this指向当前模块 {}
4.事件:this指向接收事件得dom元素
function test(){
console.log(this);
};
test(); // 局部作用域 -> 指向的就是全局对象 global
let obj = {
name:'zhangsan',
age:18,
say(){
console.log(this.name);
}
}
obj.say()//this 表示该方法所属的对象
console.log(this); //全局作用域 -> modules.export {}
<script>
//在浏览器环境下 this单独使用 指向的就是window对象
//Window file:///F:/this.html
console.log(this);
</script>
显式函数绑定
在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。
// 显式函数绑定this
// call apply
// call() 方法分别接受参数 apply() 方法接受数组形式的参数
var person1 = {
sayName: function(a){
console.log(this.name + a);
}
};
person1.sayName(); //NaN
var person2 = {
name:'lisi'
};
person1.sayName.call(person2); // lisiundefined
person1.sayName.call(person2, 123); // lisi123
person1.sayName.apply(person2); // lisiundefined
person1.sayName.apply(person2,[123]); // lisi123
IIFE
IIFE立即执行函数,Immediately Invoked Function Expression,意为立即调用的函数表达式。
作用:
1.页面加载完成后只执行一次的设置函数。
2.将设置函数中的变量包裹在局部作用域中,不会泄露成全局变量。
普通函数调用和IIFE函数调用
//普通函数
function foo(){
console.log('1');
}
foo();
//IIFE函数
(function foo(){
console.log('1');
})();
经典面试题-IIFE
for (var i = 0; i < 6; i++) {
function output() {
console.log(i); // 为什么输出的是6,而不是0,1,2,3,4,5
// 因为输出的 i 是全局作用域的,当循环结束后 i 的值是 6,所以输出的 i 就是6。
}
}
output()
for (var i = 0; i < 6; i++) {
(function (j) {
console.log(j); //0,1,2,3,4,5
})(i)
// 因为 JS 中调用函数传递参数都是值传递 ,
// 所以当立即执行函数执行时,首先会把参数 i 的值复制一份,
//然后再创建函数作用域来执行函数,循环5次就会创建5个作用域,
//所以每个输出访问的都是不同作用域的 i 的值 。
}
需要IIFE的原因:JS只有全局作用域和函数作用域,通过立即执行函数隔离作用域。杜绝作用于对于函数的影响。
作用域
ES5中
函数作用域: 在 JavaScript函数中声明的变量,会成为函数的局部变量。
函数内部声明的变量,在函数外部不能访问。
全局作用域:函数之外声明的变量,会成为全局变量。
函数外部声明的变量,在函数内部可以访问。
当函数嵌套,在这个时候,内部函数与外部函数的这个变量就组成了闭包。
//全局作用域:global/window/本文件内
var a = 10;
b = 20; // 所有末定义直接赋值的变量自动声明为拥有全局作用域
function foo() {
//函数作用域、局部作用域
var c = 3;
console.log(a, b);
console.log(this);
}
foo()
// console.log(c); // a is not defined
作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突
作用域链
什么是自由变量
当前作用域没有定义的变量,这就是自由变量 。
下列代码中的a变量就是自由变量
var a = 1;
function foo(){
console.log(a); //1
var b = 2;
console.log(b); //2
}
foo();
什么是作用域链
当前作用域中找不到所需要的变量,就向上一层中寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链 。
var a = 1;
function foo(){
var b = 2;
function fn(){
var c = 3;
console.log(c); // 3
console.log(b); // 2
console.log(a); // 1 如果foo函数中有定义变量a 该打印就会打印foo中的变量a
}
fn();
}
foo();
闭包案例 经典面试题
var a = 10
function fn() {
var b = 20
function bar() {
console.log(a + b) //30
}
return bar
}
var x = fn(); // 执行fn() 返回的是bar
b = 200;
x() //执行x,就是执行bar函数 10+20