分享,进步,自足

标签 笔记 下的文章

21/2
2019

webpack基础学习+自定义封装AJAX类

webpack

本文用于记录webpack的简单使用,以及用原生JS封装XMLHttpRequest对象。
中文文档:webpack中文文档

  1. 首先生成package.json:npm init -y

  2. 安装webpack和webpack-cli:npm i webpack webpack-cli -D

  3. 新建一个webpack.config.js配置文件:

    const path = require("path");
    module.exports = {
     entry: "./src/app.js",//入口文件
     output: {//输出文件
         path: path.resolve(__dirname, "dist"),
         filename: "bundle.js"
     },
     mode: 'production'
    }
  4. package.json文件的scripts对象内添加:"webpack": "webpack",如下:

    "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
     "webpack": "webpack"
    }
  5. 在index.html中引入bundle.js文件,运行即可在浏览器终端看见结果。

    <!DOCTYPE html>
    <html lang="en">
    <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <title>webpack学习</title>
    </head>
    <body>
    </body>
    <script src="./dist/bundle.js"></script>
    </html>
  6. 以后使用npm run webpack运行webpack命令


AJAX

文件结构:
QQ截图20190221190310.png
以下为ajax.js文件内容:

export default class Ajax {
    constructor() {
        this.xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");//兼任IE5及以下
    }
    send(options){
        let xhr = this.xhr;
        let opt = {
            type: options.type||"GET",
            url: options.url||"",
            async: options.async||"true",
            data: options.type == "POST" ? options.data||"" : ""
        }
        return new Promise(function(resolve, reject){
            xhr.open(opt.type, opt.url, opt.async);
            xhr.onreadystatechange = ()=>{
                if (xhr.readyState !== 4) {
                    return;
                  }
                  if (xhr.status === 200) {
                    resolve(xhr.response);
                  } else {
                    reject(new Error(xhr.statusText));
                  }
            }
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send(opt.data);
        })
    }
}

使用方法,在app.js:

import xmlhttp from "./ajax";
let tianqi = new xmlhttp();
tianqi.send({
    type: "GET",
    url: "https://api.isoyu.com/index.php/api//Movie/playing_movie_list?start=0&count=9", 
}).then((value) => {
    console.log(value);
});

大致过程:创建一个Ajax类,构造函数中新建XMLHttpRequest对象,创建一个send方法,接收一个对象。使用Promise对象进行AJAX发送,并且返回这个Promise对象

+ MORE

20/2
2019

JS实现简单的事件管理

这是一道面试题:

// 类型: 校招
// 时长: 30 分钟
// 姓名:
// 日期:

// 实现下面的 EventEmitter 类, 用于简单的事件管理.

// 提示:
// 运行代码快捷键: Ctrl + S 

class EventEmitter {

    emit(type, ...args) {

    }

    oncets(that, type, listener) {

    }

    on(type, listener) {

    }

    off(type, listener) {

    }
  }

  // 在不修改下面代码的情况下, 能满足下面列举的使用

  console.log('输出结果:');

  const target = new EventEmitter();

  // once

  target.once('ready', id => console.log('ready', id));

  target.emit('ready', 1);
  target.emit('ready', 2);

  const messageListener = (...args) => console.log(args);

  // on

  target.on('message', messageListener);
  target.emit('message', 'hello');
  target.emit('message', 'world', '!');

  // off
  target.off('message', messageListener);

  target.emit('message', 'nothing');

  // 输出结果参考

  // 输出结果:
  // ready 1
  // hello
  // world !
  // (off 后无输出)

我在此之前完全没有写过事件驱动型的程序,对事件驱动我还停留在DOM的事件管理上,所有这题没有做出来,但是当时的思路有一些了。
事后在查阅网上资料后完成了以下代码,特此记录:

// [makeflow: event-emitter]
// 类型: 校招
// 时长: 30 分钟
// 姓名:
// 日期:

// 实现下面的 EventEmitter 类, 用于简单的事件管理.

// 提示:
// 运行代码快捷键: Ctrl + S 

class EventEmitter {
    constructor() {
        this.eventList = {};
    }

    emit(type, ...args) {
        let event = this.eventList[type];
        if(!event){
            return false;
        }else if(typeof event =="function"){
            event(...args);//如果只有一个值就直接执行
        }else if(Array.isArray(event)){//循环遍历执行
             for(let i = 0;i < event.length;i++){
                 event[i](...args);
             }
        }
    }

