友情提示:本文仅mark几个常用的新特性,详细请参见:ES6入门 - ryf

碎片

var VS let VS const

  • var:声明全局变量,
  • let:声明块级变量,即局部变量
  • const:声明常量,块级作用域,不可修改且必须初始化

将一个对象彻底冻结为常量的方法

var constantize = (obj) => {
// 冻结对象本身
Object.freeze(obj);
// 冻结对象的属性
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};  

ES6声明变量的方法,除上述外,还支持:class、import、function。

Number.isNaN() & Number.isFinite()  

该两者仅对数值有效:

  • Number.isNaN():判断一个数值是否为NaN,利用NaN是唯一不等于自身的值,用于isNaN()判断
  • Number.isFinite():表示某个数值是否为正常的数值(即,非infinity),Infinity、-Infinity、NaN和undefined返回false,其余均返回true

注意与传统的全局方法isFinite()和isNaN()的区别,传统方法先调用Number()将非数值的值转为数值,再进行判断。

同理,Number.parseInt(), Number.parseFloat()优先使用。

新增Number.EPSILON表示极小量,表示 1 与大于 1 的最小浮点数之间的差。

function isTrueWithinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}

新增Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER分别表示安全的极大值和极小值。

Symbol

JS 的第7种数据类型,独一无二的特性:

  • 用于扩展对象属性名
  • 定义常量

提供几个常用方法

  • Symbol()
  • Symbol.for()
  • Symbol.keyfor()

${}

模版字符串(template string)语法,配合反引号``使用

  • 换行
  • 表达式嵌入:占位符(使用 <%...%> 放置 JavaScript 代码,使用 <%= ... %> 输出 JavaScript 表达式。)
  • 支持嵌套

标签模版

函数调用的一种特殊形式:fun`xxx`。

可过滤 HTML 字符串,防止用户输入恶意内容(特殊字符转义)

function toSaferHTML(templateData) {
let s = templateData[0];
for (let i = 1; i < arguments.length; i++) {
let arg = String(arguments[i]); // Escape special characters in the substitution.
s += arg.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">"); // Don't escape special characters in the template.
s += templateData[i];
}
return s;
} let sender = '<script>alert("abc")</script>'; // 恶意代码
let message = toSaferHTML`<p>${sender} has sent you a message.</p>`;
// <p><script>alert("abc")</script> has sent you a message.</p>

注:模板处理函数的第一个参数(模板字符串数组),还有一个 raw 属性,用于保存转义后的原字符串。

支持多语言处理。

...

扩展运算符,基于 for...of,将一个数组转为参数序列,或将实现了 Iterator 接口的对象转化为真正的数组。

  • 取代apply()方法
  • 复制数组(深拷贝)或合并数组(浅拷贝)
  • 配合解构赋值:扩展运算符可以识别四字节的Unicode字符的长度

注意,没有实现 Iterator 接口的对象可以使用Array.from

  • 类似数组的对象:(1)DOM 操作返回的 NodeList 集合;(2)函数内部的arguments对象
  • 可遍历的对象

提供2种字符串长度方法

[1]. [...str].length
[2]. Array.from(str).length 

Object.assign

将源对象(source)的所有可枚举属性,复制到目标对象(target)。(浅拷贝)

  • undefined和null不能作为第一个参数
  • 只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)

使用场景

  • 为对象添加属性/方法
  • 克隆/合并对象
  • 为属性指定默认值

Object.getOwnPropertyDescriptor

获取对象属性的描述对象,其中属性enumerable表示可枚举性。以下只对enumerable=true的对象有效

  • for...in循环:只遍历对象自身的和继承的可枚举的属性
  • Object.keys():返回对象自身的所有可枚举的属性的键名
  • JSON.stringify():只串行化对象自身的可枚举的属性
  • Object.assign(): 忽略enumerablefalse的属性,只拷贝对象自身的可枚举的属性

Object.getOwnPropertyDescriptors

基于Object.getOwnPropertyDescriptor实现,返回指定对象所有自身属性(非继承属性)的描述对象。

  • 解决Object.assign()无法正确拷贝get属性和set属性的问题
  • 配合Object.create方法,将对象属性克隆到一个新对象(浅拷贝)
  • 实现 Mixin(混入)模式
