【JS】307- 复习 Object.assign 原理及其实现
点击上方“前端自习课”关注,学习起来~
引言
上篇文章介绍了赋值、浅拷贝和深拷贝,其中介绍了很多赋值和浅拷贝的相关知识以及两者区别,限于篇幅只介绍了一种常用深拷贝方案。
本篇文章会先介绍浅拷贝 Object.assign 的实现原理,然后带你手动实现一个浅拷贝,并在文末留下一道面试题,期待你的评论。
浅拷贝 Object.assign
上篇文章介绍了其定义和使用,主要是将所有可枚举属性的值从一个或多个源对象复制到目标对象,同时返回目标对象。(来自 MDN)
语法如下所示:
Object.assign(target, ...sources)
其中 target 是目标对象,sources 是源对象,可以有多个,返回修改后的目标对象 target。
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后来的源对象的属性将类似地覆盖早先的属性。
示例1
我们知道浅拷贝就是拷贝第一层的基本类型值,以及第一层的引用类型地址。
// 木易杨// 第一步let a = { name: "advanced", age: 18}let b = { name: "muyiy", book: { title: "You Don't Know JS", price: "45" }}let c = Object.assign(a, b);console.log(c);// {// name: "muyiy",// age: 18,// book: {title: "You Don't Know JS", price: "45"}// } console.log(a === c);// true// 第二步b.name = "change";b.book.price = "55";console.log(b);// {// name: "change",// book: {title: "You Don't Know JS", price: "55"}// } // 第三步console.log(a);// {// name: "muyiy",// age: 18,// book: {title: "You Don't Know JS", price: "55"}// }
// 第一步
let a = {
name: "advanced",
age: 18
}
let b = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let c = Object.assign(a, b);
console.log(c);
// {
// name: "muyiy",
// age: 18,
// book: {title: "You Don't Know JS", price: "45"}
// }
console.log(a === c);
// true
// 第二步
b.name = "change";
b.book.price = "55";
console.log(b);
// {
// name: "change",
// book: {title: "You Don't Know JS", price: "55"}
// }
// 第三步
console.log(a);
// {
// name: "muyiy",
// age: 18,
// book: {title: "You Don't Know JS", price: "55"}
// }
1、在第一步中,使用 Object.assign 把源对象 b 的值复制到目标对象 a 中,这里把返回值定义为对象 c,可以看出 b 会替换掉 a 中具有相同键的值,即如果目标对象(a)中的属性具有相同的键,则属性将被源对象(b)中的属性覆盖。这里需要注意下,返回对象 c 就是 目标对象 a。
2、在第二步中,修改源对象 b 的基本类型值(name)和引用类型值(book)。
3、在第三步中,浅拷贝之后目标对象 a 的基本类型值没有改变,但是引用类型值发生了改变,因为 Object.assign() 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用地址。
示例2
String 类型和 Symbol 类型的属性都会被拷贝,而且不会跳过那些值为 null 或 undefined 的源对象。
// 木易杨// 第一步let a = { name: "muyiy", age: 18}let b = { b1: Symbol("muyiy"), b2: null, b3: undefined}let c = Object.assign(a, b);console.log(c);// {// name: "muyiy",// age: 18,// b1: Symbol(muyiy),// b2: null,// b3: undefined// } console.log(a === c);// true
// 第一步
let a = {
name: "muyiy",
age: 18
}
let b = {
b1: Symbol("muyiy"),
b2: null,
b3: undefined
}
let c = Object.assign(a, b);
console.log(c);
// {
// name: "muyiy",
// age: 18,
// b1: Symbol(muyiy),
// b2: null,
// b3: undefined
// }
console.log(a === c);
// true
Object.assign 模拟实现
实现一个 Object.assign 大致思路如下:
1、判断原生 Object 是否支持该函数,如果不存在的话创建一个函数 assign,并使用 Object.defineProperty 将该函数绑定到 Object 上。
2、判断参数是否正确(目标对象不能为空,我们可以直接设置{}传递进去,但必须设置值)
3、使用 Object() 转成对象,并保存为 to,最后返回这个对象 to
4、使用 for..in 循环遍历出所有可枚举的自有属性。并复制给新的目标对象(hasOwnProperty返回非原型链上的属性)
实现代码如下,这里为了验证方便,使用 assign2 代替 assign。注意此模拟实现不支持 symbol 属性,因为ES5 中根本没有 symbol 。
// 木易杨if (typeof Object.assign2 != 'function') { // Attention 1 Object.defineProperty(Object, "assign2", { value: function (target) { 'use strict'; if (target == null) { // Attention 2 throw new TypeError('Cannot convert undefined or null to object'); } // Attention 3 var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { // Attention 2 // Attention 4 for (var nextKey in nextSource) { if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, writable: true, configurable: true });}
if (typeof Object.assign2 != 'function') {
// Attention 1
Object.defineProperty(Object, "assign2", {
value: function (target) {
'use strict';
if (target == null) { // Attention 2
throw new TypeError('Cannot convert undefined or null to object');
}
// Attention 3
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Attention 2
// Attention 4
for (var nextKey in nextSource) {
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
测试一下
// 木易杨// 测试用例let a = { name: "advanced", age: 18}let b = { name: "muyiy", book: { title: "You Don't Know JS", price: "45" }}let c = Object.assign2(a, b);console.log(c);// {// name: "muyiy",// age: 18,// book: {title: "You Don't Know JS", price: "45"}// } console.log(a === c);// true
// 测试用例
let a = {
name: "advanced",
age: 18
}
let b = {
name: "muyiy",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let c = Object.assign2(a, b);
console.log(c);
// {
// name: "muyiy",
// age: 18,
// book: {title: "You Don't Know JS", price: "45"}
// }
console.log(a === c);
// true
针对上面的代码做如下扩展。
注意1:可枚举性
原生情况下挂载在 Object 上的属性是不可枚举的,但是直接在 Object 上挂载属性 a 之后是可枚举的,所以这里必须使用 Object.defineProperty,并设置 enumerable: false 以及 writable: true, configurable: true。
// 木易杨for(var i in Object) { console.log(Object[i]);}// 无输出Object.keys( Object );// []
for(var i in Object) {
console.log(Object[i]);
}
// 无输出
Object.keys( Object );
// []
上面代码说明原生 Object 上的属性不可枚举。
我们可以使用 2 种方法查看 Object.assign 是否可枚举,使用 Object.getOwnPropertyDescriptor 或者 Object.propertyIsEnumerable 都可以,其中propertyIsEnumerable(..) 会检查给定的属性名是否直接存在于对象中(而不是在原型链上)并且满足 enumerable: true。具体用法如下:
// 木易杨// 方法1Object.getOwnPropertyDescriptor(Object, "assign");// {// value: ƒ, // writable: true, // 可写// enumerable: false, // 不可枚举,注意这里是 false// configurable: true // 可配置// }// 方法2Object.propertyIsEnumerable("assign");// false
// 方法1
Object.getOwnPropertyDescriptor(Object, "assign");
// {
// value: ƒ,
// writable: true, // 可写
// enumerable: false, // 不可枚举,注意这里是 false
// configurable: true // 可配置
// }
// 方法2
Object.propertyIsEnumerable("assign");
// false
上面代码说明 Object.assign 是不可枚举的。
介绍这么多是因为直接在 Object 上挂载属性 a 之后是可枚举的,我们来看如下代码。
// 木易杨Object.a = function () { console.log("log a");}Object.getOwnPropertyDescriptor(Object, "a");// {// value: ƒ, // writable: true, // enumerable: true, // 注意这里是 true// configurable: true// }Object.propertyIsEnumerable("a");// true
Object.a = function () {
console.log("log a");
}
Object.getOwnPropertyDescriptor(Object, "a");
// {
// value: ƒ,
// writable: true,
// enumerable: true, // 注意这里是 true
// configurable: true
// }
Object.propertyIsEnumerable("a");
// true
所以要实现 Object.assign 必须使用 Object.defineProperty,并设置 writable: true, enumerable: false, configurable: true,当然默认情况下不设置就是 false。
// 木易杨Object.defineProperty(Object, "b", { value: function() { console.log("log b"); }});Object.getOwnPropertyDescriptor(Object, "b");// {// value: ƒ, // writable: false, // 注意这里是 false// enumerable: false, // 注意这里是 false// configurable: false // 注意这里是 false// }
Object.defineProperty(Object, "b", {
value: function() {
console.log("log b");
}
});
Object.getOwnPropertyDescriptor(Object, "b");
// {
// value: ƒ,
// writable: false, // 注意这里是 false
// enumerable: false, // 注意这里是 false
// configurable: false // 注意这里是 false
// }
所以具体到本次模拟实现中,相关代码如下。
// 木易杨// 判断原生 Object 中是否存在函数 assign2if (typeof Object.assign2 != 'function') { // 使用属性描述符定义新属性 assign2 Object.defineProperty(Object, "assign2", { value: function (target) { ... }, // 默认值是 false,即 enumerable: false writable: true, configurable: true });}
// 判断原生 Object 中是否存在函数 assign2
if (typeof Object.assign2 != 'function') {
// 使用属性描述符定义新属性 assign2
Object.defineProperty(Object, "assign2", {
value: function (target) {
...
},
// 默认值是 false,即 enumerable: false
writable: true,
configurable: true
});
}
注意2:判断参数是否正确
有些文章判断参数是否正确是这样的
// 木易杨if (target === undefined || target === null) { throw new TypeError('Cannot convert undefined or null to object');}
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
这样肯定没问题,但是这样写没有必要,因为 undefined 和 null 是相等的(高程 3 P52 ),即 undefined == null 返回 true,只需要按照如下方式判断就好了。
// 木易杨if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object');}
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
注意3:原始类型被包装为对象
// 木易杨var v1 = "abc";var v2 = true;var v3 = 10;var v4 = Symbol("foo");var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); // 原始类型会被包装,null 和 undefined 会被忽略。// 注意,只有字符串的包装对象才可能有自身可枚举属性。console.log(obj); // { "0": "a", "1": "b", "2": "c" }
var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo");
var obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj);
// { "0": "a", "1": "b", "2": "c" }
上面代码中的源对象 v2、v3、v4 实际上被忽略了,原因在于他们自身没有可枚举属性。
// 木易杨var v1 = "abc";var v2 = true;var v3 = 10;var v4 = Symbol("foo");var v5 = null;// Object.keys(..) 返回一个数组,包含所有可枚举属性// 只会查找对象直接包含的属性,不查找[[Prototype]]链Object.keys( v1 ); // [ '0', '1', '2' ]Object.keys( v2 ); // []Object.keys( v3 ); // []Object.keys( v4 ); // []Object.keys( v5 ); // TypeError: Cannot convert undefined or null to object// Object.getOwnPropertyNames(..) 返回一个数组,包含所有属性,无论它们是否可枚举// 只会查找对象直接包含的属性,不查找[[Prototype]]链Object.getOwnPropertyNames( v1 ); // [ '0', '1', '2', 'length' ]Object.getOwnPropertyNames( v2 ); // []Object.getOwnPropertyNames( v3 ); // []Object.getOwnPropertyNames( v4 ); // []Object.getOwnPropertyNames( v5 ); // TypeError: Cannot convert undefined or null to object
var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo");
var v5 = null;
// Object.keys(..) 返回一个数组,包含所有可枚举属性
// 只会查找对象直接包含的属性,不查找[[Prototype]]链
Object.keys( v1 ); // [ '0', '1', '2' ]
Object.keys( v2 ); // []
Object.keys( v3 ); // []
Object.keys( v4 ); // []
Object.keys( v5 );
// TypeError: Cannot convert undefined or null to object
// Object.getOwnPropertyNames(..) 返回一个数组,包含所有属性,无论它们是否可枚举
// 只会查找对象直接包含的属性,不查找[[Prototype]]链
Object.getOwnPropertyNames( v1 ); // [ '0', '1', '2', 'length' ]
Object.getOwnPropertyNames( v2 ); // []
Object.getOwnPropertyNames( v3 ); // []
Object.getOwnPropertyNames( v4 ); // []
Object.getOwnPropertyNames( v5 );
// TypeError: Cannot convert undefined or null to object
但是下面的代码是可以执行的。
// 木易杨var a = "abc";var b = { v1: "def", v2: true, v3: 10, v4: Symbol("foo"), v5: null, v6: undefined}var obj = Object.assign(a, b); console.log(obj);// { // [String: 'abc']// v1: 'def',// v2: true,// v3: 10,// v4: Symbol(foo),// v5: null,// v6: undefined // }
var a = "abc";
var b = {
v1: "def",
v2: true,
v3: 10,
v4: Symbol("foo"),
v5: null,
v6: undefined
}
var obj = Object.assign(a, b);
console.log(obj);
// {
// [String: 'abc']
// v1: 'def',
// v2: true,
// v3: 10,
// v4: Symbol(foo),
// v5: null,
// v6: undefined
// }
原因很简单,因为此时 undefined、true 等不是作为对象,而是作为对象 b 的属性值,对象 b 是可枚举的。
// 木易杨// 接上面的代码Object.keys( b ); // [ 'v1', 'v2', 'v3', 'v4', 'v5', 'v6' ]
// 接上面的代码
Object.keys( b ); // [ 'v1', 'v2', 'v3', 'v4', 'v5', 'v6' ]
这里其实又可以看出一个问题来,那就是目标对象是原始类型,会包装成对象,对应上面的代码就是目标对象 a 会被包装成 [String: 'abc'],那模拟实现时应该如何处理呢?很简单,使用 Object(..) 就可以了。
// 木易杨var a = "abc";console.log( Object(a) );// [String: 'abc']
var a = "abc";
console.log( Object(a) );
// [String: 'abc']
到这里已经介绍很多知识了,让我们再来延伸一下,看看下面的代码能不能执行。
// 木易杨var a = "abc";var b = "def";Object.assign(a, b);
var a = "abc";
var b = "def";
Object.assign(a, b);
答案是否定的,会提示以下错误。
// 木易杨TypeError: Cannot assign to read only property '0' of object '[object String]'
TypeError: Cannot assign to read only property '0' of object '[object String]'
原因在于 Object("abc") 时,其属性描述符为不可写,即 writable: false。
// 木易杨var myObject = Object( "abc" );Object.getOwnPropertyNames( myObject );// [ '0', '1', '2', 'length' ]Object.getOwnPropertyDescriptor(myObject, "0");// { // value: 'a',// writable: false, // 注意这里// enumerable: true,// configurable: false // }
var myObject = Object( "abc" );
Object.getOwnPropertyNames( myObject );
// [ '0', '1', '2', 'length' ]
Object.getOwnPropertyDescriptor(myObject, "0");
// {
// value: 'a',
// writable: false, // 注意这里
// enumerable: true,
// configurable: false
// }
同理,下面的代码也会报错。
// 木易杨var a = "abc";var b = { 0: "d"};Object.assign(a, b); // TypeError: Cannot assign to read only property '0' of object '[object String]'
var a = "abc";
var b = {
0: "d"
};
Object.assign(a, b);
// TypeError: Cannot assign to read only property '0' of object '[object String]'
注意4:存在性
如何在不访问属性值的情况下判断对象中是否存在某个属性呢,看下面的代码。
// 木易杨var anotherObject = { a: 1};// 创建一个关联到 anotherObject 的对象var myObject = Object.create( anotherObject );myObject.b = 2;("a" in myObject); // true("b" in myObject); // truemyObject.hasOwnProperty( "a" ); // falsemyObject.hasOwnProperty( "b" ); // true
var anotherObject = {
a: 1
};
// 创建一个关联到 anotherObject 的对象
var myObject = Object.create( anotherObject );
myObject.b = 2;
("a" in myObject); // true
("b" in myObject); // true
myObject.hasOwnProperty( "a" ); // false
myObject.hasOwnProperty( "b" ); // true
这边使用了 in 操作符和 hasOwnProperty 方法,区别如下(你不知道的JS上卷 P119):
1、in 操作符会检查属性是否在对象及其 [[Prototype]] 原型链中。
2、hasOwnProperty(..) 只会检查属性是否在 myObject 对象中,不会检查 [[Prototype]] 原型链。
Object.assign 方法肯定不会拷贝原型链上的属性,所以模拟实现时需要用 hasOwnProperty(..) 判断处理下,但是直接使用 myObject.hasOwnProperty(..) 是有问题的,因为有的对象可能没有连接到 Object.prototype 上(比如通过 Object.create(null) 来创建),这种情况下,使用 myObject.hasOwnProperty(..) 就会失败。
// 木易杨var myObject = Object.create( null );myObject.b = 2;("b" in myObject); // truemyObject.hasOwnProperty( "b" );// TypeError: myObject.hasOwnProperty is not a function
var myObject = Object.create( null );
myObject.b = 2;
("b" in myObject);
// true
myObject.hasOwnProperty( "b" );
// TypeError: myObject.hasOwnProperty is not a function
解决方法也很简单,使用我们在【进阶3-3期】中介绍的 call 就可以了,使用如下。
// 木易杨var myObject = Object.create( null );myObject.b = 2;Object.prototype.hasOwnProperty.call(myObject, "b");// true
var myObject = Object.create( null );
myObject.b = 2;
Object.prototype.hasOwnProperty.call(myObject, "b");
// true
所以具体到本次模拟实现中,相关代码如下。
// 木易杨// 使用 for..in 遍历对象 nextSource 获取属性值// 此处会同时检查其原型链上的属性for (var nextKey in nextSource) { // 使用 hasOwnProperty 判断对象 nextSource 中是否存在属性 nextKey // 过滤其原型链上的属性 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { // 赋值给对象 to,并在遍历结束后返回对象 to to[nextKey] = nextSource[nextKey]; }}
// 使用 for..in 遍历对象 nextSource 获取属性值
// 此处会同时检查其原型链上的属性
for (var nextKey in nextSource) {
// 使用 hasOwnProperty 判断对象 nextSource 中是否存在属性 nextKey
// 过滤其原型链上的属性
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
// 赋值给对象 to,并在遍历结束后返回对象 to
to[nextKey] = nextSource[nextKey];
}
}
本期思考题
如何实现一个深拷贝?
参考
MDN 之 Object.assign()
ES2015系列(二) 理解 Object.assign
▼原创系列推荐▼1.JavaScript 重温系列(22篇全)
2.ECMAScript 重温系列(10篇全)
3.JavaScript设计模式 重温系列(9篇全)
4.正则 / 框架 / 算法等 重温系列(16篇全)
你点的每个赞,我都认真当成了喜欢
【JS】307- 复习 Object.assign 原理及其实现的更多相关文章
- 【进阶4-2期】Object.assign 原理及其实现 (转)
这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://github.com/yygmind/blog/issues/26 浅拷贝 Object.assign 上篇文章介绍了其定义和使 ...
- js中的Object.assign接受两个函数为参数的时候会发生什么?
缘由 今天看到一段代码 return Object.assign(func1, func2); 心生疑惑,为什么 Object.assign 的参数可以是函数? 于是有了下面这一堆东西,其实都是老生常 ...
- javascript系列--Object.assign实现浅拷贝的原理以及实现
一.前言 之前在前面一篇学习了赋值,浅拷贝和深拷贝.介绍了这三者的相关知识和区别. 传送门:https://www.mwcxs.top/page/592.html 本文会介绍浅拷贝Object.ass ...
- 再谈js对象数据结构底层实现原理-object array map set
如果有java基础的同学,可以回顾下<再谈Java数据结构—分析底层实现与应用注意事项>:java把内存分两种:一种是栈内存,另一种是堆内存.基本类型(即int,short,long,by ...
- 解决webpack和gulp打包js时ES6转译ES5时Object.assign()方法没转译成功的问题
在webpack或gulp打包的配置文件中package.json 引入"@babel/plugin-transform-object-assign": "^7.2.0& ...
- js - object.assign 以及浅、深拷贝
浅(引用)拷贝:共用同一内存地址,你改值我也变 譬如常用的对象赋值操作 深拷贝:深拷贝即创建新的内存地址保存值(互不影响) 譬如以下 const shallBasicCopy = obj => ...
- js 合并多个对象 Object.assign
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象.它将返回目标对象. var o1 = { a: 1 };var o2 = { b: 2 };var o3 ...
- js中或者vue中 Object.assign()用法详解
Object.assign()是浅拷贝. 合并对象 var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object. ...
- JavaScript 复制对象【Object.assign方法无法实现深复制】
在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...
随机推荐
- Java基础:8种基本数据类型,取值范围和储存字节说明。
Java中,一共有8种基本数据类型: 4种整数型:int,short,long,byte. 2种浮点型:float,double. 1种字符类型:char. 1种表示真值的类型:boolean. [S ...
- hdu 1533 Going Home (KM)
Going HomeTime Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- 在lldb调试中调用c++函数 - 如何使用QuartzCore里面的日志消息
承接上一篇,上一篇讲到可以在lldb调试中调用QuartzCore.framework里的CA::Render::Object::show方法来是观察CA::Render模块内的类的信息,但是在lld ...
- 推荐算法之用矩阵分解做协调过滤——LFM模型
隐语义模型(Latent factor model,以下简称LFM),是推荐系统领域上广泛使用的算法.它将矩阵分解应用于推荐算法推到了新的高度,在推荐算法历史上留下了光辉灿烂的一笔.本文将对 LFM ...
- 学习记录:《C++设计模式——李建忠主讲》6.“状态变化”模式
状态变化模式:在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定.状态变化模式为这一问题提供了一种解决方案. 典型模式:状态模式(State).备忘录 ...
- 使用idea来部署git项目
使用idea来部署git项目 一).将项目交由git管理 VCS ---->import into Version Cntorl ------>create Git Repository ...
- php为什么需要异步编程?php异步编程的详解(附示例)
本篇文章给大家带来的内容是关于php为什么需要异步编程?php异步编程的详解(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 我对 php 异步的知识还比较混乱,写这篇是为了 ...
- 超速入门AT指令集 | 我的物联网成长记
[摘要] 在物联网中,AT命令集可用于控制&调测设备.通信模块入网等.本文为您介绍NB-IoT常用的AT命令集及其调测工具. 什么是AT指令集 AT命令,用来控制TE(Terminal Equ ...
- [Odoo12基础教程]之第一篇-创建Todo应用
声明: 本教程基于 Ruter 老师的 [Odoo基础教程系列] ,Ruter老师教程的链接地址为:Odoo基础教程系列 . 至于为什么已经有了Ruter老师的教程,还要自己再搬移一份呢?是基于一 ...
- enable_shared_from_this用法分析
一.背景 在为什么需要异步编程文章末尾提到,"为了使socket和缓冲区(read或write)在整个异步操作的生命周期一直保持活动,我们需要采取特殊的保护措施.你的连接类需要继承自enab ...