1. Modules Import/Export
    1. Export anonymous function
  2. 快速生成等差数组
  3. 位运算
  4. Array Flaten/DuplicateRemoval/Sort
    1. 一位数组去重
    2. 多维数组去重
    3. ES5 备选方法
  5. Module Pattern
    1. 几种变体
    2. Named Function & Anonymous Function
  6. Lodash Template with condition
  7. .match()
  8. .replace()
  9. .slice()
    1. 获取数组的最后一个 elem
    2. 移除特定 elem
  10. .fetch()
  11. ajax with serialized form
  12. Deep Clone
  13. Reduce
    1. Example
  14. Datatable
    1. Datatable 自定义 Excel/Print 输出 Column
    2. Datatable 额外筛选条件 & 绑定额外 filter
    3. Datatable 获取当前页数 & 获取总页数 & 跳转到特定页
    4. Datatable 限定特定行 允许/不允许 排序
    5. Datatable 监听每一次刷新表格
  15. Object.assign()
  16. Javascript: Select2 多选的实现
    1. Datatable 输出 Excel 时添加额外行
  17. 关于 Element.onclick
  18. 动态提交 Form
  19. 进制转换
  20. eval()
    1. 实例
    2. 实例 2
  21. 键盘事件监听
  22. Console 的特殊用法
  23. Single Linked List Reverse
    1. 分析流程

Modules Import/Export

Export 基本语法:

  1. 可以暴露一个已经声明的变量, 类或者函数
  2. 可以暴露一个立刻声明的变量。
var name = "xxx";
export {
  name
}
/*
  // 效果相同
  export var name="xxx";
*/
……

import {
  name
} from "/xxx"
var name1 = "xxx";
var name2 = "yyy";
export {
  name1,
  name2
}

/*
  // 效果相同
  export name1; 
  export name2; 
*/

……

import {
  name1 as x1,
  names as x2
} from "/xxx"
const getdata = () => {
  ……
}
export default getdata;
// 一个文件中 default 只能使用一次。

……

import getdata from './XXX'
// 特别注意这个地方没有花括号

Export anonymous function

Default is required due to anonymous export

export default () => console.log("say hello");

……

import str as XXX from 'demo1' //导入的时候没有花括号

快速生成等差数组

[……Array(10).keys()];
// 生成 0-9

[……Array(10).keys()].map(e => e + (new Date).getFullYear())
// 如果需要其他数组就 map 一下
// 这个例子生成了当前年份前后 5 年的数字

位运算

请注意 位运算适用于 32 位整数, 所以精度可能会丢失

  • 用 "|" 取整
let num = 1.5
num = num | 0 // 1

  • 用 ">>" 取半
let num = 4
num = num >> 1 // 2

  • 用 ">>" 加倍
let num=2;
num=num<<1; / / 4

  • 用 "^" 两值交换
let a = 1
let b = 2

a ^= b
b ^= a
a ^= b
// a===2,b===1

  • 用 "&" 判断奇数
let n = 3
let m = 4
n & (1 === 1) // true 奇数
m & (1 === 1) // false 偶数
  • 用 "~" 判断项是否存在
let firstname = 'Ma'
let fullname = 'Jack Ma'
let isExist = !!~fullname.indexOf(firstname) // true

Array Flaten/DuplicateRemoval/Sort

一位数组去重

ES6

[……new Set([1, 1, 2, 2, 3, 3])]
// 首先是 Set 去重, Set 的结果是一个 Obj
// 注意 Set 使用时需要关键字 new
// 然后使用 spread operator 展开

多维数组去重

数组平化, 去重, 排序

