js-15 递归 斐波那契数列 快速排序 防抖节流 call apply 面向对象的创建

递归

递归: 函数里面调用自己的函数

注意: 一定要有函数结束的条件

将大的操作划分小操作重复执行的时候使用

报错: Uncaught RangeError: Maximum call stack size exceeded 栈溢出 ---> 原因: 递归函数没有设置结束条件

// 阶乘: 6! = 6 * 5 * 4 * 3 * 2 * 1
// function jc(n) {
//     return n * jc(n - 1);
// }
​
function jc(n) {
    // 设置结束条件
    if(n == 1){
        return 1;
    }
    return n * jc(n - 1);
}
var s = jc(6);
console.log(s);
console.log(jc(10));
console.log(jc(100));

斐波那契数列

有名的兔子问题: 出生2个月后每个月都会生产一对新兔子

月份 兔子

1 1 1

2 1 1

3 2 1 1

4 3 1 1 1

5 5 1 1 1 1 1

6 8 1 1 1 1 1 1 1 1

7 13 1 1 1 1 1 1 1 1 1 1 1 1 1

序列: 1 1 2 3 5 8 13 21

当前月的兔子 = 上个月的兔子个数 + 上上个月的兔子个数

第二个月和第一个月的时候 个数都是1

用函数求第n个月的兔子个数

function fib(n) {
    // 设置返回值 结束条件
    if(n == 1 || n == 2){ return 1; }
    return fib(n-1) + fib(n-2);
};
​
console.log(fib(6));
console.log(fib(12));
​
/* 
    第6个月的兔子 = 5 + 4
                = 4 + 3 + 3 + 2
                = 3 + 2 + 2 + 1 + 2 + 1 + 2
                = 2 + 1 + 2 + 2 + 1 + 2 + 1 + 2
*/

快速排序

快速排序: 找到中间项 进行左右重复排序的过程

\1. 有一个函数处理排序函数

\2. 找到中间项的下标

\3. 找到中间项

\4. 删除中间项

\5. 创建两个空数组 放置比中间项小 和 大的值

\6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边

\7. 左右数组需要重复排序

\8. 设置每次排序以后的返回结果

\9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回

var arr = [32, 12, 435, 56, 21, 78, 90];
// function qs(array) {
//     // 9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回
//     if(array.length <= 1){
//         return array;
//     }
//     // 2. 找到中间项的下标
//     var num = Math.floor(array.length / 2);
//     // console.log(num);
//     // 3. 找到中间项
//     var val = array[num];
//     // 4. 删除中间项
//     array.splice(num, 1);
//     // 5. 创建两个空数组 放置比中间项小 和 大的值
//     var left = [], right = [];
//     // 6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边
//     for(var i = 0; i < array.length; i++){
//         if(array[i] > val){
//             right.push(array[i]);
//         } else {
//             left.push(array[i]);
//         }
//     }
//     // 7. 左右数组需要重复排序
//     left = qs(left);
//     right = qs(right);
//     // 8. 设置每次排序以后的返回结果
//     return left.concat(val, right);
​
// };
​
function qs(array) {
    // 9. 设置排序结束条件: 当穿进去的数组长度小于等于1 的时候 直接返回
    if(array.length <= 1){
        return array;
    }
    // 2. 找到中间项的下标
    var num = Math.floor(array.length / 2);
    // 3-4:
    var val = array.splice(num, 1)[0];
    // 5. 创建两个空数组 放置比中间项小 和 大的值
    var left = [], right = [];
    // 6. 用数组的每一个项和中间项做比较 比他大的放右边 比她小的放左边
    for(var i = 0; i < array.length; i++){
        if(array[i] > val){
            right.push(array[i]);
        } else {
            left.push(array[i]);
        }
    }
    // 7-8
    return qs(left).concat(val, qs(right));
};
​
var a =qs(arr);
console.log(a);

事件频繁触发

为了解决事件频繁触发的问题 引申出了防抖和节流

防抖

防抖: 利用闭包, 在用户触发的事件过程中不进行事件的处理 等待用户停止触发多长时间后 再进行事件的处理