    once(type, listener) {
        this.on(type, this.oncets(this, type, listener));
    }

    oncets(that, type, listener) {
        //执行回调时首先删除自己,再执行
        function funconce() {
            that.off(type,funconce);
            listener(arguments);
        }
        return funconce;
    }

    on(type, listener) {
        //注册事件
        let event = this.eventList[type];
        if(!event){//直接添加到数组
            this.eventList[type] = listener;
        }else if(typeof event == "function"){//注册第二个事件时把属性改为数组
            this.eventList[type] = [event, listener];
        }else if(Array.isArray(type)){//第三次之后直接向数组中添加函数体
            this.eventList[type].push(listener);
        }
    }

    off(type, listener) {
        let event = this.eventList[type];
        if(typeof event =="function"){
            if(event == listener){//一个值,直接删除
                delete this.eventList[type];
            }
        }else if(Array.isArray(event)){
            //多个值,找到相同的删除掉
            for(let i = 0;i < event.length;i++){
                if(this.eventList[type][i] === listener){
                    this.eventList[type][i] = this.eventList[type][this.eventList[type].length - 1];
                    this.eventList[type].pop();
                    i--;
                    if(this.eventList[type].length === 0){
                        delete this.eventList[type];
                    }
                }
            }
        }
    }
  }

  // 在不修改下面代码的情况下, 能满足下面列举的使用

  console.log('输出结果:');

  const target = new EventEmitter();

  // once

  target.once('ready', id => console.log('ready', id));

  target.emit('ready', 1);
  target.emit('ready', 2);

  const messageListener = (...args) => console.log(args);

  // on

  target.on('message', messageListener);
  target.emit('message', 'hello');
  target.emit('message', 'world', '!');

  // off
  target.off('message', messageListener);

  target.emit('message', 'nothing');

  // 输出结果参考

  // 输出结果:
  // ready 1
  // hello
  // world !
  // (off 后无输出)

最后大致完成了,校招题都这样啊,难受。

+ MORE

13/2
2019

二维数组中的查找

题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

例如:

输入:16, [[1, 2, 8, 9], [2, 4, 9, 12], [4, 7, 10, 13], [6, 8, 11, 15]]
输出:false


一般情况下我们可以使用两个for循环进行遍历,代码是这样:

function Find(target, array){
    for(var i = 0;i < array.length;i++){
        for(var j = 0;j < array[i].length;j++){
            if(array[i][j] == target){
                return true;
            }
        }
    }
    return false;
}

但是这样浪费了题目中的信息,题目中说这是一个有序序列,并且子数组的长度相同,并且这样的时间复杂度是O(n^2)。


所以可以考虑其它方式,首先把数组写成二维的样式,如下:

子数组0 子数组1 子数组2 子数组3
1 2 4 6
2 4 7 8
8 9 10 11
9 12 13 15

观察得知从上至下是递增,从左至右也是递增。现在以左下角的数字9作为开始数字,对传入的数字与9相比较,如果比9小则向上移动,如果比9大则向右移动,一直重复就可以找到这个数字。
为什么不从左上角开始呢,因为左上角不管向下还是向右都是递增,这是一个分岔路口,程序不知道应该走哪边,所以选择左下角唯一的。
代码如下:

function Find(target, array) {
    var num1 = array.length;
    var num2 = array[0].length;
    for (var i = 0, j = num2 - 1; i < num1 && j >= 0;) {
        /*
            i代表列,j代表行,初始就为左下角的数字。
            i<num1是列的边界,j>=0是行的边界(子数组边界)
        */
        if (target == array[i][j]) {
            return true;
        }
        if (target > array[i][j]) {
            i++;
            continue;
        }
        if (target < array[i][j]) {
            j--;
            continue;
        }
    }
    return false;
}

当然也有一些其它方法,比如把子数组进行二分法查找,并对每个子数组都这样操作。不过这里就讨论了。

+ MORE

12/2
2019

正则表达式的反向引用

今天遇到了一道题,他是这样的:

题目描述

给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false

实例

输入:'rattler'
输出:true


我的解决方式是这样的,循环检测每一个字符和它下一个字符是否相同,从第一个字符开始,所以最后一个字符不需要检测,代码:

function containsRepeatingLetter(str) {
    for(var i = 0;i < str.length;i++){
        if(i !== str.length-1){
            if(str[i] == str[i+1] && /[a-zA-Z]/.test(str[i]) && /[a-zA-Z]/.test(str[i+1])){
                return true;
            }
        }
    }
    return false;
}

