前端面试每日-31-第183天

今天的知识点 (2019.10.16) —— 第183天[html] HTML5的output是非常棒的一个标签,你对它有了解吗?[css] 怎样去除图片自带的边距?[js] 在js中函数返回多个值有哪些方法?[软技能] 说说你对AMD、CMD和CommonJS的理解《论语》,曾子曰:“吾日三省吾身”(我每天多次反省自己)。 前端面试每日3+1题,以面试题来驱动学习,每天进步一点! 让努力成为一种习惯,让奋斗成为一种享受!相信 坚持 的力量!!!欢迎在 Issues 和朋友们一同讨论学习! 项目地址:前端面试每日3+1 【推荐】欢迎跟 jsliang 一起折腾前端,系统整理前端知识,目前正在折腾 LeetCode,打算打通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个Star, 同时欢迎微信扫码关注 前端剑解 公众号,并加入 “前端学习每日3+1” 微信群相互交流(点击公众号的菜单:进群交流)。 学习不打烊,充电加油只为遇到更好的自己,365天无节假日,每天早上5点纯手工发布面试题(死磕自己,愉悦大家)。希望大家在这浮夸的前端圈里,保持冷静,坚持每天花20分钟来学习与思考。在这千变万化,类库层出不穷的前端,建议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢迎大家到Issues交流,鼓励PR,感谢Star,大家有啥好的建议可以加我微信一起交流讨论!希望大家每日去学习与思考,这才达到来这里的目的!!!(不要为了谁而来,要为自己而来!)交流讨论欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个[Star] https://github.com/haizlin/fe...

October 16, 2019 · 1 min · jiezi

实现一个自己的日志处理库并发布到npm

前言不折腾的前端不是一个好的前端,最近在搭建公司内部工具以及组件库,使用npm进行管理,所以学习一下如何创建一个属于自己的JavaScript库,并发布成npm模块。步骤创建账号点击进入npm官网 右上角进行注册 创建项目一路回车或者根据内容填写相关信息后,项目就创建好了。 package.json内容如下: 新建index.js文件(function (root, factory) { 'use strict'; if(typeof define === 'function' && define.amd){ define('log', [], factory); }else{ root['log'] = factory(); }})(this ? this : window, function(){ 'use strict'; const OFF = Number.MAX_VALUE; const DEBUG = 10; const INFO = 20; const WARN = 30; const ERROR = 40; function LogUtil(){ this.consoleLog = window.console; this._level = OFF; } LogUtil.prototype.setLevel = function(level){ if(!level){ return; } level = String(level).toLowerCase(); if(level === 'info'){ level = INFO; }else if(level === 'warn'){ level = WARN; }else if(level === 'error'){ level = ERROR; }else if(level === 'debug'){ level = DEBUG; }else{ level = OFF; } this._level = level; }; LogUtil.prototype.runLog = function(level, methodName, msg){ if(!level){ return; } var form = [new Date().toLocaleString(), level.toLowerCase(), methodName, msg].join('|'); if(level.toLowerCase() === 'debug' && this._level <= DEBUG){ this.consoleLog.debug(form); }else if(level.toLowerCase() === 'info' && this._level <= INFO){ this.consoleLog.info(form); }else if(level.toLowerCase() === 'warn' && this._level <= WARN){ this.consoleLog.warn(form); }else if(level.toLowerCase() === 'error' && this._level <= ERROR){ this.consoleLog.error(form); } }; return LogUtil;});到这里一个简单的包就创建好了。如果想再完善一下的话,还可以在包根目录下创建README.md文件,里面可以写一些关于包的介绍信息,最后发布后会展示在NPM官网上。 ...

July 9, 2019 · 1 min · jiezi

js导入导出总结与实践

