JavaScript上万关键字瞬间匹配

既然考虑的是那种极端的关键字搜索,通常的逐个遍历搜索显然是行不通的。如今用的是JavaScript,若不使用Hash表实在是太对不起这门语言了。有着对表特天独厚的支持,不妨就拿出少量的空间来换取大量的时间吧。

代码在下面:

var treeSearch = {
    makeTree: function(strKeys) {
        'use strict';
        var tblCur = {},
            tblRoot,
            key,
            str_key,
            Length,
            j,
            i;
        tblRoot = tblCur;
        for (j = strKeys.length - 1; j >= 0; j -= 1) {
            str_key = strKeys[j];
            Length = str_key.length;
            for (i = 0; i < Length; i += 1) {
                key = str_key.charAt(i);
                if (tblCur.hasOwnProperty(key)) {
                    //生成子节点
                    tblCur = tblCur[key];
                } else {
                    tblCur = tblCur[key] = {};
                }
            }
            tblCur.end = true; //最后一个关键字没有分割符
            tblCur = tblRoot;
        }
        return tblRoot;
    },
    search: function(content, tblRoot) {
        'use strict';
        var tblCur,
            p_star = 0,
            n = content.length,
            p_end,
            match, //是否找到匹配
            match_key,
            match_str,
            arrMatch = [], //存储结果
            arrLength = 0; //arrMatch的长度索引
        while (p_star < n) {
            tblCur = tblRoot; //回溯至根部
            p_end = p_star;
            match_str = '';
            match = false;
            do {
                match_key = content.charAt(p_end);
                if (!(tblCur = tblCur[match_key])) {
                    //本次匹配结束
                    p_star += 1;
                    break;
                } else {
                    match_str += match_key;
                }
                p_end += 1;
                if (tblCur.end === true) {
                    //是否匹配到尾部  //找到匹配关键字
                    match = true;
                }
            } while (true);

            if (match === true) {
                //最大匹配
                arrMatch[arrLength] = {
                    //增强可读性
                    key: match_str,
                    begin: p_star - 1,
                    end: p_end
                };
                arrLength += 1;
                p_star = p_end;
            }
        }
        return arrMatch;
    }
};

测试代码:

function test(strContent, strKeys) {
    var arrMatch,
        tblRoot = treeSearch.makeTree(strKeys),
        t = new Date();
    arrMatch = treeSearch.search(strContent, tblRoot);
    console.log('time is: ' + (new Date() - t) + 'mm');
    console.log(arrMatch);
}

var s = (function() {
    var Things = [' ', '\n', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    var s = '';
    for (var i = 1000000; i >= 0; i--) {
        s += Things[parseInt(Math.random() * Things.length) % Things.length];
    }
    return s;
})();
test(s, ['abc', 'efge', 'fun', 'tree']);

JavaScript AJAX上传base64图片

下面代码可以通过Ajax请求,直接向一个正常的文件上传接口提交请求,上传已经base64编码的图片文件。

直接贴代码:

function ajaxSubmitImageFile(base64Codes) {
    let convertBase64UrlToBlob = function(urlData) {
        let arr = urlData.split(',');
        let mime = arr[0].match(/:(.*?);/)[1];
        let bytes = window.atob(urlData.split(',')[1]); // 去掉url的头,并转换为byte

        // 处理异常,将ascii码小于0的转换为大于0
        let ab = new ArrayBuffer(bytes.length);
        let ia = new Uint8Array(ab);
        for (let i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i);
        }

        return new Blob([ab], { type: mime });
    };

    let getFileExt = function(urlData) {
        let arr = urlData.split(',');
        let mime = arr[0].match(/:(.*?);/)[1];
        return mime.replace('image/', '');
    };

    let deferred = $.Deferred();

    // let form = document.forms[0];
    // var formData = new FormData(form);   // 这里连带form里的其他参数也一起提交了,如果不需要提交其他参数可以直接FormData无参数的构造函数

    let formData = new FormData();

    let fileExt = getFileExt(base64Codes);

    // convertBase64UrlToBlob函数是将base64编码转换为Blob
    formData.append(
        'upfile',
        convertBase64UrlToBlob(base64Codes),
        'file_' + Date.parse(new Date()) + '.' + fileExt
    ); // append函数的第一个参数是后台获取数据的参数名,和html标签的input的name属性功能相同

    // ajax 提交form
    $.ajax({
        url:
            window.location.origin +
            '/article/ueditor/asp/controller.asp?action=uploadimage',
        type: 'POST',
        data: formData,
        // dataType: "text",
        processData: false, // 告诉jQuery不要去处理发送的数据
        contentType: false, // 告诉jQuery不要去设置Content-Type请求头

        success: function(data) {
            // console.log(data);
            if (data) {
                data = JSON.parse(data);
                if (data.state === 'SUCCESS') {
                    deferred.resolve(window.location.origin + data.url);
                } else {
                    deferred.reject('error');
                }
            } else {
                deferred.reject('error');
            }

            // window.location.href = "${ctx}" + data;
        },
        xhr: function() {
            // 在jquery函数中直接使用ajax的XMLHttpRequest对象
            let xhr = new XMLHttpRequest();

            xhr.upload.addEventListener(
                'progress',
                function(evt) {
                    if (evt.lengthComputable) {
                        let percentComplete = Math.round(
                            (evt.loaded * 100) / evt.total
                        );
                        window.console.log(
                            '正在提交.' + percentComplete.toString() + '%'
                        ); // 在控制台打印上传进度
                    }
                },
                false
            );

            return xhr;
        }
    });

    return deferred.promise();
}