只要用户在输入或者是移动 就不触发事件处理函数 等用户停止1s后 在执行事件处理函数

只要用户触发 时间需要重新计时

问题: 太生硬

// 防抖函数
function debounce(fn, wait) {
    // 解决全局变量的问题
    var timer = null;
    return function () {
        // 清除定时器
        clearTimeout(timer);
        // 延迟定时器
        timer = setTimeout(fn, wait);
    };
}
// 获取元素
var div = document.querySelector('div');
var n = 0;
// 添加事件
div.onmousemove = debounce(inner, 3000);
​
function inner() {
    n++;
    div.innerHTML = n;
};

节流

节流: 在一定的时间内 只能触发一次事件处理函数

利用闭包 为了解决全局变量

// 节流函数
function throttle(fn, wait) {
    // 假设当前可以触发函数
    var tag = true;
    var timer = null;
    return function () {
        // 判断当前是否可以触发函数
        if(tag){
            // 将状态变成不可触发
            tag = false;
            // 开启定时器
            timer = setTimeout(function () {
                fn();
                // 将状态变成可触发
                tag = true;
                clearTimeout(timer);
            }, wait);
​
        }
    };
}
// 获取元素
var div = document.querySelector('div');
var n = 0;
// 添加事件
div.onmousemove = throttle(inner, 100);
​
function inner() {
    n++;
    div.innerHTML = n;
};

call和apply

call和apply: 改变this指向

区别:

函数.call(this的新指向, ...data); 参数一个个用,分隔直接写

函数.apply(this的新指向, [...data]); 第二个参数是一个数组

call

var obj = {
    name: '张三',
    sayName: function () {
        console.log(this.name);
    }
};
obj.sayName(); // 张三
​
var obj1 = {
    name: '李四'
};
obj.sayName.call(obj1); // 李四
​
function fn() {
    console.log(this);
}
fn(); // window
​
fn.call(document);
fn.call(undefined);
fn.call(1);
fn.call('a');
​
​
function fn1(a, b) {
    console.log(this, a, b);
}
fn1(20, 30); // window 20 30
fn1.call(1, 10, 20); // 1 10 20
​
// 判断数据的类型
console.log(Object.prototype.toString()); // [object Object]
console.log(Object.prototype.toString.call(1)); // [object Number]
console.log(Object.prototype.toString.call('aaa')); // [object String]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call({}).slice(8, -1)); // Object
console.log(Object.prototype.toString.call([]).slice(8, -1)); // Array

apply

function fn1(a, b) {
    console.log(this, a, b);
}

fn1.apply(document, [44, 33]);
// 数组找最大和最小项
var arr = [32, 43, 546, 56, 32, 534, 234, 65];
console.log(Math.max.apply(this, arr));
console.log(Math.min.apply(this, arr));

面向对象

概念

概念: 基于对象 

面向过程: 一步步分析实现  注重过程
面向对象: 一种编程思想    注重结果

核心: 对象 

组成:
    方法: 函数 行为
    属性: 描述 属性

以类创建模板 实例化对象的过程 
es5中 没有明确的类的概念 用函数去创建模板 实例化对象

实例化: 具象化对象的时候 就是实例化

遵循: 有对象就要用对象 没有对象就创建对象

特点:
    封装 继承 多态

创建对象

字面量

字面量: 只适用于单个对象的创建

var obj = {
    name: '张三',
    age: 33,
    work: function () {
        console.log('为了碎银几两 辛辛苦苦工作');
    }
};
console.log(obj);
console.log(obj.name);
obj.work();

new关键字

new关键字创建: 代码冗余

// 1. 创建空对象
var obj = new Object();

// 2. 添加属性和方法
obj.name = '杨洋';
obj.age = 38;
obj.work = function () {
    console.log('演员');
};

console.log(obj);
console.log(obj.name);
obj.work();

工厂模式创建

问题:

\1. 识别不清

\2. 内存浪费