var arr = [
  [1, 2, 2],
  [3, 4, 5, 5],
  [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10
];

Array.from(new Set(arr.flat(Infinity))).sort((a, b) => {
  return a - b
})

// 或者使用 spread operator

[……new Set(arr.flat(Infinity))].sort((a, b) => {
  return a - b
})

// arr.flat(Infinity) 无限层扁平化, 多维数组全部变为一维数组
// Array.from(new Set(arr)) 传递数组给 Set
// 最后排序

ES5 备选方法

ES5 使用对象属性单一性

function distinct(a, b) {
  let arr = a.concat(b) // 先将两个数组拼起来
  let result = []
  let obj = {}

  for (let i of arr) {
    if (!obj[i]) { // 如果数组里面没有这个元素
      result.push(i)
      obj[i] = 1
    }
  }

  return result
}

Module Pattern

var myModule = (function() {
  'use strict';

  var _privateProperty = 'Hello World';
  var publicProperty = 'I am a public property';

  function _privateMethod() {
    console.log(_privateProperty);
  }

  function publicMethod() {
    _privateMethod();
  }

  return {
    publicMethod: publicMethod,
    publicProperty: publicProperty
  };
}());

/* private 和 public 的区别就在于是否返回了出来 */

console.log(myModule.publicProperty);
// outputs 'I am a public property'
console.log(myModule._privateProperty);
// is undefined protected by the module closure

myModule._privateMethod();
// is TypeError protected by the module closure
myModule.publicMethod();
// outputs 'Hello World'

几种变体

传递参数

var myModule = (function(args) {

  /* 将参数传递进去 */

}(……args……));

Named Function & Anonymous Function

var myModule = (function() {

  var privateField = 12345;

  function _privateMethod() {
    /* 可以访问到 privateField */
  }

  var _privateMethod = function() {
    /* 无法访问到 privateField */
  }

}());

Lodash Template with condition

var itemRowTemplate = _.template([
  '<tr>',
  '<td class="btn-link pointer itemViewLink" data-spgid="<%= spgid %>">',
  '<%= itemnumber %><br><%= itemname %>',
  '<% if (hasMark == true) { %>',
  '<i class="fa fa-flag text-danger pull-right"></i>',
  '<% } %>',
  '</td>',
  '</tr>'
].join(''));

/* some other issues */

itemRowTemplate({
  itemnumber: row.customid,
  itemname: row.groupname,
  spgid: row.surveypartnergroupid,
  itemconcentrationexceeded: row.itemconcentrationexceeded,
  itemstatus: (row.approvalstatus.length > 0) ? row.approvalstatus : 'No Response',
})

.match()

Get occurrences count of substring in a string

//
// Example:
// '123123'.match(new RegExp("1", "g"))
//
// Output:
// ["1", "1"]
//
// If no substring found will return null !!!
//
let singleCountObj = s.match(new RegExp("a", "g"));
let singleCount = (singleCountObj !== null) ? singleCountObj.length : 0;

.replace()

正则表达式替换

'213-123-321-321'.replace(/-/g, '')
// 第一个参数没有引号!!!
// 213123321321

.slice()

获取数组的最后一个 elem

var myArray = [1, 2, 3, 4, 5, 6];
console.log(myArray.slice(-1)[0])

移除特定 elem

// splice(startFromWhichIndex, deleteLength0)
// array self will be updated

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
var removed = arr.splice(2, 2);

/*
removed === [3, 4]
arr === [1, 2, 5, 6, 7, 8, 9, 0]
*/

.fetch()

fetch(url, {
    method: 'POST', // or 'PUT'
    body: JSON.stringify(data), // data can be `string` or {object}!
    headers: {
      'Content-Type': 'application/json'
    }
  }).then(res => res.json())
  .then(response => console.log('Success:', JSON.stringify(response)))
  .catch(error => console.error('Error:', error));

ajax with serialized form

$.ajax({
    url: 'xxx.cfm?t=10EFCE11946ABB54D46EB44607097E60EAE5384E87E8&cfcid=3e481ba9f2a444c9987f068177150742',
    method: 'post',
    data: $('form').serialize()
  })
  .done(function(res) {
    // TODO
  })
  .fail(function() {
    console.log("error");
  })
  .always(function() {
    console.log("complete");
  });

Deep Clone

const deepClone = obj => {
  let clone = Object.assign({}, obj);
  Object.keys(clone).forEach(
    key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
  );
  return Array.isArray(obj) && obj.length ?
    (clone.length = obj.length) && Array.from(clone) :
    Array.isArray(obj) ?
    Array.from(obj) :
    clone;
};

Reduce

var rv = [];
[1, 2, 3, 4, 5].reduce((a, c) => {
  let str = a + ((c === 1) ? '' : '/') + c;
  rv.push(str);
  return str;
}, []);atte

/*
Input: [1,2,3,4,5]
Output: ["1", "1/2", "1/2/3", "1/2/3/4", "1/2/3/4/5"]
*/

Example

x = [1, 2, 3, 4];
x.reduce((accumulator, currentValue) => (accumulator + currentValue), 0);
// 设置了 0 为初始值, 如果没有初始值那么会将第一个元素当成 acc 放进去, 可能会忽略第一个参数
// output 10
[1, 2, 3, 4, 5, 6, 7, 8, 9].reduce((acc, cv) => (acc + cv))
// 45, 因为一开始 1 就被作为 acc 了

[1, 2, 3, 4, 5, 6, 7, 8, 9].reduce((acc, cv) => (acc + cv), 10)
// 55

[{
  a: 1,
  b: 2
}, {
  a: 2,
  b: 3
}].reduce((acc, cv) => acc + cv.a, 0)
// 3, 全部 a 的总和是 3

[{
  a: 1,
  b: 2
}, {
  a: 2,
  b: 3
}].reduce((acc, cv) => acc + cv.b, 0)
// 5

Datatable

Datatable 自定义 Excel/Print 输出 Column

Datatable 限定特定行 允许/不允许 排序

$('#results').html(res); // res = html pure table with good format
$('#results table').DataTable({
  "buttons": [{
    extend: 'print',
    text: '<i class="fa fa-print" title="Print"></i>',
    className: "mb-2",
    exportOptions: {
      columns: [0, 1, 2, 3, 4]
    }
  }, {
    extend: 'excelHtml5',
    text: '<i class="fa fa-file-excel-o" title="Excel Download"></i>',
    className: "mb-2",
    exportOptions: {
      columns: [0, 1, 2, 3, 4]
    }
  }]
});

各种按钮的 Action 列表:https://datatables.net/reference/button/


Datatable 额外筛选条件 & 绑定额外 filter

$.fn.dataTable.ext.search.push(
  /* 这里 push 了一个方法, 每次 draw 的时候就会调用这个方法 */
  function(settings, data, dataIndex) {
    var status = $('#approvalStatus').val();

    // 这里判断 status 和 data[1], 返回 true 的话就显示, 否则不显示
    if (status == "") return true;
    else if (data[1] == status) return true;
    else return false;
  }
);

/* 给特定的 filter 绑定事件, 选择之后进行筛选  */
$('#approvalStatus').change(function(event) {
  /* temp save the filter to global var */
  if ($(this).val() !== '') currStatus = $(this).val();
  dataTable.draw(false);
});

Datatable 获取当前页数 & 获取总页数 & 跳转到特定页

var dataTable = $itemDashboardCard.find('table').DataTable({
  ……});

dataTable.page.info().page; // 当前页数 index, 这个是 index 从 0 开始
dataTable.page.info().pages; // 总页数计数

dataTable.page(currPageIndex).draw(false); // 跳转到 index = currPageIndex 的那一页

Datatable 限定特定行 允许/不允许 排序

tags: datatable, excel, print, 限制, 隐藏

"columnDefs": [{
  orderable: false,
  targets: [5]
}],

这样第 6 列就不会输出了, 注意从 0 开始

Datatable 监听每一次刷新表格

分页, 筛选都会调用到

"drawCallback": function(settings) {
  debugger
}

Object.assign()

实际上就是将几个参数合并到第一个参数而已啦

var o1 = {
  a: 1,
  b: 1,
  c: 1
};
var o2 = {
  b: 2,
  c: 2
};
var o3 = {
  c: 3
};

var obj = Object.assign({}, o1, o2, o3);
//首先将第二个和第一个得到 A, 然后将第三个合并到之前的结果 A
console.log(obj); // { a: 1, b: 2, c: 3 }

需要注意的一点: 第一个参数在合并之后会改变, 其他参数不会

var o1 = {
  a: 1
};
var o2 = {
  b: 2
};
var o3 = {
  c: 3
};

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

Javascript: Select2 多选的实现

实际上很简单

HTML 部分加一个 multiple="true" 然后 select2.init 的时候加一个参数 isMultiple: isMultiple


Datatable 输出 Excel 时添加额外行

Add extra rows for datatable-exported-excel

方法 1: datatable.init 之前用 JS 添加额外行, 此方法无法添加到 header 之前 方法 2: 对 Excel 进行操作

主要说方法 2:

$('table#datatable').dataTable({
  buttons: [{
    extend: 'excelHtml5',
    customize: function(xlsx) {
      var sheet = xlsx.xl.worksheets['sheet1.xml'];
      var downrows = 7;
      var clRow = $('row', sheet);

      // add styles for the column header, and row[0] will be move down later
      $(clRow[0]).find('c').attr('s', 31);

      //update Row
      clRow.each(function() {
        var attr = $(this).attr('r');
        var ind = parseInt(attr);
        ind = ind + downrows;
        $(this).attr("r", ind);
      });

      // Update  row > c
      $('row c ', sheet).each(function() {
        var attr = $(this).attr('r');
        var pre = attr.substring(0, 1);
        var ind = parseInt(attr.substring(1, attr.length));
        ind = ind + downrows;
        $(this).attr("r", pre + ind);
      });

      function Addrow(index, data) {
        msg = '<row r="' + index + '">'
        for (i = 0; i < data.length; i++) {
          var key = data[i].k;
          var value = data[i].v;
          msg += '<c t="inlineStr" r="' + key + index + '">';
          msg += '<is>';
          msg += '<t>' + value + '</t>';
          msg += '</is>';
          msg += '</c>';
        }
        msg += '</row>';
        return msg;
      }

      //add data to extra rows
      var countryStateList = $('select[name=f_stateidlist] option:selected').map(function(index, elem) {
        return $(elem).attr('title').trim().replace('>>', '');
      }).get().join(",");
      var agencyValue = $('select[name=f_agency] option:selected').val();
      var reportGroupList = $('select[name=f_reportgroup] option:selected').map(function(index, elem) {
        return $(elem).attr('title').trim();
      }).get().join(",");
      var repealValue = $('select[name=f_repealed] option:selected').val();
      var actTypeValue = $('select[name=f_actiontype] option:selected').val();
      var updateStatusValue = $('select[name=f_rulestatus] option:selected').val();
      countryStateList = (countryStateList != "") ? countryStateList : 'All';
      agencyValue = (agencyValue != "") ? agencyValue : 'All';
      reportGroupList = (reportGroupList != "") ? reportGroupList : 'All';
      repealValue = (repealValue != "") ? repealValue : 'All';
      actTypeValue = (actTypeValue != "") ? actTypeValue : 'All';
      updateStatusValue = (updateStatusValue != "") ? updateStatusValue : 'All';
      var r1 = Addrow(1, [{
          k: 'A',
          v: 'Report Filter Criteria:'
        },
        {
          k: 'B',
          v: ''
        }
      ]);
      var r2 = Addrow(2, [{
          k: 'A',
          v: 'Country/State:'
        },
        {
          k: 'B',
          v: countryStateList
        }
      ]);
      var r3 = Addrow(3, [{
          k: 'A',
          v: 'Agency:'
        },
        {
          k: 'B',
          v: agencyValue
        }
      ]);
      var r4 = Addrow(4, [{
          k: 'A',
          v: 'Report Group:'
        },
        {
          k: 'B',
          v: reportGroupList
        }
      ]);
      var r5 = Addrow(5, [{
          k: 'A',
          v: 'Repealed:'
        },
        {
          k: 'B',
          v: repealValue
        }
      ]);
      var r6 = Addrow(6, [{
          k: 'A',
          v: 'Action Type:'
        },
        {
          k: 'B',
          v: actTypeValue
        }
      ]);
      var r7 = Addrow(7, [{
          k: 'A',
          v: 'Update Status:'
        },
        {
          k: 'B',
          v: updateStatusValue
        }
      ]);

      sheet.childNodes[0].childNodes[1].innerHTML = r1 + r2 + r3 + r4 + r5 + r6 + r7 + sheet.childNodes[0].childNodes[1].innerHTML;
    }
  }]
});


关于 Element.onclick

newElem.onclick = function() {
  document.getElementById('' + newRowID).className = "tbl_highlightRow";
  PCC_Notes_deleteNote(newRowID, noteID);
}

注意这里不需要写 new function


动态提交 Form

var form = document.createElement("form");
form.id = "form";

var input = document.createElement("input");
input.name = "index";
input.value = $(this).data('metaresultid');
form.appendChild(input);

form.method = "POST";
form.action = "tib.cfm?ajaxModal";
form.submit();

进制转换

左边是修改前的进制, 右边是修改后的

to = parseInt(num).toString(2);
to = parseInt(num).toString(8);
to = parseInt(num).toString(16);
to = parseInt(num, 2);
to = parseInt(num, 8);
to = parseInt(num, 16);
to = parseInt(num, 2).toString(8);
to = parseInt(num, 8).toString(2);
to = parseInt(num, 2).toString(16);
to = parseInt(num, 16).toString(2);
to = parseInt(num, 8).toString(16);
to = parseInt(num, 16).toString(8);

定义 eval() 函数可计算某个字符串, 并执行其中的的 JavaScript 代码.


eval()

实例

eval("x=10;y=20;document.write(x*y)")
document.write(eval("2+2"))
var x=10
document.write(eval(x+17))

实例 2

主要通过配合 Object 使用, 可以访问不确定的属性

person=new Object();
person.age=56;
var attrname="age";
eval("alert(person."+attrname+");");

键盘事件监听

window.onload = function() {
  var oTxt1 = document.getElementById('txt1');
  var oTxt2 = document.getElementById('txt2');

  oTxt1.onkeydown = function(ev) {
    var oEvent = ev || event;
    if (oEvent.keyCode == 13 && oEvent.ctrlKey) //keyCode==13 就是等于按回车键
    {
      oTxt2.value += oTxt1.value + '\n';
      oTxt1.value = '';
    }
  };
};

Console 的特殊用法

显示表格模式:

let args = ["%c Environment %c production ",
  "padding: 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060;",
  "padding: 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e;"
]

console.log(args[0], args[1], args[2])
// or
console.log.apply(this, arguments)

给输出设定样式:

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

var john = new Person("John", "Smith");
var jane = new Person("Jane", "Doe");
var emily = new Person("Emily", "Jones");

console.table([john, jane, emily], ["firstName"]);

Single Linked List Reverse

var d = {}
var c = {
  next: d
}
var b = {
  next: c
}
var a = {
  next: b
}

f = function(head) {
  if (head.next) {
    f(head.next)['next'] = head; // 将递归结果的 next 指向前一个
    delete head.next; // 并且删除掉
  }
  return head;
}
f(a)

分析流程

// 我们的目的
d.next = c
c.next = b
b.next = a
a.next = undefined

可以看到 [x.next].next = [x] 上方两个变量可以推得一个函数

f(x) {
  f(x.next).next = x;
  //我们将函数递归点放到了最前端, 这样可以一次性递归到最后一个元素
  return x
}

我们需要一个跳出条件:

f = function(x) {
  if (x.next) {
    f(x.next).next = x;
  }
  return x
}

然后我们需要清除原始数据

f = function(head) {
  if (head.next) {
    f(head.next)['next'] = head; // 将递归结果的 next 指向前一个
    delete head.next; // 并且删除掉
  }
  return head;
}