字符串常用技巧

时间对比:时间个位数形式需补0

const time1 = "2019-03-31 21:00:00";
const time2 = "2019-05-01 09:00:00";
const overtime = time1 > time2;
// overtime => false

替换图片的class类正则

let reg = /(<\s*img[^>]*)class[=\s\"\']+[^\"\']*[\"\']?([^>]*>)/gi;

格式化金钱

const ThousandNum = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const money = ThousandNum(19941112);
// money => "19,941,112"

生成随机ID

const RandomId = len => Math.random().toString(36).substr(3, len);
const id = RandomId(10);
// id => "jg7zpgiqva"

操作URL查询参数

const params = new URLSearchParams(location.search.replace(/\?/ig, "")); // location.search = "?name=yajun&sex=female"
params.has("yajun"); // true
params.get("sex"); // "female"

Number常用技巧

取整:代替正数的Math.floor(),代替负数的Math.ceil()

const num1 = ~~ 1.69;
const num2 = 1.69 | 0;
const num3 = 1.69 >> 0;
// num1 num2 num3 => 1 1 1

补零

const FillZero = (num, len) => num.toString().padStart(len, "0");
const num = FillZero(169, 5);
// num => "00169"

转数值::只对null、""、false、数值字符串有效

const num1 = +null;
const num2 = +"";
const num3 = +false;
const num4 = +"169";
// num1 num2 num3 num4 => 0 0 0 169

时间戳

const timestamp = +new Date("2019-03-31");
// timestamp => 1553990400000

精确小数

const RoundNum = (num, decimal) => Math.round(num * 10 ** decimal) / 10 ** decimal;
const num = RoundNum(1.69, 1);
// num => 1.7

判断奇偶

const OddEven = num => !!(num & 1) ? "odd" : "even";
const num = OddEven(2);
// num => "even"

取最小最大值

const arr = [0, 1, 2];
const min = Math.min(...arr);
const max = Math.max(...arr);
// min max => 0 2

生成范围随机数

const RandomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
const num = RandomNum(1, 10);

Boolean常用技巧

短路运算符

const a = d && 1; // 满足条件赋值:取假运算,从左到右依次判断,遇到假值返回假值,后面不再执行,否则返回最后一个真值
const b = d || 1; // 默认赋值:取真运算,从左到右依次判断,遇到真值返回真值,后面不再执行,否则返回最后一个假值
const c = !d; // 取假赋值:单个表达式转换为true则返回false,否则返回true

判断数据类型:undefined、null、string、number、boolean、array、object、symbol、date、regexp、function、asyncfunction、arguments、set、map、weakset、weakmap

function DataType(tgt, type) {const dataType = Object.prototype.toString.call(tgt).replace(/\[object /g, "").replace(/\]/g, "").toLowerCase();return type ? dataType === type : dataType;
}
DataType("yajun"); // "string"
DataType(19941112); // "number"
DataType(true); // "boolean"
DataType([], "array"); // true
DataType({}, "array"); // false

是否为空数组

const arr = [];
const flag = Array.isArray(arr) && !arr.length;
// flag => true

是否为空对象

const obj = {};
const flag = DataType(obj, "object") && !Object.keys(obj).length;
// flag => true

Array常用技巧

克隆数组

const _arr = [0, 1, 2];
const arr = [..._arr];
// arr => [0, 1, 2]

合并数组

const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const arr = [...arr1, ...arr2];
// arr => [0, 1, 2, 3, 4, 5];

去重数组

const arr = [...new Set([0, 1, 1, null, null])];
// arr => [0, 1, null]

混淆数组

const arr = [0, 1, 2, 3, 4, 5].slice().sort(() => Math.random() - .5);
// arr => [3, 4, 0, 5, 1, 2]

清空数组

const arr = [0, 1, 2];
arr.length = 0;
// arr => []

截断数组

const arr = [0, 1, 2];
arr.length = 2;
// arr => [0, 1]

交换赋值

let a = 0;
let b = 1;
[a, b] = [b, a];
// a b => 1 0

过滤空值:undefined、null、""、0、false、NaN

const arr = [undefined, null, "", 0, false, NaN, 1, 2].filter(Boolean);
// arr => [1, 2]

解构数组成员嵌套

const arr = [0, 1, [2, 3, [4, 5]]];
const [a, b, [c, d, [e, f]]] = arr;
// a b c d e f => 0 1 2 3 4 5

解构数组成员别名

const arr = [0, 1, 2];
const { 0: a, 1: b, 2: c } = arr;
// a b c => 0 1 2

Object常用技巧

克隆对象

const _obj = { a: 0, b: 1, c: 2 }; // 以下方法任选一种
const obj = { ..._obj };
const obj = JSON.parse(JSON.stringify(_obj));
// obj => { a: 0, b: 1, c: 2 }

合并对象

const obj1 = { a: 0, b: 1, c: 2 };
const obj2 = { c: 3, d: 4, e: 5 };
const obj = { ...obj1, ...obj2 };
// obj => { a: 0, b: 1, c: 3, d: 4, e: 5 }

对象变量属性

const flag = false;
const obj = {a: 0,b: 1,[flag ? "c" : "d"]: 2
};
// obj => { a: 0, b: 1, d: 2 }

删除对象无用属性

const obj = { a: 0, b: 1, c: 2 }; // 只想拿b和c
const { a, ...rest } = obj;
// rest => { b: 1, c: 2 }

解构对象属性嵌套

const obj = { a: 0, b: 1, c: { d: 2, e: 3 } };
const { c: { d, e } } = obj;
// d e => 2 3

解构对象属性默认值

const obj = { a: 0, b: 1, c: 2 };
const { a, b = 2, d = 3 } = obj;
// a b d => 0 1 3

js数组去重

function unique1(array){             var n=[]; //一个新的临时数组             //遍历当前数组             for(var i=0;i<array.length;i++){              //如果当前数组的第i已经保存进了临时数组,那么跳过, 否则把当前项push到临时数组里面                     if(n.indexOf(array[i])==-1) n.push(array[i]);             }             return n;
}

数组偏平化处理

var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];var b = arr.toString().split(",").sort((a,b) => { return a - b}).map(Number)