//克隆 方法1
const clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
//方法2
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)),
obj
);

属性遍历

  • for...in
  • Object.keys()
  • Object.getOwnPropertyNames():返回一个数组,包含对象自身的所有属性的键名
  • Object.getOwnPropertySymbols():返回一个数组,包含对象自身的所有 Symbol 属性的键名
  • Reflect.ownKeys():返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举

建议,尽量不要用for...in循环,而用Object.keys()代替。

此外,for...in只能获得对象的键名,不能直接获取键值,而for...of允许遍历获得键值。

Iterator & for...of

为不同的数据结构提供统一的访问机制,任何数据结构只要部署了Iterator接口:

  • 支持遍历(for...of)操作
  • 使用扩展运算符,将其转为数组

本质是:数据结构部署Symbol.iterator属性

遍历器接口(Iterable)、指针对象(Iterator)和next方法返回值的模版描述如下

interface Iterable {
[Symbol.iterator]() : Iterator,
} interface Iterator {
next(value?: any) : IterationResult,
} interface IterationResult {
value: any,
done: boolean,
}

原生具备 Iterator 接口的数据结构:

Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象

默认调用遍历器的场景

  • for...of
  • 解构赋值
  • ...
  • yield*:其后面跟一个可遍历的结构,默认调用该结构的遍历器接口
  • Array.from(),Promise.all/race()

扩展应用

  • String

将遍历器转换为数组,提供2种方法:

[...str.matchAll(regex)]
Array.from(str.matchAll(regex));

其中,matchAll() 用于一次性取出所有匹配结果,返回一个遍历器。  

Set & Map

ES6在原有的集合数据结构(数组Array和对象Object)的基础上,新增MapSet

  • Set:类似数组,值唯一
  • Map:类似(键值对集合的)对象,将"字符串-值"结构的Object扩展到"值-值"结构的Map
  • WeakSet:不可遍历,成员只能是对象
  • WeakMap:不可遍历

很重要:遍历顺序就是插入顺序。支持遍历 for...of 和 forEach。

其中,forEach 方法的

  • 第一个参数回调函数的参数依次为:(value, key, map)
  • 第二个参数用于绑定this,指向某个对象

Set

[1]. 数组去重

function dedupe(array) {
return Array.from(new Set(array));
}

[2]. 交并差集运算

若想改变Set本身,提供如下2种方法

// 方法一:利用原 Set 结构映射出一个新的结构,然后赋值给原来的 Set 结构
let set = new Set([1, 2, 3]);
set = new Set([...set].map(val => val * 2));
// 方法二:利用Array.from方法
let set = new Set([1, 2, 3]);
set = new Set(Array.from(set, val => val * 2));

Map

关于Map与其他数据结构的转换,可参见:http://es6.ruanyifeng.com/#docs/set-map

解构赋值

从数组和对象中提取值,对变量进行赋值:(模式匹配)

  • 只要等号右边的值不是对象或数组,就先将其转为对象
  • 实现了Iterator接口的数据结构,可以采用数组形式的解构赋值
  • 由于undefined和null无法转为对象,所以对其解构赋值,会报错
  • 解构赋值尽量不适用圆括号()

支持默认值,前提是对象的属性值/数组成员严格等于undefined。若数组成员是null,默认值不会生效。

除数组和对象,字符串也支持解构赋值。

应用场景

  • 交换变量的值
  • 从函数返回多个值
  • 函数参数的定义、默认值
  • 提取json数据
  • 利用for...of遍历map结构

[1]. 在函数形参使用解构赋值

// 写法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
  • 写法一:函数参数的默认值是空对象,但是设置了对象解构赋值的默认值
  • 写法二:函数参数的默认值是一个有具体属性的对象,但是没有设置对象解构赋值的默认值

推荐写法一,因为在函数体中实际使用的左边的x和y。 

箭头函数

箭头函数可以让this指向固定化,总是指向函数定义生效时所在的作用域,而不是指向运行时所在的作用域,这种特性很有利于封装回调函数。

s1 = 0;  s2 = 0;
function Timer() {
this.s1 = 0; this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
} var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3200); // 3
setTimeout(() => console.log('s2: ', timer.s2), 3200); // 0
setTimeout(() => console.log('s11: ', this.s1), 3200); // 0
setTimeout(() => console.log('s22: ', this.s2), 3200); // 3