// 工厂
function createObj(name, age) {
    // 1. 创建空对象
    var obj = new Object();

    // 2. 添加属性和方法
    obj.name = name;
    obj.age = age;
    obj.work = function () {
        console.log('工作去吧');
    };

    // 3. 出厂 设置返回值
    return obj;
};

// 实例化对象
var obj = createObj('张三', 33);
var obj1 = createObj('古力娜扎', 28);
console.log(obj, obj1);
console.log(obj.name, obj1.name);
obj.work();
obj1.work();

// 判断对象是否是由createObj函数创建
// 对象 instanceof 函数  true--是 false--不是
console.log(obj instanceof createObj); // false
console.log(obj.work == obj1.work); // false

构造函数

构造函数:
    1. 构造函数首字母大写 为了和普通函数进行区分 (约定)
    2. 方法和属性直接加给this
    3. 必须使用new进行调用, 否则和普通函数没有区别

new的发生了什么:
    1. 创建一个空对象
    2. 将this指向当前空对象
    3. 将函数prototype 赋值给 对象的__proto__
    4. 添加属性和方法
    5. 隐式返回对象

问题:
    1. 内存浪费
function CreateObj(name, age){
    // // 1. 创建空对象
    // var obj = new Object();

    // 2. 添加属性和方法
    this.name = name;
    this.age = age;
    this.work = function () {
        console.log('工作去吧');
    };

    // // 3. 出厂 设置返回值
    // return obj;
}

// 实例化:
var obj = new CreateObj('迪丽热巴', 38);
var obj1 = new CreateObj('古力娜扎', 38);
console.log(obj, obj1);

console.log(obj instanceof CreateObj); // true
console.log(obj.work == obj1.work); // false

原型创建

问题: 不能传参

// 1. 构造函数
function CreateObj() {  };

// 2. 给原型添加属性和方法
CreateObj.prototype.name = '迪丽热巴';
CreateObj.prototype.age = 39;
CreateObj.prototype.work = function () {
    console.log('工作');
};

// 3. 实例化对象
var obj = new CreateObj();
var obj1 = new CreateObj();
console.log(obj, obj1);
console.log(obj.name, obj1.name);

// 原型链: 在对象或函数被创建的时候所自带的链表关系, 实现继承和查找;
// 找: 先找自身, 在找原型属性  在找object 找到直接返回 找到object都没有 返回undefined
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

混合创建

构造创建(可变的) + 原型创建(不变的)

// 1. 构造函数
function CreateObj(name, age) {
    this.name = name;
    this.age = age;
};

// 2. 给原型添加属性和方法
CreateObj.prototype.work = function () {
    console.log('工作');
};

// 3. 实例化对象
var obj = new CreateObj('张三', 23);
var obj1 = new CreateObj('李四', 33);
console.log(obj, obj1);
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

动态混合创建(了解)

在构造函数中判断原型上的方法和属性是否是期望值 不是的话在进行赋值

// 1. 构造函数
function CreateObj(name, age) {
    this.name = name;
    this.age = age;

    if (typeof this.work == 'function') {
        console.log('已经是函数');
    } else {
        console.log('不是函数');
        // 2. 给原型添加属性和方法
        CreateObj.prototype.work = function () {
            console.log('工作');
        };
    }
};



// 3. 实例化对象
var obj = new CreateObj('张三', 23);
var obj1 = new CreateObj('李四', 33);
console.log(obj, obj1);
obj.work();
obj1.work();

console.log(obj.work == obj1.work); // true

原型

原型: 用来存储最顶层共享的方法和属性的对象
函数: prototype
对象: __proto__ 
var arr = [1,2,3,4];
arr.push(5);

console.log(arr);
console.log(arr.__proto__);


var brr = new Array(2,3,4,5);
console.log(brr);
console.log(brr.__proto__);
console.log(Array.prototype);

console.log(Array.prototype == brr.__proto__); // true

Array.prototype.push = function () {
    console.log('新方法');
};

brr.push(666);
console.log(brr);

原型链

原型链: 在对象或函数被创建的时候所自带的链表关系, 实现继承和查找;


版权声明:本文为ILove_bugs原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。