ES6 flat

  function flat5 (arr=[]) {// flat() 方法会移除数组中的空项return arr.flat(Infinity)}flat5(arr) // [1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12, 13, 14, 10]

js书写的几条基本规范

  • 不要在同一行声明多个变量。
  • 请使用 ===/!==来比较true/false或者数值
  • 不要使用全局函数。
  • Switch语句必须带有default分支
  • 函数不应该有时候有返回值,有时候没有返回值。
  • For循环必须使用大括号
  • If语句必须使用大括号
  • for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。

JS基本类型和引用类型的区别?

基本类型: undefined,boolean,number,string,null,symbol(ES6)

引用类型:object,arrary,date,RegExp(正则),Function

基本数据类型是简单的数据段。

引用类型是由多个值构成的对象,其实都是Object的实例。

基本类型可以直接访问,而引用类型的访问是按照对象在内存中的地址,再按照地址去获取对象的值,叫做引用访问。

当从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的对象的值复制一份放到为新变量分配的空间中。前面讲引用类型的时候提到,

保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后,

两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响,从而引发了对象的深拷贝和浅拷贝的问题。

柯理化函数

在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。所谓柯里化就是把具有较多参数的函数转换成具有较少参数的函数的过程。
举个例子

//普通函数
function fn(a, b, c, d, e) {console.log(a, b, c, d, e)
}
//生成的柯里化函数
let _fn = curry(fn)_fn(1, 2, 3, 4, 5) // print: 1,2,3,4,5
_fn(1)(2)(3, 4, 5) // print: 1,2,3,4,5
_fn(1, 2)(3, 4)(5) // print: 1,2,3,4,5
_fn(1)(2)(3)(4)(5) // print: 1,2,3,4,5

柯理化函数的实现

function add () {let x=0;for(let i=0;i<arguments.length;i++){x+=arguments[i];}return x;
}// 对求和函数做curry化
let f1 = curry(add, 1, 2, 3)
console.log('复杂版', f1()) // 6// 对求和函数做curry化
let f2 = curry(add, 1, 2)
console.log('复杂版', f2(3)) // 6// 对求和函数做curry化
let f3 = curry(add)
console.log('复杂版', f3(1, 2, 3)) // 6// 复杂版curry函数可以多次调用,如下:
console.log('复杂版', f3(1)(2)(3)) // 6
console.log('复杂版', f3(1, 2)(3)) // 6
console.log('复杂版', f3(1)(2, 3)) // 6// 复杂版(每次可传入不定数量的参数,当所传参数总数不少于函数的形参总数时,才会执行)
function curry(fn) {// 闭包// 缓存除函数fn之外的所有参数let args = Array.prototype.slice.call(arguments, 1)return function() {// 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)let newArgs = args.concat(Array.from(arguments))if (newArgs.length < fn.length) {// 累积的参数总数少于fn形参总数// 递归传入fn和已累积的参数return curry.call(this, fn, ...newArgs)} else {// 调用return fn.apply(this, newArgs)}}
}

柯里化的用途

function checkByRegExp(regExp, string) {return regExp.test(string)
}checkByRegExp(/^1\d{10}$/, '18642838455') // 校验电话号码
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@163.com') // 校验邮箱

我们每次进行校验的时候都需要输入一串正则,再校验同一类型的数据时,相同的正则我们需要写多次, 这就导致我们在使用的时候效率低下,并且由于 checkByRegExp 函数本身是一个工具函数并没有任何意义。此时,我们可以借助柯里化对 checkByRegExp 函数进行封装,以简化代码书写,提高代码可读性。

//进行柯里化
let _check = curry(checkByRegExp)
//生成工具函数,验证电话号码
let checkCellPhone = _check(/^1\d{10}$/)
//生成工具函数,验证邮箱
let checkEmail = _check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/)checkCellPhone('18642838455') // 校验电话号码
checkCellPhone('13109840560') // 校验电话号码
checkCellPhone('13204061212') // 校验电话号码checkEmail('test@163.com') // 校验邮箱
checkEmail('test@qq.com') // 校验邮箱
checkEmail('test@gmail.com') // 校验邮箱

