#Js篇:闭包&内存溢出&内存泄露&事件委托&事件循环&拷贝&作用域-作用域链

闭包

什么是闭包?

函数嵌套函数,内部函数被外部函数返回并保存下来时,就会产生闭包。

特点:可以重复利用变量,并且这个变量不会污染全局的一种机制(可以实现变量的私有化);这个变量是一只保存在内存中,不会被垃圾回收机制回收.

缺点:闭包较多的时候,会消耗内存,导致页面性能下降。

使用场景: 防抖、截流,函数嵌套函数避免全局污染的时候。

  <script>
    function outer() {
      let a = 1;
      function inner() {
        a++
        console.log(a);
      }
      return inner;
    }
    let fn = outer()
    fn() // 2
  </script>

内存溢出

你要求分配的内存超出了系统能给你分配的,系统不能满足,产生溢出。

内存泄露

你向系统申请内存进行使用,使用完以后不归还,结果你申请的内存自己也不能使用了,系统也不会将你申请的内存分配给其它的需要的内存。

事件冒泡

<!DOCTYPE html>
<html>

<head>
  <title>event</title>
</head>
<style>
  #obj1 {
    width: 100px;
    height: 500px;
    background-color: red;
  }

  #obj2 {
    width: 100px;
    height: 100px;
    background-color: blue;
  }

  #obj3 {
    width: 100px;
    height: 100px;
    background-color: green;
  }
</style>

<body>
  <div id="obj1">
    welcome
    <h5 id="obj2">hello</h5>
    <h5 id="obj3">world</h5>
  </div>
  <script type="text/javascript">
    var obj1 = document.getElementById('obj1');
    var obj2 = document.getElementById('obj2');
    obj1.addEventListener('click', function () {
      alert('hello1');
    }, false); // 冒泡
    obj2.addEventListener('click', function (event) {
      event.stopPropagation() // 阻止事件冒泡到obj1
      alert('world2');
    }, false) // 冒泡

  </script>
</body>

</html>

事件委托

又叫事件代理,原理就是利用事件冒泡的机制来实现,也就说把子元素的事件绑定到父元素的身上。

如果字元素阻止了事件冒泡,那么委托也就不成立

阻止事件冒泡: event.stopPropagation

addEventListener(‘click’,函数名,true/false)

默认false—事件冒泡

true—事件捕获

优点:提高性能,减少事件的绑定

<body>
  <ul id="my-ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <script>
    let ulD = document.getElementById('my-ul')
    ulD.addEventListener('click', (e) => {
      console.log('e: ', e.target.innerText);
    }, true)
  </script>

堆栈的理解

堆是动态分配内存,内存大小不一,也不会自动释放(堆是由自动的垃圾回收来负责的)

数据类型:引用类型 数组、function

栈是自动分配相对固定大小的内存空间,并由系统自动释放。

数据类型:基本数据类型 优势:读取速度快

事件循环

原型和原型链

原型 就是一个普通的对象,它是为构造函数的实例共享属性和方法。所有实例中引用的原型都是同一个对象。

<script>
    function Person() {
      this.say = function () {
        console.log('say')
      }
    }
    let p1 = new Person()
    let p2 = new Person()
    p1.say()
    p2.say()
  </script>

使用prototype可以把方法挂在原型上,内存值保存一份

 	Person.prototype.look = function () {
      console.log('西游记');
    }
    let p1 = new Person()
    let p2 = new Person()

    p1.look() // 西游记
    p2.look() // 西游记
  </script>

__proto__可以理解为指针,实例对象中的属性。指向了构造函数的原型(prototype)

 console.log(p1.__proto__ === Person.prototype); // true

原型链

一个实例对象在调用属性和方法的时候,会依次从实例本身__proto__、构造函数原型prototype、原型的原型上去查找

new操作符的理解

  1. 先创建一个空对象
  2. 把空对象和和构造函数通过原型链链接
  3. 把构造函数的this绑定到新的空对象身上
  4. 根据构造函数返回类型判断,如果是值类型,则返回对象,如果是引用类型,则返回这个引用类型
<script>
    function newFun(Fun, ...args) {
      // 1. 先创建一个空对象
      let newObj = {}
      // 2. 把空对象和和构造函数通过原型链链接
      newObj.__proto__ = Fun.prototype
      // 3. 把构造函数的this绑定到新的空对象身上
      const result = Fun.apply(newObj, args)
      // 4. 根据构造函数返回类型判断,如果是值类型,则返回对象,如果是引用类型,则返回这个引用类型
      return typeof result instanceof Object ? result : newObj
    }
    function Person(name) {
      this.name = name
    }
    Person.prototype.say = function () {
      console.log('say');
    }
    const p1 = newFun(Person, '李四')
    p1.say()
    console.log('对象', p1);
    // say
    //  Person {name: '李四'}
  </script>

js如何实现继承

  1. 原型链接 ----无法穿参数
  2. 借用构造函数 — 方法不能共享
  3. 组合式继承
  4. es6的class继承

js的设计原理

js引擎

运行上下文

调用栈

事件循环

回调

js中this指向问题

  1. 全局对象中this —window
  2. 全局作用域或者普通函数 —window
  3. this永远指向最后调用它的那个对象 (在不是箭头函数的情况下)
  4. new关键字改变了this的指向
  5. apply call bind可以改变this执行
  6. 箭头函数中的this,它的指向在定义时候已经确定了,箭头函数没有自己的this,要看外层是否有函数,有就是外层函数的this,没有就是window
  7. 匿名函数中this====永远指向了window,匿名函数的执行环境具有全局性,因此this指向window

setTimeout最小执行时间

setTimeout最小执行时间是4ms—html5规定的内容

setInterval最小执行时间

setInterval最小执行时间是10ms—html5规定的内容

用递归的时候有没有遇到

递归就是一个函数可以调用函数本身

----函数内部调用自己

注意:写递归必须要有return

深拷贝

就是完全拷贝一份新的对象,会在堆中开辟新的空间,拷贝的对象被修改后,原对象不受影响

  1. 扩展运算符 —只能一层
  2. JSON.parse(JSON.stringify()) — 函数不会复制
  3. 递归
let origin = {
      name: '张三',
      age: 18,
      sex: '男',
      arr: [1, 2, 3, 4],
      // obj2: {
      //   name: 123123
      // },
      say() {
        console.log(1111);
      }
    }
    function extend(origin, deep) {
      let obj = {}
      if (origin instanceof Array) {
        obj = []
      }
      for (let key in origin) {
        let value = origin[key]
        obj[key] = (!!deep && typeof value === 'object' && value !== null) ? extend(value, deep) : value
      }
      return obj
    }
    const copy = extend(origin, true)
    copy.arr.unshift(999)
    console.log('origin: ', origin);
    console.log('copy: ', copy);
    // {name: '张三', age: 18, sex: '男', arr: Array(5), say: ƒ}age: 18arr: (5) [999, 1, 2, 3, 4]name: "张三"say: ƒ say()sex: "男"[[Prototype]]: Object

作用域作用域链

作用域分为

  1. 全局作用域

  2. 局部作用域

  3. 函数作用域

  4. 块级作用域

    作用域链

    当在js中使用一个变量的时候,首先在js引擎会尝试在当前作用域下去寻找改变量,如果没有找到,再到它的上层作用域中去寻找,一次类型知道找到该变量或者已经到了全局作用域。

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值