箭头函数自动绑定this,可以减少对this的显式绑定(callapplybind)。

::双冒号运算符(函数绑定运算符),可以用来取代callapplybind调用。

foo::bar(...arguments);  等同于  bar.apply(foo, arguments);  

注意点

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
  • 不可以当作构造函数,即:不可以使用new命令 
  • 不可以使用yield命令,即:箭头函数不能用作 Generator 函数
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替

尾调用 & 尾递归

尾调用:某个函数的最后一步是调用另一个函数

function f(x){
return g(x); //(1)return (2)无其他计算
}

尾递归基于尾调用,相对节省内存,不会发生栈溢出。

相关示例,可参考:阶乘或Fibonacci 数列.

注意,尾调用优化,仅在严格模式下有效。

Proxy & Reflect

Proxy:修改某些操作的默认行为,可以进行数据验证

关于 Proxy 支持的拦截操作,具体参见:http://es6.ruanyifeng.com/#docs/proxy

其中,apply用于拦截如下操作:

  • 函数调用
  • call、apply
  • Reflect.apply

Reflect:将Object对象上的方法迁移到Reflect对象上

关于Reflect对象的方法与Proxy对象的方法一一对应,具体参见:http://es6.ruanyifeng.com/#docs/reflect

建议用 Reflect.xxx 代替 Object.xxx

综上,Proxy 对象和 Reflect 对象联合使用,前者拦截操作,后者完成默认行为。

Promise对象

引出

  • 回调地狱(callback hell)
  • 多个异步回调难以维护和控制的问题

设计思想:所有异步任务都返回一个 Promise 实例。(异步操作同步化)

Promise 实质上是一个构造函数。

var p = new Promise(f1);
p.then(f2);

回调函数f1完成后,执行回调函数f2。(添加状态改变时的回调函数通过then()方法)

Promise 对象通过自身的状态,来控制异步操作。

  • 异步操作未完成(pending)
  • 异步操作成功(fulfilled)
  • 异步操作失败(rejected)

同时,只有异步操作的结果才会改变其状态,Promise 实例的状态变化只可能发生一次:

  • 异步操作成功,Promise 实例传回一个值(value),状态变为 fulfilled
  • 异步操作失败,Promise 实例抛出一个错误(error),状态变为 rejected
// resolve 和 reject 均由 JavaScript 引擎提供,无需自己实现
var p = new Promise(function (resolve, reject) {
// ...
if (/* 异步操作成功 */){
resolve(value);
} else { /* 异步操作失败 */
reject(new Error());
}
});
  • resolve:将Promise实例的状态从“未完成”变为“成功”(pending-->fulfilled),在异步操作成功时调用,并将异步操作的结果作为参数传出
  • reject:将Promise实例的状态从“未完成”变为“失败”(pending-->rejected),在异步操作失败时调用,并将异步操作的错误作为参数传出

注意:

  • Promise 的回调函数属于异步任务,会在同步任务之后执行。
  • Promise 的回调函数不是正常的异步任务,而是微任务(microtask) 

正常任务追加到下一轮事件循环,微任务追加到本轮事件循环。所以,微任务的执行时间一定早于正常任务。

setTimeout(function() {
console.log(1);
}, 0); new Promise(function (resolve, reject) {
resolve(2);
}).then(console.log); console.log(3); // 3 2 1

Promise对象还有其他特性(可以看作是缺点):

  • Promise 对象新建后就会立即执行,无法取消Promise
  • Promise 内部的错误不会影响到 Promise 外部的代码(Promise 会吃掉错误),也可以通过设置回调函数将错误信息抛出
  • 代码冗余,all then()...

静态方法

  • Promise.all():与
  • Promise.race():或
  • Promise.resolve():将现有对象转为立即resolved的Promise对象
  • Promise.reject():返回一个新的Promise实例,该实例的状态为rejected,回调立即执行

Promise.resolve()与Promise.reject()略有不同,Promise.reject()会将参数原封不动地传出。

新的Promise.try()用于统一管理同步和异步代码,统一用promise.catch()捕获所有同步和异步的错误