compose 函数

compose 就是组合函数,将子函数串联起来执行,一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行,会像多米诺骨牌一样推导执行后续函数。

const greeting = name => `Hello ${name}`
const toUpper = str => str.toUpperCase()toUpper(greeting('Onion')) // HELLO ONION

compose 函数的特点

  • compose 接受函数作为参数,从右向左执行,返回类型函数
  • fn()全部参数传给最右边的函数,得到结果后传给倒数第二个,依次传递
var compose = function(...args) {var len = args.length // args函数的个数var count = len - 1var resultreturn function func(...args1) {// func函数的args1参数枚举result = args[count].call(this, args1)if (count > 0) {count--return func.call(null, result) // result 上一个函数的返回结果} else {//回复count初始状态count = len - 1return result}}
}

举个例子

var greeting = (name) =>  `Hello ${name}`
var toUpper = str => str.toUpperCase()
var fn = compose(toUpper, greeting)
console.log(fn('jack'))

大家熟悉的 webpack 里面的 loader 执行顺序是从右到左,是因为webpack 选择的是 compose 方式,从右到左依次执行 loader,每个 loader 是一个函数。

rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]

如上,webpack 使用了 style-loader 和 css-loader,它是先用 css-loader 加载.css 文件,然后 style-loader 将内部样式注入到我们的 html 页面。
webpack 里面的 compose 代码如下:

const compose = (...fns) => {return fns.reduce((prevFn, nextFn) => {return value =>prevFn(nextFn(value)) },value => value)
}

尾调用和尾递归

尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚。就是指某个函数的最后一步是调用另一个函数。

function g(x) {console.log(x)
}
function f(x) {return g(x)
}
console.log(f(1))
//上面代码中,函数f的最后一步是调用函数g,这就是尾调用。

上面代码中,函数 f 的最后一步是调用函数 g,这就是尾调用。尾调用不一定出现在函数尾部,只要是最后一步操作即可。
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生栈溢出错误。但是队伍尾递归来说,由于只存在一个调用帧,所以永远不会发生栈溢出错误。

function factorial(n) {if (n === 1) {return 1}return n * factorial(n - 1)
}

上面代码是一个阶乘函数,计算 n 的阶乘,最多需要保存 n 个调用数据,复杂度为 function(n),如果改写成尾调用,只保留一个调用记录,复杂度为 function(1)。简单来说 每次的返回结果 n * factorial(n - 1) 都会被缓存在内存中,以便于下次递归时候使用,而缓存函数,浏览器就会自动开辟内存空间。而下面这种写法,函数执行后的结果,函数执行过后则会自动销毁。

function factor(n, total = 1) {if (n === 1) {return total}return factor(n - 1, n * total)
}

最经典的例子则是斐波拉切数列的尾调用。

function Fibonacci(n) {if (n <= 1) {return 1}return Fibonacci(n - 1) + Fibonacci(n - 2)
}
//尾递归
function Fibona(n, ac1 = 1, ac2 = 1) {if (n <= 1) {return ac2}return Fibona(n - 1, ac2, ac1 + ac2)
}

函数防抖和节流

1. 函数防抖

  • 非立即执行版 (非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。)
function debounce(func, wait) {let timeout;return function () {let context = this;let args = arguments;if (timeout) clearTimeout(timeout);      timeout = setTimeout(() => {func.apply(context, args)}, wait);}
}
  • 立即执行版(立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果)
function debounce(func,wait) {let timeout;return function () {let context = this;let args = arguments;if (timeout) clearTimeout(timeout);let callNow = !timeout;timeout = setTimeout(() => {timeout = null;}, wait)if (callNow) func.apply(context, args)}
}

2.函数节流 (使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。)

  • 时间戳版
function throttle(func, wait) {let previous = 0;return function() {let now = Date.now();let context = this;let args = arguments;if (now - previous > wait) {func.apply(context, args);previous = now;}}
}
  • 定时器版
function throttle(func, wait) {let timeout;return function() {let context = this;let args = arguments;if (!timeout) {timeout = setTimeout(() => {timeout = null;func.apply(context, args)}, wait)}}
}

常见算法

1.全排列

function permutate(str) {var array = str.split('');function loop(array, pre = []) {if (array.length == 1) {return [pre.concat(array).join('')];}let res = [];for (let index = 0; index < array.length; index++) {var first = array.pop();res = res.concat(loop(array, [...pre, first]));array.unshift(first);}return res;}return Array.from(new Set(loop(array)))
}

2.二分搜索

function BinarySearch1 (arr, target) {return search(arr, target, 0, arr.length - 1)function search (arr, target, from, to) {if (from > to) {return -1}const mid = Math.floor((from + to)/2)if (arr[mid] > target) {return search(arr, target, from, mid - 1)} else if (arr[mid] < target) {return search(arr, target, mid + 1, to)} else {return mid}}
}
function BinarySearch2 (arr, target) {let from = 0let to = arr.length - 1let mid = Math.floor((from + to)/2)while (from <= to) {mid = Math.floor((from + to)/2)if (arr[mid] > target) {to = mid - 1} else if (arr[mid] < target) {from = mid + 1} else {return mid}}return -1
}
console.log(BinarySearch1([1,2,3,4,5,6,7,8,9],5)) // 4
console.log(BinarySearch2([1,2,3,4,5,6,7,8,9],3)) // 2

3.冒泡排序