prettier 配置

项目文件夹下建立 .prettierrc 文件,写入下面内容:

{
    tabWidth: 4,
    singleQuote: true,             // 用单引号
    printWidth: 120,               // 换行字符串阈值
    semi: true,                    // 句末加分号
    trailingComma: 'none',         // 最后一个对象元素加逗号
    bracketSpacing: true,          // 对象,数组加空格
    jsxBracketSameLine: false,     // jsx > 是否另起一行
    arrowParens: 'avoid',          // (x) => {} 是否要有小括号
    requirePragma: false,          // 是否要注释来决定是否格式化代码
    proseWrap: 'preserve'          // 是否要换行
}

在 TypeScript 中引入 CSS 并使用 WebPack 打包

需要用到 style-loader 和 css-loader 两个包,首先安装它们(我直接安装在工程中):

npm i --save-dev style-loader css-loader

在你的 .ts 或 .tsx 源码中引入 CSS 样式表文件:

import './css/custom.css';

修改 webpack.config.js 配置文件,增加内容如下:

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

OK,执行打包命令:

webpack --mode production

?

旧版浏览器(e.g. IE < 11)中的 React

在一些旧版浏览器中,你的 ES6 React 代码会报出如下错误:

Warning: React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills

比如,截图如下:

原因是因为 React 需要 ES6 中的 Map 和 Set 两种数据类型。

按照官方的方法,解决如下:

# npm i --save core-js

然后在你的代码中:

import 'core-js/es6/map';
import 'core-js/es6/set';

就 OK 啦 ?

下面附上官网上解决方法的截图

TypeScript + React + Webpack

首先假定你的开发电脑上已经安装了npm。

1、环境:

全局安装TypeScript(安装tsc命令)

npm i -g typescript

全局安装Webpack(安装webpack命令)

npm i -g webpack

2、工程:

新建工程目录,并切换到工程目录下

mkdir ~/myProject# cd ~/myProject

初始化工程,并使用npm下载react和react-dom

npm init# npm i --save react react-dom @types/react @types/react-dom

初始化typescript环境,并创建tsc的配置文件tsconfig.json

tsc --init

修改tsconfig.json,增加或修改的内容

compilerOptions.target = "es6"
compilerOptions.jsx = "react"
compilerOptions.outDir = "path/to/js"
compilerOptions.watch = true
files = [
    'path/to/src/a.tsx',
    'path/to/src/b.tsx'
]

创建webpack配置文件webpack.config.js,并填写内容

const path = require('path');

module.exports = {
    entry: {
        'a': 'path/to/js/a.js',
        'b': 'path/to/js/b.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    // mode: 'production',
};

3、开发 && 打包

实时监听文件变化,并自动打包

typescript实时编译

tsc --watch

因为之前的tsconfig.json配置文件中,配置了watch=true,所以默认加载当前目录的tsconfig.json时,会自动以监听的方式启动。一旦发现path/to/src目录下的tsx文件发生变化,会自动创建对应的path/to/js目录下的js文件。

webpack实时打包

webpack --watch

监听到path/to/js目录下的js文件内容发生变化,则自动进行打包操作,生成到dist目录下。

但是前面webpack.config.js文件中配置的mode模式为development开发模式。所以当项目最终上线时,还需要进行一次手动打包,直接指定模式为production生产模式。

生产模式会针对js和css内容进行压缩处理,去除其中的注释、空行等无用内容。

webpack --mode production

就这些了,暂时记录到这儿吧~~~

在GBK编码的页面中使用AJAX

在使用AJAX时,如果遇到使用GBK或GB2312编码的页面,怎么办呢?首先需要把GBK编码的汉字转换成UTF8编码,才不会出现乱码的情况。

使用下面的函数进行编码:

function gb2utf8(data) {
	var glbEncode = [];
	gb2utf8_data = data;
	execScript("gb2utf8_data = MidB(gb2utf8_data, 1)", "VBScript");
	var t=escape(gb2utf8_data).replace(/%u/g,"").replace(/(.{2})(.{2})/g,"%$2%$1").replace(/%([A-Z].)%(.{2})/g,"@$1$2");
	t=t.split("@");
	var i=0,j=t.length,k;
	while(++i < j) {
		k=t[i].substring(0,4);
		if(!glbEncode[k]) {
			gb2utf8_char = eval('0x' + k);
			execScript('gb2utf8_char = Chr(gb2utf8_char)', 'VBScript');
			glbEncode[k]=escape(gb2utf8_char).substring(1,6);
		}
		t[i]=glbEncode[k]+t[i].substring(4);
	}
	gb2utf8_data = gb2utf8_char = null;
	return unescape(t.join('%'));
}