Closure 闭包:有权访问另一个函数作用域中变量的函数。 一个作用域可以访问另外一个函数内部的局部变量,就产生闭包,局部变量在函数执行完后不会被立即销毁,而是等所有函数调用完该变量后再销毁。 闭包的主要作用:延伸变量的作用范围。 过度使用闭包会造成内存泄漏。 应用 模拟类私有属性 // 模拟私有属性 function getGeneratorFunc() { var _name = "John"; var _age = 22; return function () { return { getName: function () { return _name; }, getAge: function () { return _age; }, }; }; } var obj = getGeneratorFunc()(); obj.getName(); // John obj.getAge(); // 22 obj._age; // undefined 柯里化(currying) 柯里化(currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 柯里化的优势之一就是参数的复用,它可以在传入参数的基础上生成另一个全新的函数,如函数bind方法的实现。 // bind Function.prototype.myBind = function (context = window) { if (typeof this !== "function") throw new Error("Error"); let selfFunc = this; let args = [...arguments].slice(1); return function F() { // 因为返回了一个函数,可以 new F(),所以需要判断 if (this instanceof F) { return new selfFunc(...args, arguments); } else { // bind 可以实现类似这样的代码 f.bind(obj, 1)(2),所以需要将两边的参数拼接起来 return selfFunc.apply(context, args.concat(arguments)); } }; }; // Example function typeOf(value) { return function (obj) { const toString = Object.prototype.toString; const map = { "[object Boolean]": "boolean", "[object Number]": "number", "[object String]": "string", "[object Function]": "function", "[object Array]": "array", "[object Date]": "date", "[object RegExp]": "regExp", "[object Undefined]": "undefined", "[object Null]": "null", "[object Object]": "object", }; return map[toString.call(obj)] === value; }; } var isNumber = typeOf("number"); var isFunction…
JS Engine
JS Tips
JS 日期格式化
JS 引擎加载脚本文件后:语法分析、预编译、解释执行。 匿名函数不参与预编译,只有在解释执行阶段才会进行变量初始化。 JS 执行线程 javascript 引擎执行的过程的理解--执行阶段 JS 是单线程的是指永远只有 JS 引擎线程在执行 JS 脚本程序,其他的三个线程只协助,不参与代码解析与执行。 JS 引擎线程:也称为 JS 内核,负责解析执行 Javascript 脚本程序的主线程(例如 V8 引擎)。 事件触发线程:归属于浏览器内核进程,不受 JS 引擎线程控制。主要用于控制事件(例如鼠标,键盘等事件),当该事件被触发时候,事件触发线程就会把该事件的处理函数推进事件队列,等待 JS 引擎线程执行。 定时器触发线程:主要控制计时器 setInterval 和延时器 setTimeout,用于定时器的计时,计时完毕,满足定时器的触发条件,则将定时器的处理函数推进事件队列中,等待 JS 引擎线程执行。(注:W3C 在 HTML 标准中规定 setTimeout 低于 4ms 的时间间隔算为 4ms。) HTTP 异步请求线程:通过 XMLHttpRequest 连接后,通过浏览器新开的一个线程,监控 readyState 状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进事件队列中,等待 JS 引擎线程执行。 注:浏览器对同一域名请求的并发连接数是有限制的,Chrome 和 Firefox 限制数为 6 个,ie8 则为 10 个 JS 异步执行机制——Even Loop JS 宏任务、微内核 Tasks, microtasks, queues and schedules 内存管理 内存泄漏 可能造成内存泄漏的原因 闭包的使用 全局变量的无意创建 DOM 元素绑定事件未随 DOM 元素的移除而注销 内存泄漏排查 内存泄露的排查手段 内存泄漏的解决方案 使用严格模式,避免不经意间的全局变量泄露 关注 DOM 生命周期,在销毁阶段记得解绑相关事件,或者可以使用事件委托的手段统一处理事件,减少由于事件绑定带来的额外内存开销 避免过度使用闭包 引申 setTimeout 与 setInterval 区别 防抖和节流
任何变量,如果未经声明就赋值,此变量是属于 window 的属性,而且不会做变量提升。(注意,无论在哪个作用域内赋值) function foo() { var a = (b = 100); // a和b的区别 } defer and async The best thing to do to speed up your page loading when using scripts is to put them in the head, and add a defer attribute to your script tag. Efficiently load JavaScript with defer and async
JS日期格式化转换方法 Date.prototype.format = function(fmt) { var o = { "M+" : this.getMonth()+1, //月份 "d+" : this.getDate(), //日 "h+" : this.getHours(), //小时 "m+" : this.getMinutes(), //分 "s+" : this.getSeconds(), //秒 "q+" : Math.floor((this.getMonth()+3)/3), //季度 "S" : this.getMilliseconds() //毫秒 }; if(/(y+)/.test(fmt)) { fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); } for(var k in o) { 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; } 龙恩0707 JS日期格式化转换方法 References Moment.js 轻量级的JavaScript时间库