本文共 20440 字,大约阅读时间需要 68 分钟。
function fn(){ arrList = [] arrList[100000] = 'bost'} // 申请空间let obj = { }// 使用空间obj.name = 'xl'// 释放空间obj = null JS中什么内容会被当作垃圾回收
知道了什么是垃圾之后,JS执行引擎,就会出来工作,把他们占的对象空间进行回收,这个过程就是所谓的JS垃圾回收
总结
let obj = { name: 'xl'} /** * 这行代码相当于这个空间被obj引用了 * * 当前这个obj是可以从根上找到的,所以这个obj是可达的 * */ let ali = obj /** * xl的空间又多了一次引用 * * 所以存在了一次引用数值变化,这个概念之后引用计数算法当中会被用到 * */ obj = null /** * 这行代码之后 * * 原本xl这个对象空间是由两个引用的,而随着这行的执行 * * obj到xl空间的引用,相当于是断掉了 * * 但现在当前这个xl对象还是可达的,因为ali还在引用着 * * 这就是引用的主要说明,顺便看到了一个可达 * */ function objGroup(obj1, obj2) { obj1.next = obj2 obj2.prev = obj1 return { o1: obj1, o2: obj2 }}/** * 首先,我们定义了一个函数并接受了两个变量,一个是obj1一个是obj2 * * 然后在内部让其有一个属性互相指引 * * 通过return返回这样一个结果,然后在外部调用函数 * * 现在的对象不管是o1还是o2再或者是objGroup返回的这个对象 * * 都可以从根上找到 * */ let obj = objGroup({ name: 'obj1'}, { name: 'obj2'})console.log(obj)/** * { * o1: { name: 'obj1', next: { name: 'obj2', prev: [Circular] } }, * o2: { name: 'obj2', prev: { name: 'obj1', next: [Circular] } } * } * */ function func() { name = 'xl' return `my name is ${ name}`}func() function func() { const name = 'xl' return `my name is ${ name}`}func() const user1 = { age: 18}const user2 = { age: 28}const user3 = { age: 38}const nameList = [user1.age, user2.age, user3.age]function fn() { const num1 = 1 const num2 = 2}fn() // 不可以获取内部变量function fn1() { num1 = 1 num2 = 2}fn1() // 可以获取到内部变量 function fn() { const obj1 = { } const obj2 = { } obj1.name = obj2 obj2.name = obj1 return 'xl'}fn()/** * 我们这个函数执行结束后,内部所在的空间,肯定会涉及到空间回收的情况 * * 比如说obj1 obj2 因为在全局的地方我们已经不在直接去指向他了 * * 所以这个是他的引用计数应该为0 * * 但是现在会有一个问题: * * 在里边当我们想要去找GC来把obj1删除时,obj2现在有一个属性指向obj1 * * 换句话说,按照之前的规则,我们在全局作用域下,找不到obj1和obj2了 * * 但是由于他两者之间在同一作用域内明显还有互相指引的关系 * * 所以在这种指引下他们身上的引用计数器的数值还不为0 * * 这时引用计数算法下的GC就没有办法将其回收,从而造成了内存空间的浪费 * * 这就是所谓的对象之间的循环引用 * */ 总结:
基本使用步骤
shift + esc调出任务管理器Benchmark.js 的 https://jsperf.com/ 完成function foo () { var name = 'xl' function fn () { console.log(name) } return fn}var a = foo()a() // function foo() { // var el = document.getElementById('btn') // el.onclick = function () { // console.log(el.id) // } // } // foo() /** * 标准闭包 * 1. 外部对内部有引用 * 2. 突破作用域的限制,在一个作用域中用到另一个作用于的数据 * * 因为它是闭包,所以会产生一个不好的影响,就是当前这样一个内存是会泄露的 * * 由于闭包语法的存在,导致我们函数中的一些变量是没有办法被回收 * * 这种情况下类似于这样的操作越来越多的时候,对我们的内存来说是非常不友好的 * * 当我们的内存一直被消耗,我们程序的性能肯定是越来越差 * */ function foo() { var el = document.getElementById('btn') el.onclick = function () { console.log(el) } el = null } foo() /** * 关于btn这个元素其实本身就已经存在于我们的DOM当中或者说在body里 * * 所以就算我们这里边不通过el再去引用这样的一个必填的DOM节点,那他本身也会有一个引用的存在 * * 而我们在这个地方是相当于在它的引用之上,又去让一个el也引用了这样一个DOM节点 * * 所以我们也可以理解为是这样一个DOM节点呗我们引用了两次,如果说在将来某一个时间点下 * * 我们这个DOM节点从我们的界面中消失了,也就是说删除或者清除的行为 * * 这是我们要想明白,我们在界面把元素删除,也就意味着在DOM上的引用就不存在了 * * 但是会有一个问题:代码里的el对我们之前的DOM还是有引用的,所以根据我们之前所提到的引用计数这个原则 * * 我们这个DOM对象其实只是减少了一个引用,而代码里边仍在引用这他,所以我们的垃圾回收机制在工作时无法回收 * * 因此我们的泄露依然存在,而如果说加了 el = null 时,当我们在界面当中去把页面的元素清除掉之后,DOM对它的引用就消失了 * * 而代码里边对他的引用也消失了,这个时候我们这个样一个内存空间得以释放,这也是这行代码存在的意义 * */ function Person1() { this.name = 'xl' this.age = 18 this.getAge = function () { return this. age }}const p1 = new Person1()const a = p1.getAge() // 属性访问方法function Person2() { this.name = 'xl' this.age = 18}const p2 = new Person2()const b = p2.age // 直接访问 for (var i = 0; i < btns.length; i++) { console.log(i)}for (var i = 0, len = btns.length; i < len; i++) { console.log(i)} var arrList = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9)arrList.forEach(function (item) { console.log(item)})for (var i = arrList.length; i; i--) { console.log(arrList[i])}for (var i in arrList) { console.log(i)}// forEach > for > for..in.. for (var i = 0; i < 10; i++) { var op = document.createElement('p') op.innerHTML = i document.body.appendChild(op)}const fragEle = document.createDocumentFragment()for (var i = 0; i < 10; i++) { var op = document.createElement('p') op.innerHTML = i fragEle.appendChild(op)}document.body.appendChild(fragEle) for (var i = 0; i < 3; i++) { var op = document.createElement('p') op.innerHTML = i document.body.appendChild(op)}var oldP = document.getElementById('box')for (var i = 0; i < 3; i++) { var newP = oldP.cloneNode(false) op.innerHTML = i document.body.appendChild(op)} var a = [1, 2, 3]var a1 = new Array(3)a1[0] = 1 a1[1] = 2 a1[2] = 3// a > a1
let a = 10;function foo (b) { let a = 2 function baz (c) { console.log(a + b + c) } return baz}let fn = foo(2)fn(3) // function dys (part, chapter) { // const parts = ['ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020']// if (part) { // if (parts.includes(part)) { // console.log('当前属于这个模块')// if (chapter > 5) { // console.log('您需要提供VIP')// }// }// } else { // console.log("请确认模块信息")// }// }// dys('ES2016', 6)function dys (part, chapter) { const parts = ['ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020'] if (!part) { console.log("请确认模块信息") return } if (!parts.includes(part)) return console.log("当前属于这个模块") if (chapter > 5) { console.log("您需要提供VIP") }}dys('ES2016', 6)/** * 优化的核心思想和作用域链的查找和内存的空间的使用并不是那么的有关系或者直观 * * 因为我们是从代码的整体的一个写法进行的改变 * * 首先就是代码量 * * 再有就是上边的代码就是一层一层的套,下边的直接去判断一层够了 * * 相当于我们判断问题的算法得到一个改变 * * 明确类条件的分支建议使用 switch..case... * * if..else...一般适合于区间的条件判断,如果我们明确了几个枚举值的时候建议使用switch...case... * * 这样代码会更加清晰,易于维护 * * 不过易于维护的代码并不代表执行速度就很快,这点对于性能优化来说还是要看我们需要什么来决定的 * */ // var name = 'xl'// function foo () { // name = 'xl666' // name属于全局 --- 修改了全局变量// function fn () { // var age = 38// console.log(age)// console.log(name)// }// fn()// }// foo()var name = 'xl'function foo () { var name = 'xl666' // name属于局局 --- 修改了局部变量 function fn () { var age = 38 console.log(age) console.log(name) } fn()}foo() // var box = document.getElementById('skip')// function hasbox (ele, cls) { // return ele.className === cls// }// console.log(hasbox(box, 'skip'))var box = document.getElementById('skip')function hasbox (ele, cls) { var clsname = ele.className return clsname === cls}console.log(hasbox(box, 'skip')) // let test = () => { // let obj = new Object()// obj.name = 'xl'// obj.age = 18// obj.slogan = '你好小鹿'// return obj// }// console.log(test())/** * 上边的方式就好像是在调用一个函数,而下边在创建时其实就是直接去开辟空间在里边存东西 * * 这个过程又涉及到了一个函数的调用,所以就相当于他做的事情更多一些 * */ let test = () => { let obj = { name : 'xl', age : 18, slogan : '你好小鹿' } return obj}console.log(test())var str1 = 'xl说我为XX学代码'/** * 上边的代码其实就是一行字符串,下边的是一个对象 * */ var str2 = new String('xl说我为XX学代码') // var test = () => { // var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]// for (var i = 0; i < arr.length; i++) { // console.log(arr[i])// }// }// test()// var test = () => { // var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],// i ,// len = arr.length// for (i = 0; i < len; i++) { // console.log(arr[i])// }// }// test()var test = () => { var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], len = arr.length while (len--) { console.log(arr[len]) }}test() var box = document.getElementById('box') var test = (ele) => { let w = ele.offsetWidth let h = ele.offsetHeight return w * h}console.log(test(box))var box = document.getElementById('box')var test = (ele) => { return ele.offsetWidth * ele.offsetHeight}console.log(test(box))var test = () => { var name = 'xl' var age = 18 var slogan = 'xl666lx' return name + ' ' + age + ' ' + slogan}console.log(test())var test = () => { var name = 'xl', age = 18, slogan = 'xl666lx' return name + ' ' + age + ' ' + slogan}console.log(test()) var box = document.getElementById('box')function foo () { console.log(this)}// function addEvent (obj, type, fn) { // if (obj.addEventListener) { // obj.addEventListener(type, fn, false)// }else if (obj.attachEvent) { // obj.attachEvent('on' + type, fn)// } else { // obj['on' + type] = fn// }// }// addEvent(box, 'click', foo)function addEvent (obj, type, fn) { if (obj.addEventListener) { addEvent = obj.addEventListener(type, fn, false) }else if (obj.attachEvent) { addEvent = obj.attachEvent('on' + type, fn) } else { addEvent = obj['on' + type] = fn } return addEvent}addEvent(box, 'click', foo) // var list = document.querySelectorAll('li')// function showTxt(ev) { // console.log(ev.target.innerHTML)// }// for (let item of list) { // item.onclick = showTxt// }var ul = document.getElementById('ul')function showTxt(ev) { var obj = ev.target if (obj.nodeName.toLowerCase() === 'li') { console.log(obj.innerHTML) }}ul.addEventListener('click', showTxt, true) 转载地址:http://tmwiz.baihongyu.com/