前端JavaScript学习笔记之函数
1、函数介绍
函数允许我们封装一系列代码来完成特定的任务。方法一般定义在对象的函数。
函数的作用:功能的封装,直接调用,代码复用率高
函数实际上是对象,每个函数都是function类型的实例,并且都与其他引用类型一样具有属性和方法,由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。
2、函数声明
函数声明有两种:
一是由function关键字声明,后面紧跟函数名,函数名后面为形参列表,列表后面由大括号括起来的内容为函数体
二是定义一个匿名函数,将匿名函数赋值给一个函数变量,这种方式叫做函数表达式
函数声明:
function 函数名(形参列表){
}
函数表达式:
var 函数名 = function(形参列表){
}
函数声明与var变量声明类似,会进行提升
foo();
function foo(){
console.log("hell world");
}
console.log(a);
var a = 'hello';
console.log(a);
3、函数内部属性
只有在函数内部才能访问的属性。this也可以在函数外部进行使用。
argument
ECMAScript函数不介意传递参数的个数以及参数类型,这是因为函数的参数在函数内部使用一个类数组对象来表示的,这个类数组就是argument。
argument是一个类数组,包含着传入函数中的所有参数。argument主要用途是保存函数参数,但是这个对象还有一个名为callee的属性,该属性是一个指针,指向用于这个argument对象的函数。
function add(a,b){
var result = a + b;
return result;
}
console.log(add.length);
Object.getOwnPropertyDescriptor(add,'length');
add(22,42,12,44);
function add(a,b){
console.log(arguments[0],arguments[1],arguments[2],arguments[3]);
console.log(a+b);
}
add(10);
add(10,20);
add(10,20,30);
add(10,20,30,40);
callee
callee属性时argument对象的一个成员对象,仅当相关函数正在执行时才可用。
callee属性的初始值就是正在被执行的function对象
var sum = function (n) {
if (1 == n) {
return 1;
} else {
return n + arguments.callee(n - 1);
}
}
console.log(sum(6));
this
this在js中不是固定不变的,它会随着执行的环境的改变而改变
1、在方法中,this表示该方法所属的对象
? 在下面的实例中,this表示person对象
? fullName 方法所属的对象就是person
var person = {
firstName: "LeBron",
lastName : "James",
id : 8888,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
2、如果单独使用,this表示全局对象
? 在浏览器中,window就是该全局对象 [object Window]
? 在node中,this指向的是一个{}
3、在函数中,this表示全局对象
? 在函数中,函数的所属者默认绑定到this上
? 在浏览器中,window就是该全局对象 [object Window]
? 在node中,指向就是global对象
4、在事件中,this表示接收事件的元素
? 在HTML事件句中,this指向了接收事件的HTML元素
5、在显式函数绑定时,可以自己决定this指向
? 在JavaScript中函数也是对象,对象也有方法,apply和call方法,可以允许切换函数执行的上下文环境(content),即this绑定的对象。
? 在实例中使用person2作为参数来调用person1.fullName方法时,this将指向person2,即使它是person1方法。
var person1 = {
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName: "zhang",
lastName: "san",
}
var name = person1.fullName.call(person2);
console.log(name);
4、IIFE
? IIFE:Immediately Invoked Function Expression ,意为立即调用的函数表达式,也是说声明函数的同时立即调用这个函数。
? 作用:
? 1、页面加载完成后只执行一次的设置函数
? 2、将设置函数中的变量包裹在局部作用域中,不会泄露成全局变量
? IIFE的写法:
(function(形参){
函数体内容
})(实参);
? 基本用法:
var sum = (function (a,b) {
return a + b;
}(1,2))
console.log(sum);
5、作用域
函数作用域:在JavaScript函数中声明的变量,会成为函数的局部变量。函数内部声明的变量,在函数外部不能访问。
全局作用域:函数之外声明的变量,会成为全局变量,在函数内部可以访问
作用域最大的用处就是隔离变量,不同的作用域下的同名变量不会冲突
var v1 = 10;
v2 = 20;
function foo() {
var a = 3;
console.log(v1, v2);
console.log(this);
}
foo()
console.log(a);
作用域链
自由变量
在如下案例中,要输出a的变量,但是在当前作用域中没有定义a,则成为自由变量。
要得到自由变量的值就要到创建这个函数的父级作用域去找,如果没有就一直向上级祖先元素寻找(静态作用域)
var a = 100
function fn() {
var b = 200
console.log(a)
console.log(b)
}
fn()
在父级作用域也没有,就一层层向上寻找,直到找到全局作用域也没找到,就放弃,这种一层一层的关系,就是作用域链。
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a)
console.log(b)
console.log(c)
}
F2()
}
F1()
6、函数调用
? 函数声明好之后不会直接运行,需要进行调用才能运行
? 函数的调用方式不只有()执行,还有其他几种方式
? 1、函数名(实参列表);
? 2、函数名.call(执行环境对象,实参列表);
var obj = {
name: 'zhangsan',
sayName: function (a,b) {
console.log(this.name);
console.log(a,b);
}
}
var b = obj.sayName;
b.call(obj,1,2);
? 3、函数名.apply(执行环境对象,实参列表数组);
var obj = {
name: 'zhangsan',
sayName: function () {
console.log(this.name);
}
}
var b = obj.sayName;
b.apply(obj);
? 4、函数名.bind(执行环境对象)(实参列表);
var obj = {
name: 'zhangsan',
sayName: function () {
console.log(this.name);
}
}
var b = obj.sayName;
b.bind(obj);
var c = b.bind(obj);
console.log(c);
c();
总结:call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调用就什么时候调用,并且可以将参数在执行的时候添加,这就是它们的区别。
7、函数的应用
回调函数
回调函数就是回头调用的意思,主函数的事先做完,回头再调用传进来的那个函数
作用是一般都用在耗时操作上面,因为主函数不用等待回调函数执行完,可以接着执行自己的代码。
function A(callback) {
callback();
console.log('我是主函数');
}
function B() {
setTimeout(() => {
console.log('我是回调函数');
}, 3000);
}
A(B);
8、闭包
闭包是指有权访问另一函数作用域中的变量的函数。
闭包是一种特殊的对象,它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。
闭包的生成的三个必要条件:
? 1、函数嵌套函数
? 2、内部函数引用了外部函数中的数据(属性、函数)
? 3、参数和变量不会被回收
function func() {
var a = 1, b = 2;
function closure() {
return a + b;
}
return closure;
}
console.log(func()());
闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域。
闭包的作用:
? 1、可以读取函数的内部的变量
? 2、使得变量的值始终保持在内存中
|