From 600c413e6d2c65fa620686debc522ea92b16419a Mon Sep 17 00:00:00 2001 From: qianguyihao Date: Sat, 4 Jul 2020 20:37:20 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E6=B5=85=E6=8B=B7=E8=B4=9D=E5=92=8C?= =?UTF-8?q?=E6=B7=B1=E6=8B=B7=E8=B4=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 04-JavaScript基础/23-高阶函数.md | 52 ++++++ 04-JavaScript基础/{23-闭包.md => 24-闭包.md} | 17 +- .../{24-面向对象概述.md => 25-面向对象概述.md} | 0 ...创建&构造函数.md => 26-对象的创建&构造函数.md} | 0 ...6-对象的基本操作.md => 27-对象的基本操作.md} | 0 04-JavaScript基础/28-浅拷贝和深拷贝.md | 161 ++++++++++++++++++ ...操作:Object.assign().md => 29-对象的高级操作.md} | 10 -- ...型链和原型继承.md => 30-原型链和原型继承.md} | 0 .../{29-类和构造继承.md => 31-类和构造继承.md} | 0 9 files changed, 229 insertions(+), 11 deletions(-) create mode 100644 04-JavaScript基础/23-高阶函数.md rename 04-JavaScript基础/{23-闭包.md => 24-闭包.md} (91%) rename 04-JavaScript基础/{24-面向对象概述.md => 25-面向对象概述.md} (100%) rename 04-JavaScript基础/{25-对象的创建&构造函数.md => 26-对象的创建&构造函数.md} (100%) rename 04-JavaScript基础/{26-对象的基本操作.md => 27-对象的基本操作.md} (100%) create mode 100644 04-JavaScript基础/28-浅拷贝和深拷贝.md rename 04-JavaScript基础/{27-对象的高级操作:Object.assign().md => 29-对象的高级操作.md} (77%) rename 04-JavaScript基础/{28-原型链和原型继承.md => 30-原型链和原型继承.md} (100%) rename 04-JavaScript基础/{29-类和构造继承.md => 31-类和构造继承.md} (100%) diff --git a/04-JavaScript基础/23-高阶函数.md b/04-JavaScript基础/23-高阶函数.md new file mode 100644 index 0000000..469cf2e --- /dev/null +++ b/04-JavaScript基础/23-高阶函数.md @@ -0,0 +1,52 @@ +## 高阶函数 + +### 高阶函数的概念 + +当 函数 A 接收函数 B 作为**参数**,或者把函数 C 作为**返回值**输出时,我们称 函数 A 为高阶函数。 + +通俗来说,高阶函数是 对其他函数进行操作 的函数。 + + +### 高阶函数举例1:把其他函数作为参数 + +```js +function fn1(a, b, callback) { + console.log(a + b); + // 执行完上面的 console.log() 语句之后,再执行下面这个 callback 函数。也就是说,这个 callback 函数是最后执行的。 + callback && callback(); +} + +fn1(10, 20, function () { + console.log('我是最后执行的函数'); +}); + +``` + + +打印结果: + +``` +30 +我是最后执行的函数 +``` + + +### 高阶函数举例2:把其他区函数作为返回值 + + + +```js +function fn1() { + let a = 20; + + return function () { + console.log(a); + }; +} + +const foo = fn1(); // 执行 fn1() 之后,会得到一个返回值。这个返回值是函数 +foo(); +``` + + +上面的代码,产生了闭包现象。关于闭包,详见下一篇文章《JavaScript基础/闭包.md》。 diff --git a/04-JavaScript基础/23-闭包.md b/04-JavaScript基础/24-闭包.md similarity index 91% rename from 04-JavaScript基础/23-闭包.md rename to 04-JavaScript基础/24-闭包.md index 2da1999..10c0219 100644 --- a/04-JavaScript基础/23-闭包.md +++ b/04-JavaScript基础/24-闭包.md @@ -31,7 +31,7 @@ console.log(a); // 打印报错:Uncaught ReferenceError: a is not defined 上面这个概念,出自《JavaScript 高级程序设计(第 3 版)》这本书。上面的概念中指出,闭包是一种函数;当然,你可以**把闭包理解成是一种现象**。具体解释如下。 -简单理解就是:如果这个作用域可以**访问另外一个函数内部的局部变量**,那就产生了闭包(此时,你可以把闭包理解成是一种现象);而另外那个作用域所在的函数称之为**闭包函数**。注意,这里强调的是访问**局部变量**哦。 +简单理解就是:如果**这个作用域可以访问另外一个函数内部的局部变量**,那就产生了闭包(此时,你可以把闭包理解成是一种现象);而另外那个作用域所在的函数称之为**闭包函数**。注意,这里强调的是访问**局部变量**哦。 ### 闭包代码举例 @@ -92,6 +92,21 @@ foo(); 因此,我们可以看出,闭包的主要作用就是:延伸了变量的作用范围。 +上面的代码也可以简写成: + +```js +function fn1() { + let a = 20; + + return function () { + console.log(a); + }; +} + +const foo = fn1(); // 执行 fn1() 之后,会得到一个返回值。这个返回值是函数 +foo(); +``` + ## 我的公众号 diff --git a/04-JavaScript基础/24-面向对象概述.md b/04-JavaScript基础/25-面向对象概述.md similarity index 100% rename from 04-JavaScript基础/24-面向对象概述.md rename to 04-JavaScript基础/25-面向对象概述.md diff --git a/04-JavaScript基础/25-对象的创建&构造函数.md b/04-JavaScript基础/26-对象的创建&构造函数.md similarity index 100% rename from 04-JavaScript基础/25-对象的创建&构造函数.md rename to 04-JavaScript基础/26-对象的创建&构造函数.md diff --git a/04-JavaScript基础/26-对象的基本操作.md b/04-JavaScript基础/27-对象的基本操作.md similarity index 100% rename from 04-JavaScript基础/26-对象的基本操作.md rename to 04-JavaScript基础/27-对象的基本操作.md diff --git a/04-JavaScript基础/28-浅拷贝和深拷贝.md b/04-JavaScript基础/28-浅拷贝和深拷贝.md new file mode 100644 index 0000000..6504c53 --- /dev/null +++ b/04-JavaScript基础/28-浅拷贝和深拷贝.md @@ -0,0 +1,161 @@ +## 概念 + +- 浅拷贝:只拷贝最外面一层的数据;更深层次的对象,只拷贝引用。 + +- 深拷贝:拷贝多层数据;每一层级别的数据都会拷贝。 + +**总结**: + +拷贝引用的时候,是属于**传址**,而非**传值**。关于传值和传址的区别,是很基础的内容,详见《JavaScript 基础/对象简介.md》这篇文章。 + +深拷贝会把对象里**所有的数据**重新复制到新的内存空间,是最彻底的拷贝。 + +## 浅拷贝的实现方式 + +### 用 for in 实现浅拷贝(比较繁琐) + +```js +const obj1 = { + name: 'qianguyihao', + age: 28, + info: { + desc: '很厉害', + }, +}; + +const obj2 = {}; +// 用 for in 将 obj1 的值拷贝给 obj2 +for (let key in obj1) { + obj2[key] = obj1[key]; +} + +console.log('obj2:' + JSON.stringify(obj2)); + +obj1.info.desc = '永不止步'; // 当修改 obj1 的第二层数据时,obj2的值也会被改变。所以 for in 是浅拷贝 + +console.log('obj2:' + JSON.stringify(obj2)); +``` + +上方代码中,用 for in 做拷贝时,只能做到浅拷贝。也就是说,在 obj2 中, name 和 age 这两个属性会单独存放在新的内存地址中,和 obj1 没有关系。但是,`obj2.info` 属性,跟 `obj1.info`属性,**它俩指向的是同一个堆内存地址**。所以,当我修改 `obj1.info` 里的值之后,`obj2.info`的值也会被修改。 + +打印结果如下: + +``` +obj2:{"name":"qianguyihao","age":28,"info":{"desc":"很厉害"}} + +obj2:{"name":"qianguyihao","age":28,"info":{"desc":"永不止步"}} +``` + +### 用 Object.assgin() 实现浅拷贝(推荐的方式) + +上面的 for in 方法做浅拷贝过于繁琐。ES6 给我们提供了新的语法糖,通过 `Object.assgin()` 可以实现**浅拷贝**。 + +`Object.assgin()` 在日常开发中,使用得相当频繁,非掌握不可。 + +**语法**: + +```js +newObj = Object.assgin(newObj, 被拷贝的对象); +``` + +参数解释:`newObj`指的是**拷贝给谁**。 + +**例 1**: + +```js +const obj1 = { + name: 'qianguyihao', + age: 28, + info: { + desc: 'hello', + }, +}; + +// 浅拷贝:把 obj1 拷贝给 obj2。如果 obj1 只有一层数据,那么,obj1 和 obj2 则互不影响 +const obj2 = Object.assign({}, obj1); +console.log('obj2:' + JSON.stringify(obj2)); + +obj1.info.desc = '永不止步'; // 由于 Object.assign() 只是浅拷贝,所以当修改 obj1 的第二层数据时,obj2 对应的值也会被改变。 +console.log('obj2:' + JSON.stringify(obj2)); +``` + +代码解释:由于 Object.assign() 只是浅拷贝,所以在当前这个案例中, obj2 中的 name 属性和 age 属性是单独存放在新的堆内存地址中的,和 obj1 没有关系;但是,`obj2.info` 属性,跟 `obj1.info`属性,**它俩指向的是同一个堆内存地址**。所以,当我修改 `obj1.info` 里的值之后,`obj2.info`的值也会被修改。 + +打印结果: + +``` +obj2:{"name":"qianguyihao","age":28,"info":{"desc":"hello"}} + +obj2:{"name":"qianguyihao","age":28,"info":{"desc":"永不止步"}} +``` + +**例 2**:(和上面的例 1 等价) + +```js +const obj1 = { + name: 'qianguyihao', + age: 28, +}; + +const obj2 = {}; +// 浅拷贝:把 obj1 拷贝给 obj2 +Object.assign(obj2, obj1); +``` + +**例 3**:(和上面的例 2 等价) + +```js +const obj1 = { + name: 'qianguyihao', + age: 28, +}; + +const obj2 = {}; +// 浅拷贝:把 obj1 拷贝给 obj2。注意,这里的 obj2 和 obj3 其实是等价的,他们指向了同一个内存地址 +const obj3 = Object.assign(obj2, obj1); +``` + +## 深拷贝的实现方式 + +深拷贝其实就是将浅拷贝进行递归。 + +### 用 for in 递归实现深拷贝 + +代码实现: + +```js +let obj1 = { + name: 'qianguyihao', + age: 28, + info: { + desc: 'hello', + }, + color: ['red', 'blue', 'green'], +}; +let obj2 = {}; + +deepCopy(obj2, obj1); +console.log(obj2); +obj1.info.desc = 'github'; +console.log(obj2); + +// 方法:深拷贝 +function deepCopy(newObj, oldObj) { + for (let key in oldObj) { + // 获取属性值 oldObj[key] + let item = oldObj[key]; + // 判断这个值是否是数组 + if (item instanceof Array) { + newObj[key] = []; + deepCopy(newObj[key], item); + } else if (item instanceof Object) { + // 判断这个值是否是对象 + newObj[key] = {}; + deepCopy(newObj[key], item); + } else { + // 简单数据类型,直接赋值 + newObj[key] = item; + } + } +} +``` diff --git a/04-JavaScript基础/27-对象的高级操作:Object.assign().md b/04-JavaScript基础/29-对象的高级操作.md similarity index 77% rename from 04-JavaScript基础/27-对象的高级操作:Object.assign().md rename to 04-JavaScript基础/29-对象的高级操作.md index 215ef3e..e88d001 100644 --- a/04-JavaScript基础/27-对象的高级操作:Object.assign().md +++ b/04-JavaScript基础/29-对象的高级操作.md @@ -1,14 +1,4 @@ -## Object.assgin() - -### 把 对象 obj1 复制给 obj2(两者之间互不影响) - -代码举例: - -```js -// 复制对象:把 obj1 赋值给 obj1。两者之间互不影响 -var obj2 = Object.assign({}, obj1); -``` ## Object.freeze() 冻结对象 diff --git a/04-JavaScript基础/28-原型链和原型继承.md b/04-JavaScript基础/30-原型链和原型继承.md similarity index 100% rename from 04-JavaScript基础/28-原型链和原型继承.md rename to 04-JavaScript基础/30-原型链和原型继承.md diff --git a/04-JavaScript基础/29-类和构造继承.md b/04-JavaScript基础/31-类和构造继承.md similarity index 100% rename from 04-JavaScript基础/29-类和构造继承.md rename to 04-JavaScript基础/31-类和构造继承.md