Promise.try(database.users.get({id: userId}))
.then(...)
.catch(...)

参考:Promise对象ES6 - Promise - ryfeng

Generator函数

遍历器对象生成函数,可以暂停函数执行,返回任意表达式的值

  • function*:
  • yield:产出,暂停标志

调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针,可以通过next()依次遍历Generator函数内部的每一个状态(异步操作的容器)。

  • 异步操作同步化表达
  • 为任意对象部署 Iterator 接口
  • 作为数据结构,提供类似数组的接口
  • 控制流管理:项目拆分成任务,任务拆分成步骤,依次执行
  • 状态机(容器)
  • 协程(coroutine)

注意,返回的遍历器对象,其Symbol.iterator属性是其自身

function* gen(){...}
var g = gen();
g[Symbol.iterator] === g

遍历器对象是Generator函数的实例,继承其原型上的方法,但是this对象无法访问。若想访问:

// 将遍历器对象绑定到Generator函数的原型
var gen = Gen.call(Gen.prototype);  

若想应用new命令,对外封装一层即可

function F() {
return Gen.call(Gen.prototype);
}
// f即遍历器对象
F f = new F();

for...of

支持自动遍历Generator函数时生成的Iterator对象。

注意,不会遍历到return语句,扩展运算符、解构赋值和Array.from()亦是。

利用for...of循环,可以写出遍历任意对象(object)的方法。通过Generator函数为对象加上这个接口

function* objectEntries() {
let propKeys = Object.keys(this); for (let propKey of propKeys) {
yield [propKey, this[propKey]];
}
} let obj= { first: 'Jane', last: 'Doe' };
obj[Symbol.iterator] = objectEntries; for (let [key, value] of objectEntries(obj)) {
console.log(`${key}: ${value}`);
}

重点理解下述3个原型方法:

Generator.prototype.next()

  • next方法可以带一个参数,该参数重写上一个yield表达式的返回值(yield表达式默认无返回值或undefined)
  • 第一次执行next方法,等同于启动执行Generator函数的内部代码

Generator.prototype.throw()

  • Generator函数体内或外抛出的错误gen.throw(),会优先被Generator体内的try...catch捕获
  • 注意遍历器对象的throw()方法和throw命令的不同
  • throw方法抛出的错误要被内部try...catch捕获,前提是必须至少执行过一次next方法,,否则只能被外部try...catch捕获
  • throw方法被捕获后,会附带执行一次next方法,返回下一条yield表达式
  • Generator函数体内的错误未捕获到,会中断Generator函数体内的后续代码 

Generator.prototype.return()

  • 返回给定的值,终结执行Generator函数
  • 优先级低于finally代码块
next(): 将yield表达式替换成一个值
throw(): 将yield表达式替换成一个throw语句
return(): 将yield表达式替换成一个return语句  

yield*

在一个Generator函数A里面执行另一个Generator函数B。

场景:递归

若B中有return语句,通过以下形式获取返回值

var value = yield* B()

异步应用

异步调用方式

  • 发布/订阅(事件监听)
  • 回调函数
  • Promise对象
  • Generator函数:协程

协程

Generator函数是协程在ES6的实现,可以理解为Generator函数是协程的实例

最大特点就是可以交出函数的执行权(暂停函数执行和恢复执行)

  • 函数体内、外的数据交换
  • 错误处理机制

自动执行机制:接收和交还程序的执行权(当异步操作有了结果,自动交回执行权)

  • 回调函数:将异步操作包装成 Thunk 函数,在回调函数里面交回执行权
  • Promise对象:将异步操作包装成 Promise 对象,用then方法交回执行权

Thunk函数

自动执行Generator函数的一种方法。

  • yield:将程序的执行权移出 Generator 函数
  • thunk:将执行权交还给 Generator 函数

懒执行,传名调用的实现策略,用临时函数(Thunk函数)替换某个表达式。在JavaScript中,是将多参数(某个参数是回调函数)函数fn,替换成一个只接受回调函数作为参数的单参数函数。

// Thunk函数转换器
const Thunk = function(fn) {
return function (...args) {
return function (callback) {
return fn.call(this, ...args, callback);
}
};
};  

提供Thunk函数转换工具:Thunkify 模块

