JavaScript函数进阶、严格模式、闭包、递归
1. 函数的定义和调用
<script>
//定义函数三种方法
//1 函数声明方式 function 关键字
function fn(){}
//2 函数表达式(匿名函数)
var fn1 = function(){}
//3 new关键字
new Function('参数1','参数2','函数体');
//参数必须为字符串形式
var fn2 = new Function('a','b','console.log(a+b)');
//第三种方式执行效率低,也不方便书写,因此较少使用
//所有函数都是 Function 的实例(对象)
//函数也属于对象
</script>
2. this指向、改变this指向
函数内部的this指向
改变函数内部的this指向
call()方法
call()方法一般用于继承
<script>
var o = {
name:'hjc'
}
function Person(name){
console.log(this);
this.name = name;
}
Person('lwq'); //指向window
Person.call(o,'lwq'); //指向o对象
</script>
apply()方法
apply()方法一般用于跟数组有关系. 比如借助于数学对象实现数组最大值最小值
<script>
//1.理解代码
var o = {
name:'hjc'
}
function fn(a,b){
console.log(this);
console.log(a+b);
}
//参数必须以数组的方式
fn.apply(o,[1,2]);
//2.实际demo
var arr = [1,2,3,4,5,7];
var max = Math.max.apply(Math,arr); //返回数组中最大值
var min = Math.min.apply(Math,arr); //返回数组中最小值
console.log(max,min);
</script>
bind()方法
不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向.
<script>
var hjc = {
name:'hjc'
}
function sum(a,b,c){
console.log(this);
console.log(a+b+c);
}
// bind只会绑定,不会执行,需要调用执行
var obj = sum.bind(hjc,1,2,3);
obj();
</script>
bind方法的实际小demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
<script>
var btns = document.querySelectorAll('button');
for(var i=0;i<btns.length;i++){
btns[i].onclick = function(){
console.log(this);
this.disabled = true;
setTimeout(function(){
// console.log(this); bing绑定的this是指向当前点击按钮 不绑定的话 this指向的是window
this.disabled = false;
}.bind(this),2000);
}
}
console.log(btns);
</script>
</body>
</html>
3. 严格模式
关键词 use strict
3.1 开启严格模式
<script>
//1.在子调用函数下开启严格模式
(function(){
'use strict';
var num = 10; //严格模式下 没有声明的变量会报错
console.log(num);
})();
//2.为函数开启严格模式
function fn1(){
//未开启严格模式
}
function fn2(){
'use strict';
//本函数内部开启严格模式
}
</script>
<script>
//3.在这个script标签中,开启严格模式
'use strict';
</script>
3.2 严格模式下的变化
<script>
'use strict'
num = 10
console.log(num)//严格模式后使用未声明的变量
--------------------------------------------------------------------------------
var num2 = 1;
delete num2;//严格模式不允许删除变量
--------------------------------------------------------------------------------
function fn() {
console.log(this); // 严格模式下全局作用域中函数中的 this 是 undefined
}
fn();
---------------------------------------------------------------------------------
function Star() {
this.sex = '男';
}
// Star();严格模式下,如果 构造函数不加new调用, this 指向的是undefined 如果给他赋值则 会报错.
var ldh = new Star();
console.log(ldh.sex);
----------------------------------------------------------------------------------
setTimeout(function() {
console.log(this); //严格模式下,定时器 this 还是指向 window
}, 2000);
</script>
4. 高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出
<script>
//1.将函数作为参数
function move(a,b,callback){
console.log(a+b);
callback&&callback(); //回调函数:执行完这个函数,再调用这个函数
}
move(1,2,function(){
console.log('我执行完了');
})
//2.将函数作为返回值
function fn(a){
var num = a;
//在函数内部调用另外一个函数,也属于闭包
function fn1(){
console.log(num);
}
fn1();
}
fn(5); //输出5
</script>
5. 闭包
5.1 什么是闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量
<script>
function fn(a){
var num = a;
//在函数内部调用另外一个函数,也属于闭包
function fn1(){
console.log(num);
}
fn1();
}
fn(5); //输出5
</script>
5.2 闭包的作用
延伸变量的作用范围
<script>
function fn() {
var num = 10;
function fun() {
console.log(num);
}
return fun;
}
var f = fn();
f();
</script>
5.3 demo案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>demo3</title>
</head>
<body>
<ul>
<li>窗前明月光</li>
<li>疑是地上霜</li>
<li>举头望明月</li>
<li>低头思故乡</li>
</ul>
<script>
//获取点击当前li的索引号
var lis = document.querySelectorAll('li');
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick = function(){
console.log(i);
}
})(i)
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>demo3</title>
</head>
<body>
<ul>
<li>窗前明月光</li>
<li>疑是地上霜</li>
<li>举头望明月</li>
<li>低头思故乡</li>
</ul>
<script>
//2秒后打印点击当前li的内容
var lis = document.querySelectorAll('li');
for(var i=0;i<lis.length;i++){
(function(i){
lis[i].onclick = function(){
setTimeout(function(){
console.log(lis[i].innerHTML);
},2000);
}
})(i);
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>demo4</title>
</head>
<body>
<script>
/*需求分析
打车起步价13(3公里内), 之后每多一公里增加 5块钱. 用户输入公里数就可以计算打车价格
如果有拥堵情况,总价格多收取10块钱拥堵费*/
var car = (function(){
var start = 13; //起步价
var total = 0; //总价
return {
price : function(n){
if(n<=3){
total = start;
}else{
total = start + (n-3) * 5;
}
return total;
},
yongdu : function(flag){
if(flag){
total +=10;
}
return total;
}
}
})();
console.log(car.price(5));
console.log(car.yongdu(true));
</script>
</body>
</html>
6.递归
在一个函数内部调用其本身,这个函数叫递归函数
6.1用递归做1-n的阶乘
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>阶乘</title>
</head>
<body>
<script>
function fn(n){
if(n==1){
return 1;
}
console.log(fn.prototype);
return n * fn(n-1);
}
console.log(fn(3));
</script>
</body>
</html>
6.2 利用递归遍历数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>demo7</title>
</head>
<body>
<script>
var data = [{
id: 1,
name: '家电',
goods: [{
id: 11,
gname: '冰箱',
goods: [{
id: 111,
gname: '海尔'
}, {
id: 112,
gname: '美的'
},
]
}, {
id: 12,
gname: '洗衣机'
}]
}, {
id: 2,
name: '服饰'
}];
function getData(data,id){
var o = {};
data.forEach(function(item){
// console.log(item.goods);
if(item.id === id){
o = item;
return o;
}
else if(item.goods && item.goods.length >0){
o = getData(item.goods,id);
}
});
return o;
}
console.log(getData(data,11));
</script>
</body>
</html>