JS高级

Posted 学一点也是好

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS高级相关的知识,希望对你有一定的参考价值。

一、函数高级

1.函数回调

函数回调的本质:在一个函数中,满足特定条件下,调用另一个函数

// 回调的函数
function callback(data) {}
// 逻辑函数
function func(callback) {
    // 函数回调
    if (callback) callback(data);
}
技术分享图片
function a_fn(data) {
        console.log(a_fn);
        // 如果要使用数据,那么定义形参接收参数
        console.log(data);
    }

    function b_fn(a_fn) {
        var data = "b_fn 的 数据";
        console.log(b_fn);
        // 条件: a_fn有值(有函数实现体)
        if (a_fn) {
            // 调用参数函数
            a_fn(data);
        }
    }
    b_fn(a_fn);
test

总结:

   1.一个函数(函数名)作为另外一个函数的参数
   2.满足一定的条件,调用参数函数
   3.形成了函数回调,回调的函数可以获取调用函数的局部变量(将数据携带出去)

2.闭包

闭包本质:函数的嵌套定义,内层函数称之为闭包

闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决变量污染

function outer() {
    var data = {}
    //闭包
    function inner() {
        return data;
    }
    return inner;
}

注:外部使用局部变量的方法: 返回值 | 函数回调 | 闭包 | 提升作用域

2.1局部变量持久化

 function outer() {
        //eg:请求得到的数据,如果不持久化,方法执行完毕后,数据就会被销毁
        var data=[1,2,3,4,5];
        console.log(data);
        //通过闭包解决该类问题,所以闭包所有代码均可以随意自定义
        function inner(){
            return data;
        }
        //数据被inner操作返回,inner属于outer,所以需要将inner返回出去(跟外界建立联系)
        return inner;
    }
    //将局部变量生命周期提升于inner函数相同,inner存在,局部变量data就一直存在
    var inner = outer();

2.2闭包解决变量污染

现有一个列表,点击某个时,弹出下标

<script type="text/javascript">
    // 需求:点击li,打印li在ul中的索引 => 0, 1, 2, 3, 4
    // 1.lis 
    var lis = document.querySelectorAll(ul li);
    // 2.循环绑定
    for (var i = 0; i < lis.length; i++) {
        // 解决的原理:一共产生了5个外层函数,存储的形参i的值分别是0, 1, 2, 3, 4
        // 内层函数也产生了5个,且和外层函数一一对应,打印的i就是外层函数的形参i

        // 外层函数
        (function (i) {
            // 内层函数:闭包
            lis[i].onclick = function () {
                alert(i)
            }
        })(i)    
    }
    console.log(i);  // 点击事件触发一定晚于该逻辑语句
    // 所以再去触发点击,弹出i的值,永远是5

    // 该类问题就称之为变量污染
</script>

ES6的块级作用域的语法也可以解决循环绑定变量污染的问题

let lis = document.querySelectorAll(li);
    for (let i = 0; i < lis.length; i++) {
        lis[i].onclick = function () {
            alert(i)
        }
    }

二、JS的面向对象

1.面向对象初始

var obj = {}; | var obj = new Object();
// 属性
obj.prop = "";|obj[name]="";
// 方法
obj.func = function () {}
// 删除属性与方法
delete obj.prop
delete obj.func

2.类字典结构使用

js中没有字典(键值对存储数据的方式),但可以通过对象实现字典方式存储数据,并使用数据

var dict = {name: "zero", age: 18}
var dict = {"my-name": "zero", fn: function () {}, fun () {}}
//使用
dict.name | dict["my-name"] | dict.fn()
总结:
1.key全为字符串形式,但存在两种书写方式
2.key在js语法标识符支持情况下,可以省略引号,但key为js非法标识符的情况下,必须添加引号。
3.value可以为任意类型
4.访问值可以通过字典名(对象名).key语法与[“key”]语法来访问value
5.可以随意添加key与value完成增删改查
// 增
dict.key4 = true;
console.log(dict);

// 删
delete dict.key4;
console.log(dict);

// 改
dict["my-key3"] = [5, 4, 3, 2, 1];
console.log(dict);

// 查
console.log(dict.key1);
console.log(dict["key1"]);

3.构造函数

构造函数其实就是普通函数
特定的语法与规定:
1.一般采用首字母大写(大驼峰)
2.内部可以构建属性与方法,通过this关键词

// 普通函数
function fn() {
    var num = 10;
    console.log(普通函数);
}
fn();

//构造函数
function People(name) {
    this.name = name;
    this.eat = function (agr) {
        console.log(this.name + "" + agr);
    }
}

构造函数可以创建多个对象,使用{}构建出的对象是唯一的

var p1 = new People("zero");  // new关键词, 创建对象并实例化
var p2 = new People("seven");

var obj = {} //对象唯一

构造函数的属性变量与{}的语法规则不一样,构造函数内部通过this,二普通对象直接通过对象名.的方式

