重写留言板2:

index2.js

const obj = {m:new Map(),$:name => document.querySelector(name),bind:function(){this.$(".submit").onclick = () =>{let [_name,_message] = [this.$(".name").value,this.$(".message").value];if(!_name || !_message) return;this.m.set(_name,_message);//展示this.showList();}},showList:function(){let str = "";for(let [k,v] of this.m){//模板字符串str += `<li class="list-group-item">${k}<span>说:</span>${v}</li>`};this.$(".messageList").innerHTML = str;}
}
window.onload = function(){obj.bind();
}

index3.js

    const obj = {$: name => document.querySelector(name),url = 'http://127.0.0.1:3000'bind: function () {this.$(".submit").onclick = () => {let [_name, _message] = [this.$(".name").value, this.$(".message").value];if (!_name || !_message) return;this.submitData(_name, _message);  //存储数据}},submitData: function (_name, _message) {getJSON(this.url+'/submit_message', 'post', {name: _name, message: _message}).then(res => {console.log(res);  //将成功的数据返回到这里let {code} = res;if (code == '200') {this.getData();}}, function (error) {console.log(error)})},getData: function () {getJSON(this.url+'/get_message', 'get').then(res => {//console.log(res);   //将成功的数据返回到这里let {code, result} = res;if (code == '200') {let str = "";for (let obj of result) {//模板字符串str += `<li class="list-group-item">${obj.name}<span>说:</span>${obj.message}</li>`};this.$(".messageList").innerHTML = str;}}, function (error) {console.log(error)})},lists: function () { }   //列表展示
}window.onload = function () {obj.bind();
}

promise.js

复制4小题代码

//Promise对象实现Ajax封装
const getJSON = function (url, type, data = null) {const promise = new Promise(function (resolve, reject) {const xmlHttp = new XMLHttpRequest();xmlHttp.open(type, url);if (type == 'get') {xmlHttp.send();} else {xmlHttp.setRequestHeader("Content-Type", "application/json");xmlHttp.send(JSON.stringify(data));};xmlHttp.responseType = "json";xmlHttp.onreadystatechange = function () {if (xmlHttp.readyState !== 4) return;if (xmlHttp.status === 200) {resolve(xmlHttp.response);  //成功后,可以返回到then函数下} else {reject(new Error(xmlHttp.statusText));}};});return promise;
};

server.js

var express = require("express")
var bodyParser = require('body-parser');   //body解析
var app = express();
var path = require("path");var allowCrossDomain = function (req, res, next) {res.header('Access-Control-Allow-Origin', '*');//自定义中间件,设置跨域需要的响应头。res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');  //允许任何方法res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,X-Session-Token');   //允许任何类型next();
};const map = new Map();
var arr = [];app.use(allowCrossDomain);//运用跨域的中间件
//app.use(bodyParser.text());//运用中间件,对请求体的文本进行解析
app.use(bodyParser.json())    创建 application/json 解析
app.use(bodyParser.urlencoded({ extended: true })) // 创建 application/x-www-form-urlencoded 解析app.get("/", function (req, res) {res.send('index')
})
app.get("/data/query", function (req, res) {res.send(JSON.stringify(arr));
})
app.post("/data/add", function (req, res) {console.log(req.body, req.query, req.params);arr.push(req.body)res.send(JSON.stringify(arr));
})
app.post("/data/login", function (req, res) {console.log(req.body, req.query, req.params);if (req.body.name == 'admin' && req.body.password == 'admin') {res.send(JSON.stringify({ code: '200', msg: '登录成功' }));} else {res.send(JSON.stringify({ code: '200', msg: '账号密码输入错误!' }));}
})
=================================== 主要这两个 ======================================
//存储(添加)post  map
app.post('/submit_message', function (req, res, next) {
//获取前端传入的参数 {name: _name, message: _message}console.log(req.body, req.query, req.params);   for (let k in req.body) {map.set(k, req.body[k])};var data = {"code": "200","msg": "success",}res.end(JSON.stringify(data));next();
})
-----------------------------------------------------------------------------------
//查询    get
app.get('/get_message', function (req, res, next) {//转为对象var o = {};for (let [k, v] of map) {o[k] = v;};arr.push(o);var data = {"code": "200","msg": "success","result": arr     //存储到这里}res.end(JSON.stringify(data));next();
})
===================================================================================
app.listen(3000, function () { console.log("Server started on port 3000.") });

重写留言板3:(串行、并行)

html

用上面留言板继续

promise.js

server.js

//测试接口
app.get('/get1',function(req,res){var data ={code:'200',msg:'get1',result:{id:1}}res.send(JSON.stringify(data));
})
app.get('/get2',function(req,res){var data ={code:'200',msg:'get2'}res.send(JSON.stringify(data));
})

index.js

复制index3.js
修改:

var obj = {init: function () {this.bind();},url: 'http://localhost:3000',
$: name => document.querySelector(name),
===================================================================================bind: function () {console.log(this);this.$(".submit").onclick = () => {console.log(this);  //这里的this指的就是obj 箭头函数中this的指向不会发生变化let [_name, _msg] = [this.$(".name").value, this.$(".message").value];if (_name == '' || _msg == '') {alert("请输入信息");} else {this.submitData(_name, _msg);this.$(".name").value = '';this.$(".message").value = '';}},//链式写法this.$(".queryThen").onclick = () => { this.queryThen() };//并行写法this.$(".queryWhen").onclick = () => { this.queryWhen() };
},
===================================================================================submitData: function (_name, _msg) {getJSON(`${this.url}/submit_message`, "post", { name: _name, message: _msg }).then(res => {console.log(res);let { code } = res;if (code == '200') {this.getData();}}).catch(err => {console.log(err)})// getJSON("http:localhost:3000/map/add1","get")// .then(function(res){//     console.log(res);//     return getJSON("http:localhost:3000/add",'post', {id:res.result.id,name: '123', message: '123'})// })// .then(function(res){//         console.log(res)// },function(){// })
},
===================================================================================getData: function (res) {getJSON(`${this.url}/get_message`, "get").then(res => {console.log(res);let { code, result } = res;if (code == '200') {let str = "";for (let v of result) {str += `<li class="list-group-item">${v.name}<span>说:</span>${v.message}</li>`};this.$(".messageList").innerHTML = str;}}).catch(err => {console.log(err)})
},
===================================================================================queryThen: function () {  //串行//   getJSON(`${this.url}/get1`,"get")//     .then(res=>{//         console.log(res);//         return getJSON(`${this.url}/get2?id=${res.result.id}`,"get")//     },err=>{//     }).then(res=>{//         console.log(res)//     },function(){//     })var _this = this;async function f() {var a1 = await getJSON(`${_this.url}/get1`, "get");//console.log(a1)var a2 = await getJSON(`${_this.url}/get2?id=${a1.result.id}`, "get");//console.log(a2)}f();
},
===================================================================================queryWhen: function () {  //并行Promise.all([getJSON(`${this.url}/get1`, "get"),getJSON(`${this.url}/get2`, "get")]).then(([d1, d2]) => {console.log(d1, d2)})

===================================================================================// var p1 = new Promise((resolve,reject)=>{//     setTimeout(()=>{//         resolve('p1')//     },1000)// });// var p2 = new Promise((resolve,reject)=>{//     setTimeout(()=>{//         resolve('p2')//     },5000)// });// Promise.all([p1,p2]).then(([d1,d2])=>{//     console.log(d1,d2)// })

        // var p3 = new Promise((resolve,reject)=>{//     setTimeout(()=>{//         resolve('p3')//     },1000)// });// var p4 = new Promise((resolve,reject)=>{//     setTimeout(()=>{//         resolve('p4')//     },5000)// });// Promise.race([p3,p4]).then(d=>{   //返回的是请求快的,//     console.log(d)// })

===================================================================================}
};window.onload = function () {obj.init();
}

(12)async-await

经常会看到有了 async-await、promise 还有必要学习吗、async await优于promise的几个特点,接收了这些信息后,就蒙圈了

async-await是promise和generator的语法糖。只是为了让我们书写代码时更加流畅,当然也增强了代码的可读性

简单来说:async-await 是建立在 promise(承诺)机制之上的,并不能取代其地位

具体理解:

1.async

    async function timeout() {return 'hello world'}timeout(); //为什么没有执行'hello world'
-----------------------------------------------------------------------------------async function timeout() {return 'hello world'}console.log(timeout()); //Promise {<resolved>: "hello world"}

async 函数返回的是一个promise 对象,如果要获取到promise 返回值,应该用then 方法

    async function fn() {return 100;}console.log(fn());     //Promise {<resolved>: 100}let f = fn();f.then(function (d) {console.log(d)  //100})

 //同步—>微任务—>宏任务

//同步—>微任务—>宏任务

2.await

await操作符用于等待一个Promise对象,它只能在异步函数async function内部使用

返回值:

返回promise对象的处理结果,如果待等的不是promise对象,则返回该值本身

如果一个promise被传递给一个await操作符,await将等待promise正常处理完成并返回其处理结果

    function f2() {console.log(4)}async function f() {await f2();   //阻塞(await后面的都阻塞,阻塞console.log(2))console.log(2)}f();console.log(3);

正常情况下,await命令后面是一个promise对象,它也可以是其它值,如字符串,布尔值,数值以及普通函数。

    console.log(2)async function fn() {console.log(3)await 100; //阻塞(await后面的都阻塞,阻塞console.log(1))console.log(1)}fn()console.log(4)

await命令后面是一个promise对象

    function p() {return new Promise(resolve => {resolve();console.log(1)});};async function fn() {console.log(2)await p();console.log(3)}fn()

雅倩(网友):await 可以理解为把异步的then转为同步的写法

(13)微任务和宏任务

1.微任务与宏任务的区别

就像去银行办业务一样,先要取号进行排号。

一般上边都会印着类似:“您的号码为XX,前边还有XX人。”之类的字样。

由于柜员只能处理一个来办理业务的客户,这时每一个来办理业务的人就可以认为是银行柜员的一个宏

任务来存在的;

当柜员处理完当前客户的问题以后,选择接待下一位,广播报号,也就是下一个宏任务的开始。

所以多个宏任务合在一起就可以认为有一个任务队列在这,里边是当前银行中所有排号的客户。

如果叫到你的时候你不在,那么你当前的号牌就作废了,柜员会选择直接跳过进行下一个客户的业务处

理,等你回来以后还需要重新取号,而且一个宏任务在执行的过程中,是可以添加一些微任务的,就像在柜台办理业务,你前边的一位老大爷可能在存款,结果在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“想选择稳一些的理财”,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队”。

所以本来快轮到你来办理业务,会因为老大爷临时添加的“理财业务”而往后推。

也许老大爷在办完理财以后还想 再办一个信用卡?或者 再买点儿纪念币?

无论是什么需求,只要是柜员能够帮她办理的,都会在处理你的业务之前来做这些事情,这些都可以认

为是微任务。

在当前的微任务没有执行完成时,是不会执行下一个宏任务的。

//同步—>微任务—>宏任务

2.promise是同步还是异步?

Promise是ES6提出的解决异步编程导致陷入回调地狱问题的,那么Promise是同步的还是异步的?可以 确定的是,Promise本身是同步

    console.log(1)let a = new Promise((res, rej) => {console.log(2);});console.log(3);let b = new Promise((res, rej) => {console.log(4);});console.log(5);

Promise本身是同步

then方法和catch方法是异步

    let a = new Promise((res, rej) => {    //同步console.log(1);res(2) });a.then((res) => {  //微任务,异步console.log(res);});console.log(3);     //同步

扩展实例

    console.log(1)let a = new Promise((res, rej) => {res();console.log(2);});a.then(() => {console.log(3)})console.log(4);let b = new Promise((res, rej) => {res();console.log(5);});b.then(() => {console.log(6)})console.log(7);

//同步—>微任务—>宏任务

(14)class

1.class的基本用法

ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到

ES5中定义类

    function AA (x, y) {this.x = x;this.y = y;}AA.prototype.toString = function () {return this.x};var p = new AA (2, 4);

ES6

    class AA {constructor(x, y) {this.x = x;this.y = y;}toString() {return this.x;}}var p = new AA (3, 5);

上面代码定义了一个“类”,可以看到里面有一个构造函数方法,而 this 关键字则代表实例对象。也就是说,ES5 的构造函数 Point,对应 ES6 的 Point 类的构造方法。

Point 类除了构造方法,还定义了一个 toString 方法。注意,定义“类”的方法的时候,前面不需要加

上 function 这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了

会报错。

ES6 的类,完全可以看作构造函数的另一种写法

    class AA {// ...}typeof AA                       // "function"AA === AA.prototype.constructor   // true

2.constructor构造函数方法

constructor 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。一个类必须有 constructor 方法,如果没有显式定义,一个空的 constructor 方法会被默认添加。

    class AA { }//等同于class AA {constructor() { }}

3.类的实例

生成类的实例的写法,与 ES5 完全一样,也是使用 new 命令。

    class AA {// ...}var point = AA (2, 3);         //报错var point = new AA (2, 3);     //正确

4.class的继承

Class 可以通过 extends 关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

    class AA {constructor() {this.x = 'x';this.y = 'y';}toString() {return this.x;}}class ColorPoint extends AA {constructor() {super();}}var c = new ColorPoint();c.x                //'x'c.toString()     //'x'

上面代码定义了一个 ColorPoint 类,该类通过 extends 关键字,继承了 Point 类的所有属性和方法constructor 方法和 toString 方法之中,都出现了 super 关键字,它在这里表示父类的构造函数,用来新建父类的 this 对象

子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类自己的 this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用 super 方法,子类就得不到 this 对象。

5.super关键字

super 这个关键字,既可以当作函数使用,也可以当作对象使用

super 作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次 super 函数。

    class A { }class B extends A {constructor() {super();}}// 子类B的构造函数之中的super() ,代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错

注意, super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的 是 B 的实例,

因此 super() 在这里相当于 A.prototype.constructor.call(this)

super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

    class A {p() {return 2;}}class B extends A {constructor() {super();console.log(super.p()); // 2}}let b = new B();

(15)proxy(代理)

proxy 在目标对象的外层搭建了一层拦截

var proxy = new Proxy(target目标, handler处理);

1.基本用法

new Proxy() 表示生成一个Proxy 实例,target 参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为

    var target = { //target表示所要拦截的目标对象name: 'jindu'};var handler = {    //handler表示定制拦截行为get: function (target, key) {console.log(`${key} 被读取`);return target[key];},set: function (target, key, value) {console.log(`${key} 被设置为 ${value}`);target[key] = value;}}var a = new Proxy(target, handler);a.name;             //执行的是get方法a.name = 'abc';   //如果赋值,执行的是set方法console.log(target.name);        //abc

    //这样的话,两个都会触发

a读取属性的值时,实际上执行的是 handler.get:在控制台输出信息,并且读取被代理对象 target 的属性。

在 a 设置属性值时,实际上执行的是 handler.set:在控制台输出信息,并且设置被代理对象 target 的属性的值

2.Proxy的作用

对于代理模式 Proxy 的作用主要体现在三个方面:

  • 拦截和监视外部对对象的访问
  • 降低函数或类的复杂度
  • 在复杂操作前对操作进行校验或对所需资源进行管理

3.Proxy所能代理的范围--handler

实际上 handler 本身就是 ES6 所新设计的一个对象.它的作用就是用来 自定义代理对象的各种可代理操 作 。它本身一共有 13 中方法,每种方法都可以代理一种操作.其 13 种方法如下

get(target, key, receiver)
// 拦截对象属性的读取,比如proxy.foo和proxy['foo']。set(target, key, value, receiver)
// 拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。has(target, key)
// 拦截key in proxy的操作,返回一个布尔值。deleteProperty(target, key)
// 拦截delete proxy[key]的操作,返回一个布尔值。ownKeys(target)
// 拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)  //for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()   //的返回结果仅包括目标对象自身的可遍历属性。getOwnPropertyDescriptor(target, key)
//拦截Object.getOwnPropertyDescriptor(proxy, key),返回属性的描述对象。defineProperty(target, key, propDesc)
// 拦截Object.defineProperty(proxy, key, propDesc)、Object.defineProperties(proxy, propDescs) //返回一个布尔值。preventExtensions(target)
// 拦截Object.preventExtensions(proxy),返回一个布尔值。getPrototypeOf(target)
// 拦截Object.getPrototypeOf(proxy),返回一个对象。isExtensible(target)
// 拦截Object.isExtensible(proxy),返回一个布尔值。setPrototypeOf(target, proto)
// 拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。apply(target, object, args)
// 拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)proxy.apply(...)
construct(target, args)
// 拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

4.应用

(1)实现私有变量,想获取aaa,由于添加了拦截获取的只能是18

特点:利用startsWith方法,变量变为私有,不能被修改

    var AA = {name: 'aaa',_age: 30}var BB = {get: function (target, key) {if (key.startsWith('_')) {console.log('私有变量age不能被访问')return 18}return target[key];},set: function (target, key, value) {if (key.startsWith('_')) {console.log('私有变量age不能被修改')return 18}target[key] = value;}}var a = new Proxy(AA, BB);a._age       a._age = 20

(2)抽离校验模块

    var AA = {count: 0,id: 1234,total: 14};var BB = {set(target, key, value, proxy) {if (typeof value !== 'number') {throw Error("只能输入数字");}return Reflect反射.set(target, key, value, proxy);}};var p = new Proxy(AA, BB);

p.count = "123"; //抛出错误,因为 "123" 不是数值型

p.count = 333;   //赋值成功

5.Object.defineProperty()与Proxy的异同

Object.defineProperty()

优点:可以更好的拦截

缺点:无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应(虽说对常用的方法进行了处理,但然存在局限性);只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历(数组遍历之类会出问题)

proxy

优点:可以劫持整个对象,并返回一个新对象;有13种劫持操作

缺点:兼容性不好

    var Obj = {}Object.defineProperty(Obj, 'a', {get: function () {console.log('get');return v},set: function (val) {console.log('set');v = val}});Obj.a = []      // setObj.a.push('1')     // get(缺点,没存进去)下标问题Obj.a[0] = 1  // get(缺点,没存进去)Obj.a.pop(1)   // get(缺点,没存进去)Obj.a = [1, 2, 3] // set
===================================================================================var arr = [];var p = new Proxy(arr, {get: (target, key) => {console.log('get')return key in target ? target[key] : undefined},set: (target, key, value) => {console.log('set')target[key] = valuereturn true}})p.push(1);

    //get  获取数组arr的push方法//get  获取数组arr的length属性//set(触发两次)  设置arr[0] = 1//set  设置数组arr长度为1p[0] = 1 //setp[0] = 2  //set
<body><input type="text" id="textInput">输入:<span id="textSpan"></span><script>var obj = {},textInput = document.querySelector("#textInput"),  //输入textSpan = document.querySelector("#textSpan");    //输出Object.defineProperty(obj, 'name', {get: function () {console.log('get');return v},set: function (val) {console.log('set');v = val}});textInput.onkeyup按键按下时 = function () {obj.name = textInput.value;textSpan.innerHTML = obj.name;}</script>
</body>

ES6 —— 3、async-await、微任务和宏任务、class、proxy(代理)相关推荐

  1. async js 返回值_图文讲解浏览器执行JS过程中的微任务和宏任务

    背景 我们知道浏览器有一个特定的事件执行机制,专业名词叫做Event Loop.如下图所示,浏览器会优先执行同步代码,遇到异步的代码时,会被挂起并在需要执行的时候加入到 Task(有多种 Task) ...

  2. es6 --- promise和async/await的区别

    首先需要了解async函数: async是Generator函数的语法糖: // 使用Generator依次读取两个文件 var fs = require('fs'); var readFile = ...

  3. ES6箭头函数以及promise/async/await测试案例

    ES6箭头函数的运用 下面以一段代码解释 function one(){return 1 以上函数用箭头函数写步骤,参考下面代码 {}和里面的东西先删去 one = (里面写参数/无参数的里面为空)= ...

  4. 让IE9及以上兼容es6,Promise, 及es7的async await

    在完成下面A和B两步后,页面内嵌JS或者引入自己外部JS,script标签的type属性需要设置为text/babel <!DOCTYPE html> <html><he ...

  5. es6 async await 使用

    概述 说一下 async , await 函数的简单应用, 用最简单的示例,让复杂的事变得更简单. 记住以下知识,项目中基本够用 示例 以下示例,大家可以直接复制粘贴到浏览器的console面板测试, ...

  6. 8张图让你一步步看清 async/await 和 promise 的执行顺序

    2019独角兽企业重金招聘Python工程师标准>>> **摘要:**面试必问 原文:8张图帮你一步步看清 async/await 和 promise 的执行顺序 作者:ziwei3 ...

  7. 详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务

    队列在前端中的应用 一.队列是什么 二.应用场景 三.前端与队列:事件循环与任务队列 1.event loop 2.JS如何执行 3.event loop过程 4. DOM 事件和 event loo ...

  8. 事件循环机制 + ES7:Async/Await(基于generator原理实现)附详细示例分析

    文章目录 一.事件循环 任务队列 宏任务和微任务 循环机制 简单示例 二.Async/Await 1. async 2. await 3. 原理 4. 示例(红字分析为关键) 一.事件循环 任务队列 ...

  9. 微任务,宏任务,DOM渲染的执行顺序

    event loop过程 同步代码,一行一行放在Call Stack执行 遇到异步先记录下来,等待时机(定时,网络请求) 时机一到立马推入Callback Queue中 如Call Stack为空(同 ...

最新文章

  1. 机器学习要警惕的4个常见陷阱!
  2. python控制苹果手机触摸屏失灵怎么办_iphone触摸屏失灵怎么办 iphone触摸屏失灵解决办法【详解】...
  3. python 自动输入_Python自动输入【新手必学】
  4. java单列_Java 单例模式
  5. Python 文件处理命令
  6. BizTalk Server 2010 - 使用 WCF Service [ 中篇 ]
  7. php+mysql+记账系统_做了个php+mysql简单记账系统
  8. VMware网络NAT模式无法连接解决方法
  9. GPS基础知识(五)、GPS导航电文
  10. veracrypt加密mysql_VeraCrypt使用教程,VeraCrypt文件硬盘加密使用教程
  11. 硬核拆解自动驾驶工具链丨如何应对无人车部署落地的挑战?
  12. python如何安装第三方包
  13. 安装黑苹果时不识别内置磁盘_【让天下没有难装的黑果】3 Legacy传统BIOS使用CLOVER引导在GPT硬盘安装OSX+WIN双系统...
  14. Rotating reference frame
  15. 微信群聊,为什么人数上限500人?
  16. Dubbo结合Gateway实现微服务网关
  17. Android-WebView加载网页
  18. python量化交易:筹码分布(4)_计算方法_依据成交明细及及换手率估算
  19. 用Javascript开发《三国志曹操传》-开源讲座(五)-可移动地图的实现
  20. sql语句利用into outfile写入一句话

热门文章

  1. 微信小程序日历打卡组件wx-calendar
  2. 服务器维护后黑莲花刷新,魔兽世界怀旧服黑莲花刷新机制_wow怀旧服黑莲花刷新地点_3DM网游...
  3. slab下kmalloc内核函数实现
  4. 假使世界原来不像你预期,也要做最好的你
  5. Ubuntu 无法连接xshell的问题
  6. gradle:打包jar
  7. Windows 10安全更新后,或安装其他软件后乃至其他原因,导致开机后类似永动机的圆圈一直不停转的假死机,进不去系统的一种解决方案
  8. Microsoft WiFi与Skype WiFi有什么不同?
  9. 用hexo搭建个人博客遇见的问题
  10. 云时代数据安全才是真正的安全 —— 天空卫士 副总裁 巩文坚