重新学习js部分知识点整理

对于作用和用法不过多解释,自行百度这里只列举部分知识点
学习参考文档: https://www.cnblogs.com/xiaohuochai/p/5613593.html.


函数

我主要是按照文档了解了函数的多种使用方法:记忆函数、不完全函数、惰性函数、AOP等

1.记忆函数

代码如下(示例):

// 主要功能:如果传入的参数已经被计算过一次就会把计算结果缓存到obj中,当下一次传入相同参数时直接返回原来的计算结果,如果没有经过计算则进行计算,然后存入缓存
  function memoize(fn) {
    let obj = {} // 用来存储
    return function () {
      let key = Array.prototype.join.call(arguments, ",");
      if (key in obj) {
        return obj[key] // 如果缓存里面已经有过相同的值就直接return出去
      } else {// 如果缓存里没有就将它添加到缓存
        obj[key] = fn.apply(this, arguments)
        return obj[key]
      }
    }
  }
  function newF() { // 求所有参数的和
    let sum = 0
    for (let index = 0; index < arguments.length; index++) {
      sum += arguments[index];
    }
    return sum
  }
  const newFcC = memoize(newF)
  console.log(newFcC(1, 2, 3));
  console.log(newFcC(2, 3, 4));
  console.log(newFcC(3, 3, 4));

2.惰性函数

代码如下(示例):

  // 惰性函数可以减少判断次数,只有在第一次执行时会走if语句,执行完if语句fa会被重新赋值就不需要再走if语句
let fa = (function(){
  if(test.a == 1) {
    return function(){
      console.log('a');
    }
  } else {
    return function(){
      console.log('b');
    }
  }
})()
console.log(fa); // function(){console.log('a');}

3.不完全函数

代码如下(示例):

// 个人理解就是将一个函数拆分成多次执行得到最终结果,下面是一个简单示例
  function myFn(f) {
    let args = [].slice.call(arguments, 1) // 获取传入进来的参数
    return function () {
      return f.apply(this, args.concat([].slice.call(arguments, 0))) // 获取其他参数
    }
  }
  function setSum() {
    let sum = 0
    for (let index = 0; index < arguments.length; index++) {
      sum += arguments[index]
    }
    return sum
  }
  const f1 = myFn(setSum, 10) // 第一个参数可以为一个常量
  console.log(f1(11)); // 第二个参数可以进行任意配置

4.AOP

代码如下(示例):

// AOP 面向切片编程,实现方式分为多种,这里写出一种
  Function.prototype.befor = function (f) {
    let self = this
    return function () {
      if (f.apply(self, arguments)) {
        return self.apply(this, arguments)
      } else {
        return f.apply(self, arguments)
      }
    }
  }
  Function.prototype.after = function(f){
    let self = this
    return function(){
      let ret = self.apply(this, arguments)
      // console.log(this, 123);
      // if (!ret){
      //   return false
      // }
      f.apply(this, arguments)
      return ret
    }
  }
  function xxx() {
    console.log('我是主要代码');
  }
  let test = {
    a: 2
  }
  const testB = xxx.befor(function(test){
    if (test) {
      return test.a == 2
    } else {
      return true
    }
  }).after(function(test){
    console.log('after', test);
  })
  testB(test)

闭包,this指向

1.闭包

网上找到的定义:闭包是指有权访问另外一个函数作用域中的变量的函数。可以理解为(能够读取另一个函数作用域的变量的函数)
我的理解:函数嵌套函数,(被嵌套的函数我称为子函数,外部函数我称为父函数),子函数始终持有对父函数的引用,这个子函数跟父函数就形成了闭包

使用闭包的注意点:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,
把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

简单说比普通函数更占用内存,会导致网页性能变差,在IE下容易造成内存泄露

关于常说的闭包会引起内存泄漏
什么是内存泄漏:长期的持有一块内存的引用,让它得不到释放。