事实证明,这个代码是通过了验证的,但是我在查看其它人的代码时却发现一个以前从来没有研究过的东西

反向引用

首先给出地址:http://www.cnblogs.com/-ShiL/archive/2012/04/06/Star201204061009.html
重点看其中的2.1节,大致就可以理解

源字符串:abcdebbcde
正则表达式:([ab])\1
对于正则表达式“([ab])\1”,捕获组中的子表达式“[ab]”虽然可以匹配“a”或者“b”,但是捕获组一旦匹配成功,反向引用的内容也就确定了。如果捕获组匹配到“a”,那么反向引用也就只能匹配“a”,同理,如果捕获组匹配到的是“b”,那么反向引用也就只能匹配“b”。由于后面反向引用“\1”的限制,要求必须是两个相同的字符,在这里也就是“aa”或者“bb”才能匹配成功。
考察一下这个正则表达式的匹配过程,在位置0处,由“([ab])”匹配“a”成功,将捕获的内容保存在编号为1的组中,然后把控制权交给“\1”,由于此时捕获组已记录了捕获内容为“a”,“\1”也就确定只有匹配到“a”才能匹配成功,这里显然不满足,“\1”匹配失败,由于没有可供回溯的状态,整个表达式在位置0处匹配失败。
正则引擎向前传动,在位置5之前,“([ab])”一直匹配失败。传动到位置5处时,,“([ab])”匹配到“b”,匹配成功,将捕获的内容保存在编号为1的组中,然后把控制权交给“\1”,由于此时捕获组已记录了捕获内容为“b”,“\1”也就确定只有匹配到“b”才能匹配成功,满足条件,“\1”匹配成功,整个表达式匹配成功,匹配结果为“bb”,匹配开始位置为5,结束位置为7。
扩展一下,正则表达式“([a-z])\1{2}”也就表达连续三个相同的小写字母。

所以整段代码可以缩减为:

function containsRepeatingLetter(str) {
    return /([a-zA-Z])\1/.test(str);
}

+ MORE

30/1
2019

移除数组中的元素

题目描述

移除数组 arr 中的所有值与 item 相等的元素。不要直接修改数组 arr,结果返回新的数组

示例

输入:
[1, 2, 3, 4, 2], 2

输出:
[1, 3, 4]

个人思路

题目要求需要不直接修改原数组,所以需要复制一个新数组,再使用splice函数删除与item相同的项。
所以我得到的代码如下:

function remove(arr,item){
    var newarr = arr;
    for(var i=0;i<newarr.length;i++){
        if(newarr[i] == item){
            newarr.splice(i,1);
        }
    }
    return newarr;
}

但是实际上这个代码并没有通过测试,经过检查发现了如下的错误:

  1. 数组不是基本数据类型,而是一个引用数据类型或者叫做复杂数据类型,此类型的变量存的不是数据本身,存的是指向堆内存中的地址,直接赋值后实际上newarr和arr是指向同一个数组,不符合题目要求:不直接修改数组arr。
  2. 使用splice函数后,数组的长度会少一,整体内容会向左移,如果数组内有连续相同的元素,会漏掉最后一个元素不能被移除。
    所以修改后的代码如下:
function remove(arr,item){
    var newarr = arr.slice(0);
    for(var i=0;i<newarr.length;i++){
        if(newarr[i] == item){
            newarr.splice(i,1);
            i--;
        }
    }
    return newarr;
}

这样就可以通过测试了。但是实际上方法不止一个,下面给出其它方法:

其它方法

function remove(arr,item){
    var newarr = [];
    for(var i=0;i<arr.length;i++){
        if(arr[i] != item){
            newarr.push(arr[i]);
        }
    }
    return newarr;
}

这个方法和我想的是一类,新建一个新数组,把不同的元素添加进去


function remove(arr,item){
    return arr.filter(function(ele){
         return ele != item;
    })
}

filter()函数是用于筛选数组用的,函数是这样工作的:filter()函数可以接收一个参数,这个参数是一个回调函数,filter函数会把数组中的每个元素作用于回调函数,作用之后如果回调返回值是false就丢弃这个元素,如果是true就保留这个元素,然后依次对数组的每个元素都执行这个操作。
所以上述代码:如果数组元素与item不等就返回true,保留元素;否则返回false,丢弃元素。

+ MORE