zoukankan      html  css  js  c++  java
  • 时间format函数引爆的知识点和年末有话说

    年末感慨


    转眼之间,一年的最后一天来了。

    2017,技术界貌似正在飞跃。多年的量变终于引起了质变。
    人工智能,区块链。对此,我很激动,激动着有点害怕,害怕中有点紧张,还有点渴望。未来的至高点,未来的风口,自己作为一个小小的菜鸟程序员,能够抢占呢?能否参与吗?改变世界?

    火车上,回家后,看完了《神们自己》,想起以前囫囵吞枣看的《北京折叠》,这些科幻,离我们,真的很远吗?也曾看过一些历史穿越装逼小说,活了21个年岁,终于也渐渐感受到历史和人类的伟大。从倾向于文采的那个时代,到实业兴邦的近代,甚至到如今支付宝、比特币刷新实体货币。

    中国现在很强。


    不过下面还是来说说时间的format函数吧

    实业兴邦啊(互联网当然也是实业啦,当时的虚业我猜应该是写诗之类的吧,这里就先不百度了)

    一.目标程序

    一个时间format函数,用法 format(date,"yyyy-MM-dd hh-mm-ss"),参数可变

    const format = (value, format = "yyyy-MM-dd hh:mm:ss") => {
        const date = new Date(value);
        const o = {
            "M+": date.getMonth() + 1, // 月份
            "d+": date.getDate(), // 日
            "h+": date.getHours(), // 小时
            "m+": date.getMinutes(), // 分
            "s+": date.getSeconds(), // 秒
            "q+": Math.floor((date.getMonth() + 3) / 3), // 季度
            "S": date.getMilliseconds() // 毫秒
        };
        let fmt = format;
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1,
        (`${date.getFullYear()}`).substr(4 - RegExp.$1.length));
        Object.keys(o).forEach((k) => {
            if (new RegExp(`(${k})`).test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ?
            (o[k]) :
            ((`00${o[k]}`).substr((`${o[k]}`).length)));
        });
        return fmt;
    };
    

    二.不要小看上面的函数,用到的知识点其实还是不少的

    现在的技术真是一环扣一环,所以要重视基础啊。

    1.关于Date对象方法

    getDate,getDay,getMonth,getFullYear(getYear已经被弃用了)
    getHours,getMinutes,getSeconds

    2. substr的运用 --- 一个Array对象的方法(我们来跟 substring 比较下)

    substr(start, length) "slfjlsjf".substr(0,4) => "slfj"
    "slfjlsjf".substr(1,4) => "lfjl"
    substring(start, end) "slfjlsjf".substring(0,4) => "slfj"
    "slfjlsjf".substring(1,4) => "lfj"

    • `上面两个方法不改变原数组

    3.RegExp的$

    RegExp.$1-$9:MDN上的解释是,该特性是非标准的,尽量不要在生产环境使用。
    ==貌似已经使用了。
    该属性是只读的,而且只有在正确匹配的情况才会改变.
    括号匹配项是无限的,但是RegExp对象能捕获的只有9个。
    这些属性可以在 String.replace 方法中替换字符串,在这种情况下,不用在前面加上RegExp

    const reg = /(w+)s(w+)/;
    const str = "hello haha";
    console.log("pre:", RegExp.$1, RegExp.$2); // test.js
    const a = reg.test(str);
    console.log("after:", RegExp.$1, RegExp.$2); // hello haha
    

    我们发现一件非常有趣的事情。node环境下,默认的 RegExp.$1 竟然是文件的名字
    此后的 RegExp.$1 为第一个括号所匹配的 hello
    RegExp.$2 为第二个括号所匹配的 haha


    4.Object.keys(o)

    Object.keys() 方法会返回一个给定对象自身可枚举属性组成的数组。
    

    数组中属性名的排列顺序和使用 for ... in 循环遍历该对象返回的顺序一致。
    (两者的主要区别是 一个 for ... in 循环还会枚举 其原型链上的属性

    • 根据MDN的解释,该方法在 ES5 和 ES2015(原名ES6) 的解释是不同的

    Object.keys("foo"); // TypeError: "foo" is not an object (ES5 code)
    Object.keys("foo"); // ["0", "1", "2"]
    我自己在我电脑的 Node 6 环境下即为后者的结果
    Node.js 是针对V8引擎的现代版本而构建的。根据其文档来看,Node 已经对 ES2015的许多东西进行了实现。

    • 该方法的正常使用

    const o = { "one": 1, "two": 2 }
    console.log(Object.keys(o)); // ['one', 'two']

    • 该方法和它的兄弟们的区别:for in / Object.keys / Object.getOwnPropertyNames

    共同点:三者皆可遍历对象。
    不同点:摘自:https://www.cnblogs.com/37sky/articles/5324105.html

    const parent = Object.create(Object.prototype, {
        a: {
            value: 1,
            writable: true, // 可写
            enumerable: true, // 可枚举
            configurable: true // 能否使用访问器, 能够delete
        }
    });
    // 上面的 parent - a可以被枚举
    const child = Object.create(parent, {
        b: {
            value: 2,
            writable: true,
            enumerable: true,
            configurable: true
        },
        c: {
            value: 3,
            writable: true,
            enumerable: false,
            configurable: true
        }
    });
    // b可枚举,c不可枚举
    
    
    
    // TEST 1 --- es3 for...in
    for (const attr in child) {
        console.log(attr); // ------------> b,a
    }
    // Result: for in 会输出自身以及原型链上可枚举的可见的属性
    
    
    // TEST 2 --- es5 Object.keys
    console.log(Object.keys(child)); // ----------> ['b']
    // Result: Object.keys 会输出 自身(仅自身,不包括原型链)可枚举的可见属性
    
    
    // TEST 3 --- es5 Object.getOwnPropertyNames
    console.log(Object.getOwnPropertyNames(child)); // ------> ['b', 'c']
    // Result:Object.getOwnProperyNames 会输出 自身(不包括原型链)所有的可见属性
    
    
    // TEST 4 --- es6 for ... of
    for(var i of child) {
        console.log(i);
    }
    // Result: 很遗憾,node 6.10.0 还不支持它
    
    这里做个总结:
    • Object.keys可以输出自身(不包括原型链)的可枚举的可见属性。
    • Object.getOwnPropertyNames可以输出(不包括原型链的)的所有可见属性。
    • for in 可以输出自身和原型链 可枚举(不可枚举则不行)的可见属性。
    Object.keys 可以说是要求最严格的,严谨。

    5.同时引出JS Object的几个属性

    学习链接:http://blog.csdn.net/qq_17335153/article/details/52584727

    • Configurable
    • Enumerable
    • Writable
    • Value
    • Getter
    • Setter
    数据属性
    const obj = {};
    Object.defineProperty(obj, 'name', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: 'test'
    });
    console.log(obj.name);
    obj.name = 'write';
    console.log(obj.name); // test ,修改失败
    console.log("用delete", delete obj.name); // false, delete失败
    console.log(obj.name); // 完好如初
    Object.defineProperty(obj, 'name', {
        configurable: true // 不可修改,将抛出错误
    });
    
    访问器属性:C# ???
    const book = {
        _year: 2004,  // 加 _ ,代表属性只能通过对象方法访问
        edition: 0
    }
    Object.defineProperty(book, 'year', {
        get: function () {
            return this._year;
        },
        set: function (newValue) {
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    });
    console.log(book.year); // 2004
    book.year = 2006;
    console.log(book.year); // 2006 若无 set,则依旧为 2004
    

    三.最后的难点

    fmt = fmt.replace(RegExp.$1,
                (`${date.getFullYear()}`).substr(4 - RegExp.$1.length));
    

    此句话的作用主要是:当我们写的是 'yyy' 的时候,只会返回年份值的后三个数

    Object.keys(o).forEach((k) => {
                if (new RegExp(`(${k})`).test(fmt)) fmt = fmt.replace(RegExp.$1,
                (RegExp.$1.length === 1) ?
                (o[k]) :
                ((`00${o[k]}`).substr((`${o[k]}`).length)));
            });
    

    使用ES6的模板引擎语法 将属性字符串变为一个个正则表达式
    最后使用 replace 一一替换

    重点注意,以下两句话是不一样的

    http://blog.csdn.net/u010552788/article/details/51019367

    console.log("test", new RegExp(`${k}`));
    console.log("test2", new RegExp(`(${k})`));
    

    看似只是一句括号之差,但是我们这里需要用到 RegExp.$1
    如若用第一种,$ 是没有办法匹配到的

    此后依次匹配到 MM hh 等,之后采用 replace 的方法 分别将 MM hh 等替换为
    我们的 o[k] 对象。

    其后的三元运算符又是什么意思呢?

    原来是这样:
    假设我们返回的秒数o[k] = 1 ,那么这里我们应该给它显示 01 不是吗?
    所以我们这里使用 (00${o[k]}).substr((${o[k]}).length) 来替换
    根据是 1 位 还是 2 位 来决定使用 (008).substr(1) = 08 // 8秒
    还是 (0018).substr(2) = 18 // 18秒

    对于length = 1 的情况。
    1.此句为了 当分钟数或者秒数或者..... 为 个位数的时候 显示 '01', '02', '08'之类的
    2.一般情况下,没有 "q+" 和 "S" 的匹配了。具体看 fmt 是否有东西。
    3.对于秒来说,这里的判断其实不会走 RegExp.$1.length === 1 (true)
    4.对于毫秒 S 来说,会走这步。所以 = 1的情况是为了毫秒而准备的。
    

    四.至此,大功告成

    一段小小的程序,却能发掘出这么多我不懂的东西。还是差的太远了我,基础。

  • 相关阅读:
    jQuery学习总结之基础知识持续更新中
    经典人生感悟 看看你少了那一条
    [SQL]清空数据方法大比拼
    2010年的最后一天
    javascript学习之闭包
    实现checkbox的全选/全不选/点选/行内点选(原生JS版和jQ版)
    挖掘经典:几乎被人遗忘的HTML七种用法 (转)
    下拉及多及弹出式菜单
    win7下注册一个com失败,权限不够
    Visual Studio 2010 自述文件
  • 原文地址:https://www.cnblogs.com/can-i-do/p/8158942.html
Copyright © 2011-2022 走看看