无需编写Generator函数的自动执行器,而且其检查机制,确保回调函数只运行一次。使用前提是Generator函数的yield命令后面,只能是Thunk函数。

// 引入
var thunkify = require('thunkify');
// 转换
var thunkFun= thunkify(fn);

co模块

自动执行Generator函数的另一种方法,基于Promise对象的自动执行器。

co函数接收Generator函数作为参数,返回Promise对象,支持then方法执行回调函数。

// 引入
var co = require('co');
// 自动执行
co(gen).then(...);

本质上封装了两种自动执行器(Thunk 函数和 Promise 对象),使用 co 的前提条件是,Generator函数的yield命令后面,只能是 Thunk 函数或 Promise 对象。 

而且,co函数支持并发操作:把并发的操作放在数组或对象里,跟在yield命令后面

参考 :Generator - ruanyifeng

以上,使Generator支持异步操作,即yield命令后是异步方法,则:该方法只能返回一个Thunk函数或者一个Promise对象。

async函数

  • async:表示函数里有异步操作
  • await:表示紧跟在后面的表达式需要等待结果

Generator函数的语法糖:对Generator函数和自动执行器的封装

相比Generator函数:( *和yield --> async和await )

  • 内置(自动)执行器
  • 立即返回Promise对象,支持then方法执行回调函数。
  • 语义清晰,适应性广

async函数可以看作是将多个异步操作封装成一个Promise对象,await命令是内部then()方法的语法糖。

关于3者的比较,可参见:async函数-5

务必注意,不能在普通函数中使用await。但是 esm 模块加载器支持顶层await,即await命令可以不放在async函数里面,直接使用

// 顶层 await 的写法
const res = await fetch('google.com');
console.log(await res.text()); 

常见形式:

// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 箭头函数
const foo = async () => {}; // 对象的方法
let obj = {
async foo() {}
};
obj.foo().then(...) // Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jake').then(…);

错误处理机制

async函数内部抛出错误,会导致返回的Promise对象变为reject状态,同时中断async函数的执行,若不中断:

  • try...catch
  • await Promise(...).catch()

抛出的错误对象会被catch方法回调函数接收到。

并发

互不影响相互独立的2个异步操作同时执行

let [foo, bar] = await Promise.all([getFoo(), getBar()]);

场景:并发拉数据

async function pullDataFeomUrl(urls) {
// 并发读取远程URL
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
}); // 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}

异步遍历器(Async Iterator)

es2018引入,为异步操作提供原生的遍历器接口:异步返回value和done

特点:异步遍历器的next()方法返回一个Promise对象。

类似对象的同步遍历器部署Symbol.iterator属性,支持for...of,对象的异步遍历器部署Symbol.asynciterator属性,支持for await...of。

即,可遍历对象的Symbol.asynciterator属性返回一个异步Generator函数

const asyncIterator = asyncIterable[Symbol.asyncIterator]();  

注意,for await...of循环也可以用于同步遍历器。

异步遍历器重要的是:可以接近相同的方式处理同步操作和异步操作。

// 同步Generator函数
function* map(iterable, func) {
const iter = iterable[Symbol.iterator]();
while (true) {
const {value, done} = iter.next();
if (done) break;
yield func(value);
}
} // 异步Generator函数
async function* map(iterable, func) {
const iter = iterable[Symbol.asyncIterator]();
while (true) {
const {value, done} = await iter.next();
if (done) break;
yield func(value);
}
}

异步Generator函数

async函数与Generator函数的结合

  • await:用于将外部操作产生的值输入函数内部
  • yield:用于将函数内部的值输出

Generator函数返回同步遍历器对象,异步Generator函数返回异步遍历器对象。

