阅读 230

前端开发核心知识进阶 读书笔记

01、this

02、闭包

调用栈

function fn1() {   fn2() } function fn2() {   fn3() } function fn3() {   fn4() } function fn4() { debugger   console.log('fn4') } fn1() 复制代码

对应可以使用上面的调试按钮,看一看函数出栈的过程,压栈和弹栈这个过程就非常清楚了。

image.png

闭包

比较通俗的理解:函数嵌套函数时,内层函数引用了外层函数作用域下的变量,并且内层函数在全局环境下可访问,这就形成了闭包。

如下代码匿名函数访问了外层函数的num变量,并且在全局作用域中可以访问到这个匿名函数

function numGenerator() {   let num = 1   return () => {     console.log(num++)   } } let getNum = numGenerator() getNum() 复制代码

所以numGenerator函数执行完毕以后,相关调用栈出栈以后,变量num不会消失,仍然有机会被外界访问到。

image.png

内存管理

var foo = 'bar'  // 分配内存 alert(foo)       // 读写内存 foo = null       // 释放内存  复制代码

内存管理泄露案例

第一个

<div id="element">     <div>test</div> </div> var element = document.getElementById('element') element.mark = 'marked' // 移除 element 节点 function remove() {   element.parentNode.removeChild(element) } 复制代码

image.png 第二个

<div id="element"> </div> var element = document.getElementById('element') element.innerHTML = '<button id="button">点击</button>' var button = document.getElementById('button') button.addEventListener('click', function() {   //..... }) element.innerHTML = '' 复制代码

image.png 所以还需要调用removeEventListaner函数,以防止内存泄露。

第三个

function foo() {   var name = '小明'   window.setInterval(function(){     console.log(name)   }, 1000) } foo() 复制代码

调用这段代码之后name变量空间始终无法释放。一定要使用clearInterval来进行清理。

第四个

function foo() {   let value = Math.random()   return () =>{     console.log(value)   } } let bar = foo() bar() bar = null 复制代码

image.png

devtool 排查问题

可以看出这两者都是随着时间在一直上升的。 image.png

分析内存, 对占比比较大的进行分析。---

image.png

03、我们只实现API

jQuery 中的offset()

如何获取文档中任意一个元素与文档顶部的距离?

这里我们使用getBoundingClientRect() 这个方法来实现。递归的方式有兴趣可以去研究。

var id = document.getElementById("app"); var clientTop = id.clientTop; function offset(element) { let result = element.getBoundingClientRect(); let docElement = element.ownerDocument.documentElement; return {   left: result.left + window.pageXOffset - docElement.clientLeft,   top: result.top + window.pageYOffset - doc4Element.clientTop, }; } // element.ownerDocument 是DOM节点的一个属性,返回当前节点的顶层 document对象 // window.pageXOffset  // x轴滚动的距离 // window.pageYOffset  // y轴滚动的距离 let result = offset(id); 复制代码

实现一个reduce()函数

ing 复制代码

compose() 函数

主要用于执行一连串长度不定的任务(方法)

看如下代码

const fn1 = x => x + 1 const fn2 = x => x * 3 const fn3 = x => x / 2 let ret = fn1(fn2(fn3(2)))   // 2/2 * 3 + 1 console.log(ret)             // 4 复制代码

这段代码的功能是把每一个函数执行的结果交给下一个函数当做参数。现在我们有三个函数,我们可以把代码写成这样,假设我们有更多的函数呢?

所以我们期待有一个这样的函数, 从右往左依次执行。 let funcs = [fn1,fn2,fn3] let operate = compose(funcs)     // 这个函数里面实现串行任务的执行。 operate(2)                       // 用于接收第一个函数的 入参 复制代码

于是我们想到了reduce函数

  function compose(...funcs) {     // x 存储的就是第一个函数执行的时候的实参 。就是最内部的函数执行的参数     // 翻转顺序     funcs = funcs.reverse()     return function(x) {       return funcs.reduce((accumulator, currValue)=>{         // 把上一个函数执行的结果交给当前函数         return currValue(accumulator)       }, x)     }   } 复制代码

实现pipe 函数

pipecompose 函数 只是执行的顺序不同,如果用recude实现的话就是把内部的reverse去掉就可以了。用数组本身的顺序去执行。

// compose  fn1(fn2(fn3(2))) // pipe  fn3(fn2(fn1(2))) 复制代码

实现一个bind函数

ing 复制代码

04、js高频考点及基础只是题库

数据类型分类

5中基本数据类型:number,string,boolean,undefined,null

其余都是object类型。

typeof

typeof 'a'       // 'string' typeof 1         // 'number' typeof undefined // 'undefined' typeof true      // 'boolean' 复制代码

null比较特殊

typeof null  // 'object' 复制代码

判断复杂类型

const fn = () => {} typeof fn             // 'function' let obj = {} typeof obj            // 'object' let arr = [] typeof arr            // 'object' let date = new Date() typeof date           // 'object' let foo = Symbol('foo') typeof foo            // 'symbol' 复制代码

总结:使用 typeof可以精确地判断出除了 null之外的基本数据类型,以及function类型 symbol类型。null会被typeof判断为 object

instanceof 判断

a instanceof B 判断的是 a 是否为 B 的实例 , 也就是 在 a 的原型链上是否存在 B 的构造函数。

function Person(name){     this.name = name } const a = new Person('小敏') console.log(a instanceof Person)   // true console.log(a.__proto__.constructor === Person)  // true console.log(a.__proto__.constructor === Person.prototype.constructor)  // true console.log(Person.prototype.__proto__ === Object.prototype)  // true console.log(a instanceof Object)  // true console.log(a instanceof Person)  // true 复制代码

我们发现在我们写一个函数的时候js在内部会给这个函数添加一个prototype的属性 如下代码

function Person(name){     this.name = name } console.log(Person.prototype) 并且这个prorotype 还有个 constructor的是属性指向函数本身。 复制代码

image.png

实现 instanceof

function instanceOfMock(L, R) {   // 先对左边的进行类型判断    if(typeof L !== 'object') return false   while(true) {       // 找到了 Object.prototype.__proto__ (最顶部)       if(L === null) return false       if(R.prototype === L.__proto__) return true       L = L.__proto__   } } // 记住一个 实例的 __proto__ === 构造函数的 prorotype (也就是new 的原理了) console.log(a.__proto__ === Person.prototype) console.log(instanceOfMock(a, String)) 复制代码

终极方法 Object.prorotype.toString.call()


作者:一咻
链接:https://juejin.cn/post/7038248485967101983

 伪原创工具 SEO网站优化  https://www.237it.com/ 


文章分类
前端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