js 学习笔记

目录:

  1. 闭包
  2. 深拷贝与浅拷贝
  3. 防抖与节流
  4. 实现lodsh的_.get
    5.函数柯里化

1. 闭包:

1. 概念:闭包是指有权访问另一函数作用域中变量的函数。

2. 原理:函数执行分为「预编译阶段」和「执行阶段」。
    「预编译阶段」:如果发现内部函数使用了外部函数的变量,则会在内存中创建一个“闭包”对象并保存对应变量值。如果已存在“闭包”,则只需增加对应属性值即可。
    「执行阶段」执行完后,函数上下文会被销毁,函数对“闭包”对象的引用也会被销毁,但其内部函数还持用该“闭包”的引用,所以内部函数可以继续使用“外部函数”中的变量。
    利用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域中。函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被销毁才被销毁。

3. 优点:
    i) 可以从内部函数访问外部函数作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用;
    ii) 避免变量污染全局;
    iii) 把变量存到独立作用域,作为私有成员使用;

4. 缺点:
    i) 对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收,增大内存使用,故使用不当会导致内存泄漏;
    ii) 对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度;
    iii) 可能获取到意外的值(captured value);
for (var i = 0; i < 5; i++){
    setTimeout(() => {
        console.log(i)
    }, 0);
} // 5 5 5 5 5
// 改成闭包
for (var i = 0; i < 5; i++){
    (function(i) {
        setTimeout(() => {
            console.log(i)
        }, 0);
    }(i));
} // 0 1 2 3 4

2. 深拷贝与浅拷贝

https://www.cnblogs.com/echolun/p/7889848.html


3. 防抖与节流

/**
 * 防抖:
 * 1. 原理:在事件被触发n秒后执行,若在这n秒内又被触发,则重新倒计时
 * 2. 试用场景:
 *    a. 按钮提交场景:防止多次提交按钮,只执行最后一次的提交
 *    b. 搜索框联想场景:只发送最后一次请求
*/
export const debounce = function(func, wait) {
    let timeout;
    return function() {
        const context = this;
        const args = arguments
        clearTimeout(timeout);
        timeout = setTimeout(function() {
            func.apply(context, args);
        }, wait);
    }
};

/**
 * 节流:
 * 1. 原理:规定在一定时间内只能触发一次函数。若在该时间内多次触发,则只生效一次
 * 2. 试用场景:
 *    a. 拖拽场景:固定时间内只执行一次,防止超高频触发位置变动
 *    b. 缩放场景:监控浏览器resize
 *    c. 滑动场景:监控浏览器scroll
 * 3. 实现方式:
 *    a. 时间戳
 *    b. setTimeout
*/
export const throttleFun1 = function(func, wait) {
    let previous = 0;
    return function() {
        let now = new Date();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    };
};
export const throttleFun2 = function(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(function(){
                func.apply(context, args);
                timeout = null;
            }, wait);
        }
    };
};

4. 实现lodsh的_.get

(在js中经常会出现嵌套调用,如a.b.c.d.e,但是这么写容易抛出异常。需要逐层判断:a && a.b && a.b.c && a.b.c.d && a.b.c.d.e,但是这么写太冗余)

export const get = (source, path, defaultValue) => {
    // a[3].b => a.3.b => [a,3,b]
    // path中可能是数组下标的路径,需全部转化成.
    const paths = path.replace(/\[(\d+)\]/g, '.$');
    let result = source;
    for (let p of paths) {
        // null 与 undefined取属性会报错
        result = Object(result)[p];
        if (result === undefined) {
            return defaultValue;
        }
    }
    return result;
};

5. 函数柯里化:

概念:柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

export const currying = (fn) => {
    let args = [];
    let context = this;
    return function temp(...newArgs) {
        console.log('newArgs ===', newArgs)
        if (newArgs.length) {
            args = [
                ...args,
                ...newArgs
            ];
            return temp;
        }
        else {
            let val = fn.apply(context, args);
            args = [];
            return val;
        }
    }
};

function add (...args) {
    //求和
    return args.reduce((a, b) => a + b)
}

let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)())  //15
console.log(addCurry(1)(2)(3, 4, 5)())  //15
console.log(addCurry(1)(2, 3, 4, 5)())  //15

你可能感兴趣的:(js 学习笔记)