在上一篇文章中JavaScript中AMD和ES6模块的导入导出对比,偏向于理论层面,还有一些同学在微信群里或是私下里针对一些问题进行了沟通,所以有了这一篇文章,对js的导入导出进行总结和实践当直接给 module.exports时,exports会失效这个问题其实已经和导入导出没什么关系了,我们看一个知乎上的问题(详细地址阅读原文可以查看)我们以此为突破点js 数组赋值问题 :值传递还是引用?var a = [1,2,3];var b = a;a = [4,5,6];console.log(b); //=>[1,2,3]继续看var a = [1,2,3];var b = a;a.pop();console.log(b); //=>[1,2]为什么会出现这种情况?数组和对象的赋值操作都是引用传递看下这个(留意注释部分)var a = [1,2,3];// a指向了数组 [1,2,3];var b = a;//b 指向 a 所指向的数组[1,2,3];a = [4,5,6];//a 指向了新的数组 [4,5,6],(a的指向发生了变化,改变的是a引用本身,没有改变数组对象,所以b没有变)console.log(b); //b没有改变,还是指向数组 [1,2,3];再看下这个(留意注释部分)var a = [1,2,3];// a指向了数组 [1,2,3];var b = a;//b 指向 a 所指向的数组[1,2,3];a.pop();// a 指向的数组实例发生了 pop 操作console.log(b); //=>a和b都是指向同一个数组,a变量,所以b也变量,最后输出=>[1,2]看一张图片,很形象的描述数组如此,对象也是大同小异看一个群友@ZSing提供的demovar test = { “name”: “zhangshuo”}var demo = test;demo.name = “want you”//你认为test是什么?console.log(test)//=>{ name: ‘want you’ }下面通过注释解释一下(如出一辙)var test = { “name”: “zhangshuo”}//test指向了一个对象 { “name”: “zhangshuo”}var demo = test;//demo 指向 test 所指向的对象 { “name”: “zhangshuo”}demo.name = “want you”//对象的属性发生了改变 { “name”: “want you”}//你认为test是什么?console.log(test)//=>{ name: ‘want you’ }test和demo指向了同一个对象,一个变了,就都变了同样的,我们对上面的demo做一下改造var test = { “name”: “zhangshuo”}var demo = test; test={ “name”: “更改了这个name” }demo.name = “want you”//你认为test是什么?console.log(test)//=>{ name: ‘更改了这个name’ }还需要对此进行赘述吗?还是通过注释对此进行解释说明var test = { “name”: “zhangshuo”}//test指向了一个对象 { “name”: “zhangshuo”}var demo = test;//demo 指向 test 所指向的对象 { “name”: “zhangshuo”} test={ “name”: “更改了这个name” }//test的指向发生了变化,指向了一个新对象{ “name”: “更改了这个name” }demo.name = “want you”//demo的指向没有变,改变了原对象的属性 { “name”: “want you”}//你认为test是什么?console.log(test)//=>{ name: ‘更改了这个name’ }我相信,上面的两个栗子你已经看懂了,即将进入正题先来一个过渡再看一个栗子,用来模拟exports和 module.exports的关联关系 let md = {exps:{}}//md指向一个对象 {exps:{}} let exps = md.exps//exps指向了md.exps所指向的对象 ,这个空对象{} md.exps = {a: 1, b: 2}//md.exps指向了一个新对象 {a: 1, b: 2} exps.c=3//exps,属性赋值 {c: 3} console.log(md.exps); //新对象{ a: 1, b: 2 }上面栗子中的md就是module,md.exps就是module.exports,exps就是exports在每一个模块的头部都有一行这样的命令var exports = module.exports;当直接给module.exports赋值时(module.exports={…..}),module.exports就指向了一个新对象,exports会失效直接给exports赋值会切断exports和 module.exports的关联关系还是这样的一个前提var exports = module.exports;exports是来自于module,exports指向 module.exports所指向的对象当直接给exports赋值,即 exports = {a:1}exports指向了一个新对象,不再是 module.exports所指向的对象,所以不要给 exports 直接赋值( exports =。。。)实践=>导出exportsexports的output.jsexports.str=‘string字符串’//导出字符串exports.bool=true//导出布尔exports.num=123//导出numberexports.foo=(r)=>{//导出函数 console.log(导出函数为:${r});}exports.arr=[1,2,3]//导出数组exports.obj={ a:1, b:2}//导出对象input.js const iptObj= require(’./output.js’) console.log(iptObj.str);//=>string字符串 console.log(iptObj.bool);//=>true console.log(iptObj.num);//=>123 console.log(iptObj.arr);//=>[ 1, 2, 3 ] console.log(iptObj.obj);//=>{ a: 1, b: 2 } iptObj.foo(‘参数’)//=>导出函数为:参数module.exportsmodule.exports的output.jsmodule.exports={ str:‘string字符串’, bool:true, num:123, foo:(r)=>{ console.log(导出函数为:${r}); }, arr:[1,2,3], obj:{ a:1, b:2}}input.js const iptObj= require(’./output.js’) console.log(iptObj.str);//=>string字符串 console.log(iptObj.bool);//=>true console.log(iptObj.num);//=>123 console.log(iptObj.arr);//=>[ 1, 2, 3 ] console.log(iptObj.obj);//=>{ a: 1, b: 2 } iptObj.foo(‘参数’)//=>导出函数为:参数module.exports的output.js同时支持如下写法module.exports.str=‘string字符串’module.exports.bool=truemodule.exports.num=123module.exports.foo=(r)=>{ console.log(导出函数为:${r});}module.exports.arr=[1,2,3]module.exports.obj={ a:1, b:2}input.js不变exportexport的output.jsexport const srt = ‘string字符串’export const bool = trueexport const num = 123export const arr = [1, 2, 3]export const obj = { a: 1, b: 2}export function foo(r) { console.log(导出函数为:${r});}input.jsimport {str,arr,obj,bool,num,foo} from ‘./output’console.log(str)console.log(arr)console.log(obj)console.log(bool)console.log(num)foo(‘参数’)export的output.js同时支持如下写法const str = ‘string字符串’ const bool = trueconst num = 123const arr = [1, 2, 3]const obj = { a: 1, b: 2}function foo(r) { console.log(导出函数为:${r});}export { str,bool,num,arr,obj,foo}input.js 导入支持重命名import {str as STR,arr,obj,bool,num,foo as FOO} from ‘./output’console.log(STR)console.log(arr)console.log(obj)console.log(bool)console.log(num)FOO(‘参数’)继续重命名import * as newName from ‘./output’console.log(newName.str)console.log(newName.arr)console.log(newName.obj)console.log(newName.bool)console.log(newName.num)newName.foo(‘参数’)export defaultexport default的output.jsexport default { str: ‘string字符串’, bool: true, num: 123, foo: (r) => { console.log(导出函数为:${r}); }, arr: [1, 2, 3], obj: { a: 1, b: 2 }}input.jsimport defaultObj from ‘./output’console.log(defaultObj.str)console.log(defaultObj.arr)console.log(defaultObj.bool)console.log(defaultObj.num)console.log(defaultObj.obj)defaultObj.foo(’ef’)//=>导出函数为:efexport default的output.js同时支持如下写法const str = ‘string字符串’const bool = trueconst num = 123const arr = [1, 2, 3]const obj = {a: 1, b: 2}function foo(r) { console.log(导出函数为:${r});}export default { str, bool, num, arr, obj, foo}input.js不变总结这篇文章是对上一篇文章的总结和实践当直接给 module.exports时,exports会失效直接给exports赋值会切断exports和 module.exports的关联关系export,export default,exports,module.exports具体的使用方法实例更多前端资源请关注微信公众号“前端陌上寒”原文链接参考链接js 数组赋值问题 :值传递还是引用? ...