function BubbleSort (arr) {const length = arr.lengthfor (let i = 0; i < length; i++) {for (let j = 1; j < length-i; j++) {if (arr[j] < arr[j - 1]) {const temp = arr[j]arr[j] = arr[j - 1]arr[j - 1] = temp}}}return arr
}

4.选择排序

function SelectionSort (arr) {const length = arr.lengthfor (let i = 0; i < length; i++ ) {let minIndex= ifor (let j = i + 1; j < length; j++) {minIndex = arr[minIndex] <= arr[j] ? minIndex : j}if (minIndex !== i) {const temp = arr[i]arr[i] = arr[minIndex]arr[minIndex] = temp}}return arr
}

5.插入排序

function InsertionSort (arr) {const length = arr.lengthfor (let i = 1; i < length; i++) {const temp = arr[i]let jfor (j = i - 1; j >= 0 && temp < arr[j]; j--) {arr[j+1] = arr[j]}arr[j+1] = temp}return arr
}

6.希尔排序


function ShellSort (arr) {const length = arr.lengthlet gap = Math.floor(length)while (gap) {for (let i = gap; i < length; i++) {const temp = arr[i]let jfor (j = i - gap; j >= 0 && temp < arr[j]; j = j - gap) {arr[j + gap] = arr[j]}arr[j + gap] = temp}gap = Math.floor(gap / 2)}return arr
}

7.归并排序

function MergeSort (arr, low, high) {const length = arr.lengthif (low === high) {return arr[low]}const mid = Math.floor((low + high)/2)MergeSort(arr, low, mid)MergeSort(arr, mid + 1, high)merge(arr, low, high)return arr}function merge (arr, low, high) {const mid = Math.floor((low + high)/2)let left = lowlet right = mid + 1const result = []while (left <= mid && right <= high) {if (arr[left] <= arr[right]) {result.push(arr[left++])} else {result.push(arr[right++])}}while (left <= mid) {result.push(arr[left++])}while (right <= high) {result.push(arr[right++])}arr.splice(low, high-low+1, ...result)
}const test = [2, 34, 452,3,5, 785, 32, 345, 567, 322,5]
console.log(MergeSort(test, 0, test.length - 1))

8.堆排序

function HeapSort (arr) {const length = arr.length// 调整初始堆,调整完其实也确定了最大值// 但此时最大值是在 arr[0] 中for (let i = Math.floor(length/2) - 1; i >= 0; i--) {adjustHeap(arr, i, length)}// 把 arr[0](最大值)换到后面for (let i = length - 1; i >=0; i--) {const temp = arr[0]arr[0] = arr[i]arr[i] = tempadjustHeap(arr, 0, i)}return arr
}// size 是还需要调整的堆的大小
// 随着一个个最大值的确定,size 会越来越小
function adjustHeap (arr, position, size) {const left = position * 2 + 1const right = left + 1let maxIndex = positionif (left < size && arr[left] > arr[maxIndex]) {maxIndex = left}if (right < size && arr[right] > arr[maxIndex]) {maxIndex = right}if (maxIndex !== position) {const temp = arr[position]arr[position] = arr[maxIndex]arr[maxIndex] = tempadjustHeap(arr, maxIndex, size)}return arr
}

数组去重es5的高阶写法

var array = [{value: 1}, {value: 1}, {value: 2}];function unique(array) {var obj = {};return array.filter(function(item, index, array){console.log(typeof item + JSON.stringify(item))return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true)})
}console.log(unique(array)); // [{value: 1}, {value: 2}]

数组去重es6的几种写法

function unique(array) {return Array.from(new Set(array));
}function unique(array) {return [...new Set(array)];
}function unique (arr) {const seen = new Map()return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}

