所谓加密,就是经过设计算法来把字符串转化为看似杂乱无章的文本,让人不容易看穿想表达的意思。git
而解密就是按照设计的算法,反推出本来的文本内容。github
在这个算法,就是开发者本身所要设计的,既可简单又可复杂,全凭开发者本身的设计能力。算法
而对js字符串进行加密,咱们能够利用几个工具(方法)来辅助你进行字符串的转化,反复转化几回就能迷惑别人了。chrome
可是在此以前,我但愿你能对Unicode、ASCII、utf-8以及base64等涉及编码方面的,有所了解。可阅读此篇快速了解常见的字符集与编码方案的认识安全
编码,能够把浅显易懂的字符转化为难以直观理解的数字或者杂乱无章的字符,即能达到让别人摸不着头脑的加密效果了。bash
可是,单纯的利用Unicode或编码进行的字符串转化,这种形式的加密,太简单了,毕竟它们都是有广为人知的固定规则的,很容易让别人识破或反转化,毕竟,都是有一一对应的关系在那里。函数
所以,要巧妙地混用它们,设计出一个相对复杂的算法,就能达到基础的加密效果了。工具
对此,咱们先认识一些关于字符串转化的相关函数方法ui
按照UTF-16编码,把对应的数字码值转化对应的字符。是字符串的静态方法。编码
语法:
String.fromCharCode(n1[, n2, ...n])
复制代码
参数为依据UTF-16编码的码值,任何进制表示都行,如十进制或十六进制
返回值为按码值顺序排列组合起来的对应字符造成的字符串,如
String.fromCharCode(68)
// 返回字符'D',D对应的Unicode就是68
String.fromCharCode(100)
// 返回字符'd',d对应的Unicode就是100
String.fromCharCode(68, 100)
// 返回字符串'Dd'
复制代码
须要注意的是,UTF-16编码是依据Unicode编码的一种中间转化格式方案,在码值0~65535(0x0000 ~ 0xFFFF)范围内,即BMP零号平面下,UTF-16的码值和Unicode的码值表明的字符是同样的,都是1个16bit二进制表明一个字符;可是超出65535外的码值,UTF-16是用两个16bit二进制来表示一个字符,即用两个码值表示一个字符,称两个码值为代理对,这是与Unicode不一样的。
因此该方法的参数,若是要转换超出65535码值外的字符,则参数是代理对,而不是直接的Unicode码值。若是用了BMP以上的码值,会直接对大于16bit的二进制高位部分进行截断处理,由于参数只能是16bit表示一个字符,虽然不会报错,可是明显输出结果变了,不是预期的结果。
// 如U+1F303,在Unicode里1F303是一个独立的码值,表示"Night with Stars"这个字符🌃
// 可是在UTF-16里,是用两个码值来表示该字符(0xD83C,0xDF03)
// 返回结果为 🌃
String.fromCharCode(0xD83C, 0xDF03)
// 超出0xFFFF,作二进制高位截断,会变成和
// String.fromCharCode(0xF303)的结果
String.fromCharCode(0x1F303)
复制代码
和fromCharCode
目的相反,它是把字符转化为UTF-16码值。但他它不一样的是,他是实例方法,执行者是字符串对象实例。
语法:
string.charCodeAt(index)
复制代码
参数为该字符串的某个字符所在位置的下标(取值范围是0 ~ string.length-1)
返回值
NaN
;若是是非数字类型或者空,那么默认是0;fromCharCode
了解到,一个字符能够是用代理对表示的,那么这种状况下咱们要知道,这种字符的length
是2
而不是1
,因此index的取值范围是0~1,0时返回代理对的第一个,1为第二个,不传时默认是0;// '🌃'的代理对是55356,57091
'🌃'.length // 2
'🌃'.charCodeAt(0) // 返回55356
'🌃'.charCodeAt(1) // 返回57091
复制代码
'i am a teacher'.charCodeAt(2);
// 返回第三个字符a的Unicode值,97
复制代码
从上面的fromCharCode
了解到,它是有缺陷的,由于可能须要用到代理对来进行转化,这就涉及到须要进行换算出代理对这么一个麻烦的过程了,为了不进行没必要要的计算,ES 2015有一个新的方法fromCodePoint
。
从名字都能直观了解到,它是直接基于码值进行的转化,即直接根据Unicode的码值来,而没必要用UTF-16的代理对来表示一个字符。静态方法
语法:
String.fromCodePoint(n1[, n2, ...n]);
复制代码
参数为Unicode的码值,即数字,什么进制均可以。
返回值为按照参数的顺序Unicode码值对应的字符拼接的字符串。
仍是以字符'🌃'来举例说明,该字符在Unicode里用U+1F303表示,码值为0x1F303;在UTF-16里,是用代理对(0xD83C,0xDF03)表示
// 该方法就要用代理对转换
String.fromCharCode(0xD83C, 0xDF03)
// 该方法就能够直接用码值转换
String.fromCodePoint(0x1F303)
复制代码
fromCodePoint
与fromCharCode
的区别就在于前者可用Unicode码值直接转换,可是IE不支持,兼容没后者好。
与fromCodePoint
相对应的,与charCodeAt
相对比的,codePointAt
的用途也很明显。
把字符转化Unicode码值,实例方法,一样是ES 2015的新方法。
语法:
string.codePointAt(index)
复制代码
参数 为该字符串的某个字符所在位置的下标(取值范围是0 ~ string.length-1),要注意,若是字符是能够用代理对表示的,即65535码值外的字符,则直接传该字符所在下标的第一个位置,返回的就是该字符的实际Unicode码值,传第二个位置的话,就是代理对里的第二个码值。
'🌃'.codePointAt(0) // 返回127747,为该字符Unicode码值
'🌃'.codePointAt(1) // 返回57091,为该字符代理对(55356, 57091)的第二个码值
复制代码
返回值
undefined
;''
,null
,undefined
,false
或不传,那么默认是0(chrome下的表现);一样,IE不支持。
关于这两个函数的说明,能够查看我这边文章URI编码的两方法异同与场景
btoa
,即binary to ascii,同理,atob就是ascii to binary。都是window对象下的方法。IE9及如下不支持。
从名字上大致了解基本做用,btoa
做用就是把字符转化其ASCII值base64编码后的字符。而atob
则是它的逆运算,解码base64编码后的字符,即还原原字符。
这里主要说btoa
,由于atob
很简单,就是把btoa
的结果当作参数执行就行了。如下内容全是针对btoa
所说。
语法
window.btoa(stringToEncode)
复制代码
它会把参数的每个字符都被视为一个二进制数据字节来进行转换。可是该方法所能识别的的码位是基于ASCII来的,因此超出 0x00 ~ 0xFF 范围,则会引起 InvalidCharacterError 异常。因此若是字符是Unicode字符就会报错了
参数若是是数字类型,那也会当成是String类型处理,如100,即对1字符,0字符,0字符分别base64编码处理。
很明显,该方法不能针对Uncode字符进行编码,即你不能对中文编码啦。
有对其进行加强的处理,以支持Unicode的编码:
// ucs-2 string to base64 encoded ascii
function utoa(str) {
return window.btoa(encodeURIComponent(str));
}
// base64 encoded ascii to ucs-2 string
function atou(str) {
return decodeURIComponent(window.atob(str));
}
// Usage:
utoa('✓ à la mode'); // 4pyTIMOgIGxhIG1vZGU=
atou('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
复制代码
介绍了好几种方法,先简单分类总结下,避免混淆。
fromCharCode
& charCodeAt
是针对UTF-16编码的;fromCodePoint
& codePointAt
是针对Unicode编码的;encodeURI
& encodeURIComponent
是针对UTF-8编码的;btoa
& atob
是针对base64编码的这里举个简单的例子,你们能够从这里拿到点启发,可是不太建议直接套用,仍是本身动手作点改造,这样比较安全一点,还能够本身设计更复杂点。
例子仅为为你取得启发之用。
这里设计的算法比较简单:
咱们针对要进行加密的字符串,将其每一个字符先转化为Unicode值,而后基于该值作一些运算,而后获得一个新的数字,再将该数字转化为Unicode对应的字符。这样,一个新的字符串诞生了。为了更加复杂点,对其再作编码工做。
// 加密方法
function encryptChar(target) {
let result = '';
for (let i = 0, j = 0; j < target.length; j++, i++) {
let code = target.codePointAt(j);
result += String.fromCodePoint(code + i + j);
// 超出BMP的码值,是两个码值表示一个字符
if (code > 65535) { j += 1; }
}
return encodeURIComponent(result);
}
// 解密方法
function decryptChar(target) {
let newTarget = decodeURIComponent(target);
let result = '';
for (let i = 0, j = 0; j < newTarget.length; j++, i++) {
let code = newTarget.codePointAt(j);
result += String.fromCodePoint(code - i - j);
// 超出BMP的码值,是两个码值表示一个字符
if (code > 65535) {
j += 1;
}
}
return result;
}
复制代码
这里跟不少网上的资料(不少都是复制粘贴的吧?)不一样,这里采用的是codePointAt
和fromCodePoint
,而不是charCodeAt
和fromCharCode
,由于后者不能针对Unicode进行编码。那么若是把范围考虑到Unicode字符的话,则会出现代理对表示一个字符的状况,就是该字符的length
值为2,因此作循环的处理字符编码时,要用j
来作实际字符的Unicode码值工做,codePointAt
转化BMP外的字符传参为该字符所在下标的第一个便可获得Unicode码值,而i
仅仅是表示字符的个数。
由此得出的方案,比网上的资料可靠多了(我本身也查了很多,来来去去都是那样,复制粘贴),起码这里弥补了它们的缺点所在。
看了上述例子。你大概知道怎么混用以上的几个工具了。你能够设计出更加复杂的算法,各类运算加减乘除取余之类的。
建议仍是好好消化一些编码方面的知识,以及我上面罗列的几个方法的优缺点,对你会有更大帮助哦。
对你有帮助的请点赞支持~
未经容许,请勿私自转载