March 31, 2019 · 2 min · jiezi

AMD 和 CMD

脚本的无阻塞加载moduleA.js 代码console.log(“I’m A”);/此处可以放jquery源码使得该文件变大,以便异步加载时看效果/moduleB.js 代码console.log(“I’m B”);同步加载<body> <script src=“moduleA.js” onload=“console.log(‘A loaded’)"></script> <script src=“moduleB.js” onload=“console.log(‘B loaded’)"></script></body>输出I’m AA loadedI’m BA loadeddefer 和 asyncdefer:在文档完成解析后,触发 DOMContentLoaded 事件前执行。如果缺少 src 属性(即内嵌脚本),该属性不应被使用,因为这种情况下它不起作用。对动态嵌入的脚本使用 async=false 来达到类似的效果。async:是否在允许的情况下异步执行该脚本。该属性对于内联脚本无作用 (即没有src属性的脚本)。defer 示例<body> <script defer src=“moduleA.js” onload=“console.log(‘A loaded’)"></script> <script src=“moduleB.js” onload=“console.log(‘B loaded’)"></script></body>输出I’m BB loadedI’m AA loadedasync 示例异步加载<body> <script> loadScript(“moduleA.js”, “async A loaded”); loadScript(“moduleB.js”, “async B loaded”); function loadScript(url, text) { var srcEle = document.createElement(“script”); srcEle.src = url; srcEle.async = true; srcEle.onload = function () { console.log(text); }; document.body.appendChild(srcEle); } </script></body>动态创建的script标签,async默认为true;输出I’m Basync B loadedI’m Aasync A loaded相同之处:加载文件时不阻塞页面渲染使用这两个属性的脚本中不能调用document.write方法有脚本的onload的事件回调不同之处每一个async属性的脚本都在它下载结束之后立刻执行,同时会在window的load事件之前执行。所以就有可能出现脚本执行顺序被打乱的情况;每一个defer属性的脚本都是在页面解析完毕之后,按照原本的顺序执行,同时会在document的DOMContentLoaded之前执行AMD和CMDAMDRequireJS的标准特点:依赖前置、预执行define([’./a’, ‘./b’], function(a, b) { //运行至此,a.js和b.js已经下载完成 //a模块和b模块已经执行完 a.doing(); b.doing();});CMDSeaJS的标准特点:依赖就近、懒执行define(function(require, exports, module) { var a = require(”./a”); //等待a.js下载、执行完 a.doing(); var b = require(”./b”); //等待b.js下载、执行完 b.doing();});referenceAMD 和 CMD 的区别有哪些? ...

January 9, 2019 · 1 min · jiezi

npm包的发布和管理

npm包管理npm其实是Node.js的包管理工具(node package manager)。为啥我们需要一个包管理工具呢?因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到npm官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。npm的基础使用npm的指令其实常用的并不多官方文档;列出来如下面:access Set access level on published packagesadduserAdd a registry user accountauditRun a security auditbinDisplay npm bin folderbugs Bugs for a package in a web browser maybebuildBuild a packagebundleREMOVED 已删除cacheManipulates packages cacheciInstall a project with a clean slatecompletion Tab Completion for npmconfigManage the npm configuration filesdedupeReduce duplicationdeprecateDeprecate a version of a packagedist-tagModify package distribution tagsdocsDocs for a package in a web browser maybedoctorCheck your environmentseditEdit an installed packageexploreBrowse an installed packagehelp-searchSearch npm help documentationhelpGet help on npmhookManage registry hooksinitcreate a package.json fileinstall-ci-testInstall a project with a clean slate and run testsinstall-testInstall package(s) and run testsinstallInstall a packagelinkSymlink a package folderlogout Log out of the registrylsList installed packagesnpm javascript package manageroutdatedCheck for outdated packagesowner Manage package ownerspackCreate a tarball from a packagepingPing npm registryprefixDisplay prefixprofileChange settings on your registry profilepruneRemove extraneous packagespublish Publish a packagerebuildRebuild a packagerepo Open package repository page in the browserrestartRestart a packageroot Display npm rootrun-scriptRun arbitrary package scriptssearch Search for packagesshrinkwrapLock down dependency versions for publicationstarMark your favorite packagesstarsView packages marked as favoritesstartStart a packagestopStop a packageteamManage organization teams and team membershipstestTest a packagetokenManage your authentication tokensuninstallRemove a packageunpublishRemove a package from the registryupdateUpdate a packageversion Bump a package versionviewView registry infowhoamiDisplay npm usernameinit初始化创建package.jsonnpm init [–force|-f|–yes|-y|–scope]npm init <@scope> (same as npx <@scope>/create)npm init [<@scope>/]<name> (same as npx [<@scope>/]create-<name>)search搜索查看远程npm相关资源包信息npm search [-l|–long] [–json] [–parseable] [–no-description] [search terms …]aliases: s, se, findinstall可以是说是install是最为常见的命令官方介绍,npm install (with no args, in package dir)npm install [<@scope>/]<name>npm install [<@scope>/]<name>@<tag>npm install [<@scope>/]<name>@<version>npm install [<@scope>/]<name>@<version range>npm install <git-host>:<git-user>/<repo-name>npm install <git repo url>npm install <tarball file>npm install <tarball url>npm install <folder> alias: npm icommon options: [-P|–save-prod|-D|–save-dev|-O|–save-optional] [-E|–save-exact] [-B|–save-bundle] [–no-save] [–dry-run] In global mode (ie, with -g or –global appended to the command), it installs the current package context (ie, the current working directory) as a global package. The -g or –global argument will cause npm to install the package globally rather than locally. The -f or –force argument will force npm to fetch remote resources even if a local copy exists on disk.上面的还介绍已经很详细了,所以这里只是讲一下npm install packageName [|–save |–save-prod|–save-dev]的区别;npm install babel npm5以前,会把X包安装到node_modules目录中,不会修改package.json的dependencies字段,之后运行npm install命令时,不会自动安装Xnpm install babelnpm5以后,会把X包安装到node_modules目录中,会修改package.json的dependencies字段,之后运行npm install命令时,会自动安装X, 线上环境时会被安装npm install babel -P -P, –save-prod: Package will appear in your dependencies. This is the default unless -D or -O are present. Package will appear in your dependencies, With the –production flag (or when the NODE_ENV environment variable is set to production), npm will install modules listed in dependencies.npm install babel -DPackage will appear in your devDependencies,With the –production flag (or when the NODE_ENV environment variable is set to production), npm will not install modules listed in devDependencies. 会把X包安装到node_modules目录中,会在package.json的devDependencies属性下添加X,之后运行npm install命令时,会自动安装X到node_modules目录中,之后运行npm install –production或者注明NODE_ENV变量值为production时,不会自动安装X到node_modules目录中update升级某个资源包或者全部资源包到某一个版本或者匹配的最新版本。npm update [-g] [<pkg>…]aliases: up, upgradeuninstall移除某个资源包npm uninstall [<@scope>/]<pkg>[@<version>]… [-S|–save|-D|–save-dev|-O|–save-optional|–no-save]aliases: remove, rm, r, un, unlinknpm包创建、编写、测试、维护Node出现之前,JavaScript是缺少包结构的。CommonJS致力于改变这种现状,于是定义了包的结构规范。而NPM的出现则是为了在CommonJS规范的基础上,实现解决包的安装卸载,依赖管理,版本管理等问题。require的查找机制明了之后,我们来看一下包的细节。一个符合CommonJS规范的包应该是如下这种结构:一个package.json文件应该存在于包顶级目录下二进制文件应该包含在bin目录下(可选)JavaScript代码入库是index.js,其他包含在lib目录下文档应该在doc目录下(可选)单元测试应该在test目录下(可选)初始化包创建包的根目录mkdir testpackage初始化npm init // 需要进行一些基本配置编写创建入口文件touch index.js编写代码const updateQueryString = function(url, key, value) { let urlParts = url.split(’#’), hash = ‘’, uri = urlParts.shift(), re = new RegExp(([?&amp;])${key}=.*?(&amp;|$), ‘i’), separator = uri.indexOf(’?’) !== -1 ? ‘&’ : ‘?’, encodeKey = encodeURIComponent(key), encodeValue = encodeURIComponent(value); urlParts.length > 0 && (hash = #${urlParts.join('#')}); if (uri.match(re)) { return uri.replace(re, $1${encodeKey}=${encodeValue}$2) + hash; } else { return ${uri}${separator}${encodeKey}=${encodeValue}${hash}; }};// 最后的导出部分module.exports = { updateQueryString};测试创建包的根目录npm i mocha -D // 安装测试库npm i chai -D // 安装断言库mkdir testcd testtouch index.test.js编写测试代码const utils = require(’./../index.js’);const expect = require(‘chai’).expect;let { updateQueryString} = utils;describe(‘updateQueryString函数的测试’, function() { it(‘https://test.com/path?test=11 修改test参数为22 应该等于 https://test.com/path?test=22', function() { expect(updateQueryString(‘https://test.com/path?test=11', ’test’, 22)).to.be.equal(‘https://test.com/path?test=22'); });});运行测试cd …/node_modules/mocha/bin/mocha npm包的发布注册账号npm官网终端执行 npm login,输入用户名和密码 、邮箱npm publish 发布Organization包我们经常可以看到@angular、@ionic他们的包, 都可以以@开头,那么我们的可不可以,原来angular、ionic都属于一个组织(Organization)只有新创建一个Organization组织之后,才能创建@testorg/testpackname这样的包!!!那么我们就可以去官网上创建我们的Organization,命名之后,官方步骤,初始化npm init –scope=<your_org_name>npm init foo -> npx create-foonpm init @usr/foo -> npx @usr/create-foonpm init @usr -> npx @usr/create修改package.json里面的name字段为@your_org_name/<pkg_name>发布npm publish –access public // 公开包发布npm包支持esmodule ...

November 22, 2018 · 3 min · jiezi