函数进阶及闭包
一、函数进阶
让我们先回忆下函数是怎样定义的?
1.1、函数的定义
- 方式一 关键字定义
function fn(){
//代码块
}
- 方式二 匿名函数法
var fn = function(){
//代码块
}
- 方式三 构造函数法
var f = new Function('a', 'b', 'console.log(a + b)');
// 'a','b',为形参,console.log(a + b)为函数体
// 这里Function中,F是大写的
f(1, 2);
- 注意
(1)Function 里面参数都必须是字符串格式;
(2)构造函数法执行效率低,也不方便书写,因此较少使用;
(3)所有函数都是 Function 的实例(对象);
(4)函数也属于对象。
1.2、函数的调用
- 普通函数调用
function fn() {
console.log('lll');
}
//调用
fn();
- 对象的方式
var o = {
sayHi: function() {
console.log('111');
}
}
//调用
o.sayHi()
- 构造函数式
function Star() {
};
//调用
new Star();
- 绑定事件函数的三种调用方式
// 点击按钮就可以调用这个函数
btn.onclick = function() {};
// 点击了按钮就可以调用这个函数
function add() {};
btn.onclick = add;
// 点击了按钮就可以调用这个函数
var add = function(){}
btn.onclick = add;
1.3、立即调用函数
- 概念
立即调用函数(自调用函数),IIFE,是一个定义的同时执行的函数。
// 基本形式
(function() {
console.log('111');
})();
- 立即执行函数获取外部变量
var x= 10
(function(a) {
console.log(a++);
})(x);// 内部获取x的值
- 立即调用函数的局部作用域问题
(function () {
var name = "Barry";
})(); // 此时,无法从外部访问变量 name
- 实例
for (var i = 1; i < 5; i++) {
setTimeout(function () {
console.log(i++);;
}, 200)
}
// 由于setTimeout是异步代码,所以先执行for循环,
// 然后进入异步代码内部执行
console.log(i); //5
console.log('over'); // over 5 6 7 8
二、this
2.1、this指向性问题
调用方式 | this指向 |
---|---|
普通调用函数 | window |
构造函数调用 | 实例对象 |
对象方法调用 | 所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即调用函数 | window |
2.2、改变函数内部this指向
正常情况下:
// 函数内部this指向window
function fn(a,b){
console.log(this); //window
console.log(a/b); //2
}
fn(10,5);
那如果想要改变this的指向呢?
以下介绍几种方法!
- call()
function fn(a,b){
console.log(this.sex); //女
console.log(a/b); //2
}
var obj = {
sex:'女'
}
call()
// 此时.this的指向已经改变
fn.call(obj,10,5)
- apply()
apply()
// 注意,这里参数用数组包起来
fn.apply(obj,[10,5])
- bind()
// bind()方法并不会立即执行函数,而是先返回一个函数对象
var t = fn.bind(obj,10,5);
t()
三、闭包
在这之前,我们先了解下什么是高阶函数?
3.1、高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
function fn(){
return function(){};
}
// 把函数作为返回值
fn(); //此时,fn()结果为function(){};
3.2、闭包
通俗来讲,就是在一个函数内部再定义一个函数,内部函数使用到外部函数的局部变量,并且外部函数返回值是内部函数。
是不是有点蒙,其实就是满足三个条件:
(1)函数内部嵌套函数;
(2)内部函数用到外部函数的变量;
(3)外部函数返回值为内部函数。
// 闭包
function out1(){
var a = 111;
function in2(){
return a;
}
return in2;
}
var f1 = out1(); //f1等于in2()
var f2 = f1() //f2 等于in2的返回值 即a
我们知道,正常情况下在全局作用域下是无法访问局部变量的,闭包却可以解决这种境况。
3.3、闭包的作用
function Foo() {
var i = 0;
return function () {
console.log(i++);
}
}
var f1 = Foo();
f1();//0
f1();//1
f1();//2
f1();//3
就是可以在全局位置访问到局部的变量
3.4、用闭包解决选项卡问题
// 闭包实现选项卡功能
var oBut = document.querySelectorAll('button');
var oDiv = document.querySelectorAll('div');
for (var i = 0; i < oBut.length; i++) {
(function (n) {
oBut[n].onclick = function () {
for(var j=0;j<oDiv.length;j++){
oBut[j].className = '';
oDiv[j].className = '';
}
oBut[n].className = 'b1';
oDiv[n].className = 'd1';
}
})(i)//将i传递给内部事件函数,保存i的值
}
3.5、闭包实现点击按钮自加1
// 点击按钮自加1
var oBut = document.querySelector('button');
oBut.onclick = function(){
f();
}
function f1(){
var i =0;
return function(){
console.log(i++);
}
}
var f = f1()