闭包只有在IE9之前才会存在内存泄漏的情况,在IE8中,生成特定Dom节点所占用的内存是不会被释放的,即使这些节点被删除内存也不会被释放。
内存泄露的节点类型包括:form、button、input、select、textarea、a、img和objec
而且IE8使用的垃圾回收机制应该是标记清除,引用计数无法解决循环引用的问题
后面ie修复了这些问题,将DOM转为js对象并且使用了标记清除
(以上内容如果是在多个文档中找到整理的,如果存在问题会及时更正)
解决循环引用:
当dom对象不再被需要的时候将它置为null

2.this指向

this的四种绑定规则默认绑定隐式绑定显式绑定new绑定,分别对应函数的四种调用方式:独立调用方法调用间接调用构造函数调用。
默认绑定
js中this默认指向window,当一个函数被独立调用时,this都指向window

// 下面的fn都属于独立调用
function fn(){
  console.log(this) // window
}
fn()
let obj = {
  a:1,
  foo:function (){
    fn() // 独立调用
     }
}
obj.foo()// window

隐式绑定

    //一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象
    function foo1() {
        console.log(this.a);
    };
    var obj1 = {
        a: 1,
        foo: foo1,
        obj2: {
            a: 2,
            foo: foo1
        }
    }

    //foo()函数的直接对象是obj1,this隐式绑定到obj1
    obj1.foo1();//1

    //foo()函数的直接对象是obj2,this隐式绑定到obj2
    obj1.obj2.foo1();//2

显式绑定

    // 通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定
    var a = 0;
    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2
    };
    foo();//0
    foo.call(obj);//2

new绑定

// this绑定的是新创建的对象
let a = 1
function Person(){
	this.a = 2
	console.log(this,'person') // Person
}
let person = new Person()

总结

是否是new绑定?如果是,this绑定的是新创建的对象
是否是显式绑定?如果是,this绑定的是指定的对象
是否是隐式绑定?如果是,this绑定的是属于的对象
如果都不是,则使用默认绑定

JS垃圾回收机制

js存储方式:

javaScript 在定义变量时就完成了内存分配
**原始值(number, string, boolean, null, undefined)
:占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈(stack)中
复杂值(Object, Array):由于复杂值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此其存储在堆(heap)中,存储在变量处的值是一个指针,指向存储对象的内存处

js垃圾收集算法
js垃圾收集算法有两种:引用计数标记清除

引用计数

引用计数是最简单的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收
引用计数算法有个限制:无法处理循环引用。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。
它们被调用之后不会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收

    function f() {
        var o = {};
        var o2 = {};
        o.a = o2; // o 引用 o2
        o2.a = o; // o2 引用 o
        return "azerty";
    }
    f();

为了解决这个问题,最好是在变量不再被需要时手动将其置空赋值为null
将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收它们占用的内存

标记清除

javascript中最常用的垃圾收集算法是标记清除(mark-and-sweep),这个算法把“对象是否不再需要”简化定义为“对象是否可以到达”。如果对象不可到达,对象将被垃圾回收机制回收
标记清除被分为两个阶段:标记阶段(mark)和清除阶段(sweep)
标记阶段:每次js都会从根(根对象默认是全局对象)开始向下查找,每一个能从根对象被访问到的都会被加上一个标记,拥有标记的就是可到达对象
== 清除阶段==:垃圾回收器会对内存从头到尾进行线性遍历,如果发现有对象没有被标识为可到达对象,那么就将此对象占用的内存回收,并且将原来标记为可到达对象的标识清除,以便进行下一次垃圾回收操作
使用标记清除算法,循环引用不再是问题 上面的f() 在执行完成之后从全局出发无法获取因此,他们将会被垃圾回收器回收


提示:这篇文章只提供部分需要了解的知识点每一项的内容写的并不完整,有需要了解的地方需要自己百度,现在网上的很多文章给出的答案并不准确,需要自己多方对比自行判断

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值