第一章:函数的定义和调用
1.1 函数的定义方式
- ①函数声明方式:function关键字(命名函数)。
- ②函数表达式(匿名函数)。
- ③new Function()。
var fn = new Function('','',...,'函数体');
- Function里面参数都必须是字符串格式。
- 第三种执行效率低,不方便书写,较少使用(几乎不用)。
- 所有的函数都是Function的实例(对象)。
- 函数也属于对象。
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>函数的定义</title>
<script>
// 函数的定义方式
// 1. 自定义函数(命名函数)
function fn() {
console.log('自定义函数(命名函数)');
}
// 2. 函数表达式(匿名函数)
var fn2 = function () {
console.log('数表达式(匿名函数)');
}
// 3. 利用new Function('参数1','参数2',...,'函数体') 较少使用,效率低,书写不方便。
var fn3 = new Function('a', 'b', 'return a+b');
// 所有的函数都是Function的实例(对象)
console.dir(fn3);
// 函数也属于对象
console.log(fn3 instanceof Object);
</script>
</head>
<body>
</body>
</html>
1.2 函数的调用方式
- 普通函数。
- 对象的方法。
- 构造函数。
- 绑定事件函数。
- 定时器函数。
立即执行函数。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>函数的调用方式</title>
</head>
<body>
<button>点击</button>
<script>
/* 函数的调用方式 */
// 普通函数
function fn() {
console.log('我是普通函数');
}
fn();
fn.call();
// 对象的方法
var o = {
sing: function () {
console.log('我是对象的方法');
}
}
o.sing();
// 构造函数
function Star() {
}
new Star();
// 绑定事件函数
var btn = document.querySelector('button');
btn.onclick = function () {
console.log('我是绑定事件函数');
}
// 定时器函数
setTimeout(function () {
console.log('我是定时器函数');
}, 1000);
// 立即执行函数
(function () {
console.log('立即执行函数')
})();
</script>
</body>
</html>
第二章:this
2.1 函数内部this的指向
- this的指向,是当我们调用函数的时候才能确定的。调用方式的不同决定了this的指向不同。一般指向我们的调用者。 | 调用方式 | this指向 | | —- | —- | | 普通函数调用 | window | | 构造函数调用 | 实例对象,原型对象里面的方法也是指向实例对象 | | 对象方法调用 | 该方法所属对象 | | 事件绑定方法 | 绑定事件对象 | | 定时器函数 | window | | 立即执行函数 | window |
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>函数内部this的指向</title>
</head>
<body>
<button>点击</button>
<script>
// 普通函数 this指向window
function fn() {
console.log('我是普通函数');
}
window.fn();
// fn.call();
// 对象的方法 this指向的是对象 o
var o = {
sing: function () {
console.log('我是对象的方法');
}
}
o.sing();
// 构造函数 this指向ldh这个实例对象,原型对象里面的this也是指的ldh这个实例对象
function Star() {
}
Star.prototype.sing = function () {
}
var ldh = new Star();
// 绑定事件函数 this指向的是函数的调用者,btn这个按钮对象
var btn = document.querySelector('button');
btn.onclick = function () {
console.log('我是绑定事件函数');
}
// 定时器函数 this指的是window
setTimeout(function () {
console.log('我是定时器函数');
}, 1000);
// 立即执行函数 this指的是window
(function () {
console.log('立即执行函数')
})();
</script>
</body>
</html>
2.2 改变函数内部this的指向
2.2.1 概述
- JavaScript为我们专门提供了一些函数方法帮我们更优雅的处理函数内部this的执行问题,常用的有
bind()
、call()
和apply()
三种方法。
2.2.2 call()方法
- 语法:
fun.call(thisArg,arg1,arg2,...)
- call()方法调用一个对象。简单理解为调用函数的同时并可以改变函数的this指向。
- thisArg:在fun函数运行时指定的this的值。
- arg1,arg2:传递的其他参数。
- 返回值就是函数的返回值,因为它就是调用函数。
因此,当我们想改变this的执行,同时想调用这个函数的时候,可以使用call(),比如继承。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>改变函数内部this的指向之call方法</title>
</head>
<body>
<script>
// 改变函数内部的this指向,js提供了call()、apply()和bind()方法
var o = {
name: '许大仙'
}
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn.call(o, 1, 2);
// call可以调用函数,并可以改变函数内的this指向。
// call的主要作用可以实现继承
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
function Son(uname, age) {
/*
* 原来Father构造函数的this指向的是其实例化的对象,Son构造函数的this也是指向其实例化的对象。
* 当使用下面的代码的时候,就是将Father构造函数的this指向Son构造函数的实例化对象,那么Son构造函数就不需要再写this.uname=uname,...
*/
Father.call(this, uname, age);
}
var son = new Son('许大仙', 18);
console.log(son);
</script>
</body>
</html>
2.2.3 apply()方法
- 语法:
fun.apply(thisArg,[argsArray])
- apply()方法调用一个函数。简单理解为调用函数的同时并可以改变函数的this指向。
- thisArg:在fun函数运行的时候指定的this的值。
- argsArray:传递的值,必须包含在
数组
中。 - 返回值就是函数的返回值,因为它就是调用函数。
因此apply主要和数组有关,比如使用Math.max()求数组的最大值。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>改变函数内部this的指向之apply方法</title>
</head>
<body>
<script>
// 改变函数内部的this指向,js提供了call()、apply()和bind()方法
var o = {
name: '许大仙'
}
function fn(a, b) {
console.log(this);
console.log(a);
console.log(b);
}
fn.apply(o, ['pink', 'red']);
// apply可以调用函数,并可以改变函数内的this指向。
// apply的参数必须是数组(伪数组)。
// apply 的主要应用 比如:我们可以利用apply借助于数学内置对象求最大值
// Math.max()
var arr = [1, 2, 3, 4, 5, 6];
var max = Math.max.apply(Math, arr);
console.log(max);
</script>
</body>
</html>
2.2.4 bind()方法
- 语法:
fun.bind(thisArg,arg1,arg2,...)
- bind()方法不会调用函数,但是能改变函数内部this指向。
- thisArg:在fun函数运行时指定的this的值。
- arg1,arg2:传递的其他参数,
- 返回由指定的this值和初始化参数改造的
原函数拷贝
。 当我们只想改变this指向,并且不想调用这个函数的时候,可以使用bind。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>改变函数内部this的指向之bind方法</title>
</head>
<body>
<button>按钮</button>
<script>
// 改变函数内部的this指向,js提供了call()、apply()和bind()方法
// bind()方法不会调用函数,但是能改变函数内部this指向。
var o = {
name: '许大仙'
}
function fn() {
console.log(this);
}
var f = fn.bind(o);
f();
// 不会调用原来的函数,可以改变原来函数内部的this指向
// 返回的是原函数改变this产生之后的新函数
// 如果有的函数,我们不需要立即调用,又想改变这个函数内部的this指向,此时用bind方法最合适。
//有一个按钮,当我们点击之后,就禁用这个按钮,3秒钟之后开启这个按钮
var btn = document.querySelector('button');
btn.onclick = function () {
this.disabled = true; //指向的是btn这个按钮
var num = 3;
var timer = setInterval(function () {
if (num == 0) {
clearInterval(timer);
this.disabled = false;
} else {
num--;
}
console.log(num)
}.bind(this), 1000);
}
</script>
</body>
</html>
2.2.5 call()、apply()、bind()总结
- 相同点:都可以改变函数内部的this指向。
- 区别点:
- call和apply会调用函数,并且会改变函数内部的this指向。
- call和apply传递的参数不一样,call传递的参数是arg1,arg2,…,apply传递的参数是数组形式[args]。
- bind不会调用函数,只会改变函数内部的this指向。
- 主要应用场景:
- call经常用来做继承。
- apply经常和数组有关。比如:借助于数学对象Math实现数组的最大值和最小值。
- bind不调用函数,但是可以改变this指向。比如:改变定时器内部的this指向。
第三章:严格模式
3.1 什么是严格模式
- JavaScript除了提供正常模式外,还提供了
严格模式(strict mode)
。ES5的严格模式是采用具有限制性JavaScript变体的一种方式,即在严格的条件下运行JS代码。 - 严格模式在IE10以上版本的浏览器中才会被支持,旧版本的浏览器中将被忽略。
- 严格模式对正常的JavaScript语义做了一些更改:
- 消除了JavaScript语法的一些不合理、不严谨之处,减少了一些怪异行为。
- 消除代码运行的一些不安全之处,保证代码运行的安全。
- 提高编译效率,增加运行速度。
- 禁用了在ECMAScript在未来版本中可能会定义的一些语法,为未来新版本的JavaScript做好铺垫。比如:一些保留字如:class、enum、export、extends、import、super不能做变量名。
3.2 开启严格模式
- 严格模式可以应用到
整个脚本
或个别函数
中,因此在使用的时候,我们可以将严格模式分为为脚本开启严格模式
或为函数开启严格模式
两种情况。 为脚本开启严格模式:
为整个脚本开启严格模式,需要
在所有语句之前放一个特殊语句“use strict;”(或‘use strict;’)
。<script> "use strict"; console.log("这是严格模式。"); </script>
因为
"use strict"
加了引号,所以老版本的浏览器会将它当做一行普通的字符串而忽略。- 有的script脚本是严格模式,有的script脚本是正常模式,这样不利于文件的合并,所以可以将整个脚本文件放在一个立即执行的匿名函数之中,这样独立创建一个作用域而不影响其他script脚本文件。
<script> (function (){ "use strict"; var num = 10; function fn() {} })(); </script>
为函数开启严格模式:
要给某个函数开启严格模式,需要
将“use strict;”(或‘use strict;’)声明放在函数体所有语句之前
。function fn(){ "use strict"; return "这是严格模式。"; }
将
"use strict"
放到函数体的第一行,则整个函数以“严格模式
”运行。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>开启严格模式</title>
</head>
<body>
<script>
/* 开启严格模式,下面的JS代码就会按照严格模式执行 */
"use strict";
a = 100; // 在严格模式下会报错
console.log('这是严格模式');
</script>
<script>
(function () {
//在立即执行函数中开启严格模式
"use strict";
})()
</script>
<script>
function fn() {
//在函数中开启要严格模式
"use strict";
console.log('这是严格模式');
}
</script>
</body>
</html>
3.3 严格模式的变化
3.3.1 变量规定
- ①在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种写法,变量必须先用var声明,然后再使用。
②严禁删除已经声明的变量。比如:delete x;语法是错误的。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>严格模式的变化之变量规定</title>
</head>
<body>
<script>
"use strict";
/* 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种写法,变量必须先用var声明,然后再使用。 */
// a = 100;
// console.log(a);
/* 严禁删除已经声明的变量。比如:delete x;语法是错误的。 */
// var a = 100;
// delete a;
</script>
</body>
</html>
3.3.2 this指向问题
- ①以前在正常模式中全局作用函数中的this指向的是window对象;
严格模式下全局作用域中函数中的this是undefined
。 - ②以前在正常模式中构造函数不加new也是可以调用的,当做普通函数,this指向全局对象;
严格模式下,如果构造函数不加new调用,this指向的是undefined,如果给其赋值,则会报错。
- ③正常模式和严格模式下,构造函数如果使用new调用,则this指向创建的对象实例。
- ④正常模式和严格模型下的定时器的this都是指向window。
⑤正常模式和严格模式下的事件、对象还是指向调用者。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>严格模式的变化之this指向问题</title>
</head>
<body>
<script>
"use strict";
/* 以前在正常模式中全局作用函数中的this指向的是window对象,严格模式下全局作用域中函数中的this是undefined。 */
/*
function fn() {
console.log(this);
}
fn(); //undefined
*/
/* 以前在正常模式中构造函数不加new也是可以调用的,当做普通函数,this指向全局对象;严格模式下,如果构造函数不加new调用,this指向的是undefined,如果给其赋值,则会报错。 */
/*
function Star() {
this.sex = '男';
console.log(this);
}
Star();
*/
/* 正常模式和严格模式下,构造函数如果使用new调用,则this指向创建的对象实例。 */
function Star() {
this.sex = '男';
console.log(this);
}
var str = new Star();
</script>
</body>
</html>
3.3.3 函数变化
- ①严格模式下,函数不能有重名的参数。
②严格模式下,函数必须声明在顶层,新版本的JavaScript会引入“块级作用域”(ES6中已经引入)。为了和新版本接轨,不允许在非函数的代码块内声明函数。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>严格模式的变化之函数变化</title>
</head>
<body>
<script>
"use strict";
/* ①严格模式下,函数不能有重名的参数。 */
/*
以下函数会报错。
function fn(a, a) {
}
*/
/* ②严格模式下,函数必须声明在顶层,新版本的JavaScript会引入“块级作用域”(ES6中已经引入)。为了和新版本接轨,不允许在非函数的代码块内声明函数。 */
/*
以下函数会报错。
if (true) {
function f() {
}
f();
}
for (let i = 0; i <5 ; i++) {
function f() {
}
f();
}
*/
</script>
</body>
</html>
第四章:高阶函数
高阶函数
是对其他函数进行操作的函数,它接受函数作为参数
或将函数作为返回值输出
。- 函数也是一种数据类型,同样可以作为参数,传递给另一个参数使用。最典型的就是回调函数。
同理,函数也可以作为返回值传递回来。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>高阶函数</title>
</head>
<body>
<script>
/* 高阶函数:接受函数作为函数或将函数作为返回值输出 */
/* 接受函数作为函数 */
function fn(callback) {
callback && callback();
}
fn(function () {
alert('你大爷的');
});
/* 将函数作为返回值输出 */
function fn2() {
return function () {
alert('呵呵');
}
}
fn2();
</script>
</body>
</html>
第五章:闭包
5.1 变量作用域
- 变量根据作用域不同分为两种:全局变量和局部变量。
- ①函数内部可以使用全局变量。
- ②函数外部不可以使用局部变量。
- ③当函数执行完毕,本作用域内的局部变量就被销毁。
5.2 闭包
闭包(closure)
是指有权访问
另一个函数作用域中变量
的函数
。简单理解就是,一个作用域可以访问另外一个函数内部的局部变量,这个局部变量所在的函数就称为闭包函数。示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>闭包</title>
</head>
<body>
<script>
//闭包是指有权访问另一个函数作用域中变量的函数。
//闭包:fn2这个函数作用域访问了另一个函数fn里面的局部变量num,那么fn就称为闭包函数。
function fn() {
var num = 10;
function fn2() {
console.log(num); // 10
}
fn2();
}
fn();
</script>
</body>
</html>
5.3 闭包的作用
闭包的作用:延伸了变量的作用范围。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>闭包的作用</title>
</head>
<body>
<script>
//闭包是指有权访问另一个函数作用域中变量的函数。
//闭包:fn2这个函数作用域访问了另一个函数fn里面的局部变量num,那么fn就称为闭包函数。
//fn外面的作用域可以访问fn内部的局部变量。
//闭包的主要作用:延伸了变量的作用范围。
function fn() {
var num = 10;
// function fn2() {
// console.log(num); // 10
// }
//
// return fn2;
return function () {
console.log(num);
}
}
var f = fn();
f();
/*
* 类似于
* var f = function fn2(){
* console.log(num);
* }
*/
</script>
</body>
</html>
5.4 闭包案例
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>闭包应用之循环注册点击事件</title>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>鲱鱼罐头</li>
<li>大猪蹄子</li>
</ul>
<script>
//点击li输出当前li的索引号
//1. 利用动态添加属性的方式
var lis = document.querySelector('.nav').querySelectorAll('li');
/*lis.forEach(function (value, index) {
value.setAttribute('data-index', index);
value.onclick = function () {
var index = this.getAttribute('data-index');
console.log(index);
}
})*/
//2. 利用闭包的方式得到当前小li的索引号
lis.forEach(function (value, index) {
//利用for循环创建了4个立即执行函数
//立即执行函数也称为小闭包,因为立即函数里面的任何一个函数都使用使用index变量。
(function (index) {
value.onclick = function () {
console.log(index);
}
})(index);
})
</script>
</body>
</html>
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>闭包应用之定时器中的闭包</title>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>鲱鱼罐头</li>
<li>大猪蹄子</li>
</ul>
<script>
// 3秒后,打印所有的li元素的内容
var lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function (i) {
setTimeout(function () {
console.log(lis[i].innerHTML);
}, 3000);
})(i);
}
</script>
</body>
</html>
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>闭包应用之打车价格</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 = (n - 3) * 5 + start;
}
return total;
},
//拥堵之后的费用
yd: function (flag) {
return flag ? total += 10 : total;
}
}
})();
var total = car.price(1);
console.log(total);
total = car.yd(true);
console.log(total);
</script>
</body>
</html>
第六章:递归
6.1 什么是递归?
- 如果
一个函数在内部可以调用其本身
,那么这个函数就是递归函数
。简单理解,函数内部自己调用自己,这个函数就是递归函数。 - 递归函数的作用和循环效果一样。
由于递归很容易发生(栈溢出)错误,所以
必须加退出条件return
。示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>什么是递归函数</title>
</head>
<body>
<script>
// 递归函数:函数内部自己调用自己,这个函数就是递归函数
var num = 1;
function fn() {
console.log('我要打印6句话')
if (num == 6) {
return; //递归里面必须加退出条件
}
num++;
fn();
}
fn();
</script>
</body>
</html>
6.2 递归案例
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>利用递归求阶乘</title>
</head>
<body>
<script>
/* 求 1 * 2 *3 ... * n 阶乘 */
function fn(n) {
if (n == 1) {
return 1;
}
return n * fn(n - 1);
}
var num = fn(3);
console.log(num);
</script>
</body>
</html>
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>利用递归求斐波那契数列</title>
</head>
<body>
<script>
/* 利用递归函数求斐波拉契数列(兔子序列)1 1 2 3 5 8 13 21 */
/* 用户输入一个数字n,就可以求出这个数字对应的兔子序列了。 */
/* 我们只需要知道用户输入的n的前面两项(n-1)和 (n-2)就可以计算出n对应的序列值 */
function fn(n) {
if (n == 1 || n == 2) {
return 1;
}
return fn(n - 1) + fn(n - 2);
}
console.log(fn(4));;
</script>
</body>
</html>
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>利用递归遍历数据</title>
</head>
<body>
<script>
var data = [{
id: 1,
name: '家电',
goods: [{
id: 11,
name: '冰箱'
}, {
id: 12,
name: '洗衣机'
}]
}, {
id: 2,
name: '服饰'
}]
/* 输入id号,就可以返回对应的数据对象 */
function fn(id, data) {
var o = null;
data.forEach(function (item, index) {
if (item.id == id) {
o = item;
} else if (item.goods && item.goods.length != 0) { //如果里层有goods数组,并且数组的长度不为0
o = fn(id, item.goods);
}
});
return o;
}
console.log(fn(1, data));;
console.log(fn(2, data));;
console.log(fn(11, data));
console.log(fn(12, data));
console.log(fn(13, data));
</script>
</body>
</html>
6.3 深拷贝和浅拷贝
- 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
深拷贝拷贝多层,每一级别的数据都会拷贝。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>深拷贝和浅拷贝</title>
</head>
<body>
<script>
/*
* 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
*/
var obj = {
id: 1,
name: '许大仙',
msg: {
age: 18
},
color: ['red', 'green', 'blue']
}
var o = {}
for (var key in obj) {
o[key] = obj[key];
}
console.log(o);
o.msg.age = 20;
console.log(obj.msg.age); //20
/*
ES6新增方法:进行浅拷贝 Object.assign(target, ...sources)
*/
var o1 = {};
Object.assign(o1, obj);
console.log(o1);
/*
* 深拷贝拷贝多层,每一级别的数据都会拷贝。
*/
var o2 = {}
function deepCopy(newObj, oldObj) {
for (var key in oldObj) {
//判断数据类型是否是简单类型还是复杂类型
//1. 获取属性值
var item = oldObj[key];
//2. 判断属性值是否是数组
if (item instanceof Array) {
newObj[key] = [];
deepCopy(newObj[key], item);
} else if (item instanceof Object) { //3. 判断属性值是否是对象
newObj[key] = {};
deepCopy(newObj[key], item);
} else { //4. 属于简单数据类型
newObj[key] = item;
}
}
}
deepCopy(o2, obj);
console.log(o2);
</script>
</body>
</html>