js 常用的开发技巧相关推荐

  1. 【js 常用的开发技巧】

    字符串常用技巧 时间对比:时间个位数形式需补0 const time1 = "2019-03-31 21:00:00"; const time2 = "2019-05-0 ...

  2. 微信小程序-常用API开发技巧学习笔记

    常用API开发技巧学习笔记 第一章 认识微信小程序 前后端分离的开发方式 小程序的特点 小程序对开发者的影响 学习小程序需要的基础 第二章 小程序环境搭建与开发工具介绍 小程序开发环境 没有小程序号对 ...

  3. 社区说|常用 Android 开发技巧

    活动时间 4月7日(本周四) 20:00-21:00 活动日程 20:00-20:45 主题分享 常用 Android 开发技巧 李老师的开发技巧私房菜,一定有你没吃过的菜! 重构技巧 常用插件 阅读 ...

  4. 常用安卓开发技巧汇总

    经常用的一些小技巧都会记录在这边 API权限错误提示解决方法: 报这么一个错误: Call requires API level 11 (current min is 8): android.anim ...

  5. # 后端开发技巧、常用规范

    后端开发技巧.常用规范 开发技巧 equals() 方法的使用 null.equals()会出报空指针,因该是非null的值.equals() 可以使用Objects的equals()方法避免空值,完 ...

  6. javascript开发技巧训练_学好这些小技巧,帮你写出更好地JavaScript

    近几年来随着前端发展的日益成熟,JavaScript的日渐受到重视,以及Node.js方案变得越来越可行,我们对JavaScript程序员的需求也正在持续增长. 图片源自网络,仅做配文展示 从需求比例 ...

  7. js 数组过滤_JS之 开发技巧

    阅读本文约需要6分钟 大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈).上次老师跟大家分享了JS之 动画库的知识,今天跟大家分享下JS之 开发技巧的 ...

  8. Expression Blend实战开发技巧 第四章 从最常用ButtonStyle开始 - PathButton

    本文来自 烤地瓜 的博客,原文地址:http://www.cnblogs.com/kaodigua/archive/2011/02/15/1955472.html [全面解禁!真正的Expressio ...

  9. Go 学习笔记(83)— 编码规范及常用开发技巧

    UBER 开源的 Go 语言开发规范 1. 规范指南 1.1 包名 package 的命名应该遵循如下原则: 只由小写字母组成.不包含大写字母和下划线等字符: 简短并包含一定的上下文信息.例如 tim ...

最新文章

  1. 公司间STO的Invoice处理
  2. 常用事件方法及技巧(二) -- MouseEvent(鼠标事件)
  3. 单片机实验:外部中断按键
  4. iOS事件拦截(实现触摸任意位置隐藏指定view)
  5. [转载] python strptime函数转时间数组_python—时间与时间戳之间的转换
  6. 中国ai人工智能发展太快_中国的AI:开放采购和幕后玩家
  7. galton板matlab,Matlab实现Galton板的动画演示
  8. (附源码)APP+spring boot心理健康线上咨询系统 毕业设计 031539
  9. 《那些年啊,那些事——一个程序员的奋斗史》——113
  10. JAVA-循序结构、选择结构
  11. 九爷带你 查看linux所有正在运行的进程
  12. Excel数据导出图片
  13. LeetCode 题解随笔:贪心算法
  14. spring框架xml的几种配置方式
  15. 什么是CISAW认证?有什么价值?
  16. JQuery处理json数据实例(map和数组)
  17. 租房微信小程序--基于微信云开发--小程序端集成了管理员后台
  18. 微信域名拦截检测API源码 检测域名是否能在微信正常打开
  19. js伪数组和数组的区别
  20. java 获得两个时间段差距:时分秒,两个时间相差距离多少天多少小时多少分多少秒

热门文章

  1. 2010年:传统ERP丧钟响起
  2. 中国的植被覆盖度数据获取方法
  3. RHCSA笔记(1)
  4. sql添加字段并加备注、默认值
  5. CHARINDEX作用
  6. linux远程桌面连接_如何从Linux连接到远程桌面
  7. 郑州哪家土豆粉最好吃
  8. cad中直径符号不显示_CAD字体不显示怎么解决?
  9. eclipse配置Tomcat
  10. linux mkfs fat32,创建文件系统的mkfs