JS - ECMAScript2015(ES6)新特性的更多相关文章

  1. Atitit js es5 es6新特性 attilax总结

    Atitit js es5 es6新特性 attilax总结 1.1. JavaScript发展时间轴:1 1.2. 以下是ES6排名前十的最佳特性列表(排名不分先后):1 1.3. Es6 支持情况 ...

  2. Atitit js版本es5 es6新特性

    Atitit js版本es5 es6新特性 Es5( es5 其实就是adobe action script的标准化)1 es6新特性1 Es5( es5 其实就是adobe action scrip ...

  3. 必须掌握的ES6新特性

    ES6(ECMAScript2015)的出现,让前端开发者收到一份惊喜,它简洁的新语法.强大的新特性,带给我们更便捷和顺畅的编码体验,赞! 以下是ES6排名前十的最佳特性列表(排名不分先后): 1.D ...

  4. ES6新特性概览

    本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony( ...

  5. 轻松学会ES6新特性之生成器

    生成器虽然是ES6最具魔性的新特性,但也是最难懂得的一节,笔者写了大量的实例来具体化这种抽象的概念,能够让人一看就懂,目的是希望别人不要重复或者减少笔者学习生成器的痛苦经历. 在说具体的ES6生成器之 ...

  6. 你不知道的JavaScript--Item24 ES6新特性概览

    ES6新特性概览 本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代 ...

  7. 前端入门21-JavaScript的ES6新特性

    声明 本篇内容全部摘自阮一峰的:ECMAScript 6 入门 阮一峰的这本书,我个人觉得写得挺好的,不管是描述方面,还是例子,都讲得挺通俗易懂,每个新特性基本都还会跟 ES5 旧标准做比较,说明为什 ...

  8. 34.js----JS 开发者必须知道的十个 ES6 新特性

    JS 开发者必须知道的十个 ES6 新特性 这是为忙碌的开发者准备的ES6中最棒的十个特性(无特定顺序): 默认参数 模版表达式 多行字符串 拆包表达式 改进的对象表达式 箭头函数 =&> ...

  9. ES6新特性概览1

    本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony( ...

  10. 【微信小程序+ES6新特性应用】字符串模板:美元符号$+大括号{}变量的写法

    1.字符串模板简介 ES6新特性中的字符串模板允许使用英文字符抑音符号`(提示:这里我们不能将其理解为单引号)来创建字符串,并且在该字符串中可以包含都[美元符号+大括号]包裹的变量 格式:consol ...

随机推荐

  1. DB2 like两个表的字段或like一个变量

    DB2中的like的使用是有限制的,它后面不能跟一个变量或者是字段,因此,在存储过程或SQL语句中就不能like一个变量或一个字段. 比如有两个表A(a,b,c,d),B(a,b,c,d). 普遍的用 ...

  2. Mybatis之拦截器原理(jdk动态代理优化版本)

    在介绍Mybatis拦截器代码之前,我们先研究下jdk自带的动态代理及优化 其实动态代理也是一种设计模式...优于静态代理,同时动态代理我知道的有两种,一种是面向接口的jdk的代理,第二种是基于第三方 ...

  3. 项目UML设计

    团队信息 队名:火箭少男100 本次作业课上成员 短学号 名 本次作业博客链接 2507 俞辛(临时队长) https://www.cnblogs.com/multhree/p/9821080.htm ...

  4. KbmMW 4.5 发布

    We are happy to announce the release of kbmMW v. 4.50.00 Professional, Enterprise and CodeGear Editi ...

  5. 服务器的日志一直报Packet for query is too large (7632997 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable.的解决方法

    服务器的日志一直报Packet for query is too large (7632997 > 4194304). You can change this value on the serv ...

  6. java中File的delete和deleteOnExit区别(转)

    Java的File类中有两个delete方法:delete和deleteOnExit delete无需解释,为直接删除,deleteOnExit文档解释为:在虚拟机终止时,请求删除此抽象路径名表示的文 ...

  7. C++中的数组问题

    C++中的数组问题 1. 数组赋值与初始化 (1)直接初始化: ]={,,}: (2)遍历访问初始化: ;i< ;i++) //直接读入,或者用别的数组,以及别的(i+1)等. (3)内存操作函 ...

  8. 图片捕获工具driftnet

    driftnet是一款简单而使用的图片捕获工具,可以很方便的在网络数据包中抓取图片.该工具可以实时和离线捕获指定数据包中是图片,当然在kali里是有的. 在我之前的一篇博文<kali下搭建WiF ...

  9. inline函数的作用

    (一)inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联. inline int min(int first, int ...

  10. 【转】【译】【Win10】在你的程序标题栏中显示后退按钮

    原文地址:http://www.sharpgis.net/post/2015/05/21/Displaying-a-backbutton-in-your-app-window 免责声明:这篇文章基于 ...