function People(name) {
    this.name = name;
    this.eat = function (agr) {
        console.log(this.name + "吃" + agr);
    }
}

//普通对象
var obj = {
    index: "obj对象",
    fn: function () {
        console.log("obj方法");
    }
};
// 使用属性与方法
console.log(obj.index);
obj.fn();

4.继承

1.完成继承,必须拥有两个构造函数
2.一个函数要使用另外一个函数的属性与方法,需要对其进行继承(属性与方法的复用)

4.1 ES5的继承

属性的继承用call方法,在继承函数中由被继承函数调用,传入继承函数的this与被继承函数创建属性对属性进行赋值的所有需要的数据
方法的继承prototype原型

    // 类似于父级
    function Sup(name) {
        // 属性存放某个值
        this.name = name;
        // 方法完成某项功能
        this.func = function () {
            console.log("func");
        }
    }
    var sup = new Sup("supClass");
    console.log(sup.name);
    sup.func();

    // 类似于子级
    function Sub(name) {
        // 属性的继承
        Sup.call(this, name);//Sup有name属性,那么可以通过call将Sub的name传给Sup
    }
    // 方法的继承
    Sub.prototype = new Sup; //将new Sup赋值给Sub.prototype

    var sub = new Sub("subClass");
    console.log(sub.name);
    sub.func();

    // 原型
    console.log(sup.__proto__);

4.2 ES6继承

// 多对象 => 创建类
    class Person {
        // 构造器:创建对象完成初始化操作
        constructor (name, age) {
            this.name = name;
            this.age = age;
        }
        // 实例方法:只能由对象调用
        eat () {
            console.log(this.name + ‘吃吃吃‘);
        }
        // 类方法:只能由类调用
        static create () {
            console.log(‘诞生‘);
        }
    }
    let p1 = new Person(‘zero‘, 8);
    let p2 = new Person(‘seven‘, 58);

    console.log(p1.age);
    p2.eat();
    // Person.eat();
    Person.create();
    // p2.create();


    // 继承
    class Student extends Person {
        constructor (name, age, sex) {
            // super指向父级
            super(name, age);
            this.sex = sex;
        }
    }

    let s1 = new Student("张三", 18, "男");
    // 属性的继承
    console.log(s1.name, s1.age, s1.sex);
    console.log();
    // 方法的继承
    s1.eat();
    // 继承为全继承
    Student.create();

补:ES6用箭头语法表示函数

// 函数
let f = () => {
}

5.属性解决循环绑定变量污染

还是用之前的变量污染的例子,js代码看下面

    var lis = document.querySelectorAll(‘li‘);

    for (var i = 0; i < lis.length; i++) {
        // lis[i]依次代表五个li页面元素对象
        // 给每一个li设置一个(临时)属性
        lis[i].index = i;  // 第一个li的index属性存储的就是索引0,以此类推,最后一个存储的是索引4

        lis[i].onclick = function () {
            // var temp = lis[i].index; // lis[i]中的i一样存在变量污染
            var temp = this.index;  // 当前被点击的li
            alert(temp)  // temp => this.index(lis[i].index) => i(索引)
        }
    }

三、定时器

应用场景:
1.完成js自启(不需要手动触发)动画
2.css完成不了的动画

  • setInterval  一次性定时器

  • setTimeout  持续性定时器

// 一次性定时器
    /* 异步执行
        setTimeout(函数, 毫秒数, 函数所需参数(可以省略));
    */
    console.log("开始");
    setTimeout(function (data) {
        console.log(data);
    }, 1000, "数据");
    console.log("结束");


    // 持续性定时器
    /*异步执行
        setInterval(函数, 毫秒数, 函数所需参数(可以省略));
    */
    console.log("又开始");
    var timer = setInterval(function() {
        console.log("呵呵");
    }, 1000)
    console.log(timer);
    console.log("又结束");

清除定时器

1.持续性与一次性定时器通常都应该有清除定时器操作
2.清除定时器操作可以混用 clearTimeout() | clearInterval()
3.定时器的返回值就是定时器编号,就是普普通通的数字类型

    document.onclick = function () {
        console.log("定时器清除了");
        clearInterval(timer);
        // clearTimeout(timer);
    }

    // 清除所有定时器
    // 如果上方创建过n个定时器,那么timeout值为n+1
    var timeout = setTimeout(function(){}, 1);
    for (var i = 0; i < timeout; i++) {
        // 循环将编号[0, n]所有定时器都清除一次
        clearTimeout(i)
    }
    // 1.允许重复清除
    // 2.允许清除不存在的定时器编号

 

以上是关于JS高级的主要内容,如果未能解决你的问题,请参考以下文章

Vue3官网-高级指南(十七)响应式计算`computed`和侦听`watchEffect`(onTrackonTriggeronInvalidate副作用的刷新时机`watch` pre)(代码片段

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

js代码片段: utils/lcoalStorage/cookie

JS代码片段:一个日期离现在多久了

js常用代码片段(更新中)