js高级学习笔记

🍊ES6中的类和对象

🍊创建类

语法

// 1.创建类
class Star{
    constructor(uname,age){
        this.uname = uname;
        this.age = age;
    }
}
// 2.利用类创建对象 new
var ldh = new Star('刘德华',18)
var zxy = new Star('张学友',20)
console.log(ldh.uname)  // 打印一个对象:刘德华,18
console.log(zxy.uname)  // 打印一个对象:张学友,20

🍊类中添加方法

  • 类里面所有的函数不需要写function
  • 多个函数方法之间不需要添加逗号分隔
// 1.创建类
class Star{
    constructor(uname,age){
        this.uname = uname;
        this.age = age;
    }
    sing(song){
        console.log(this.uname+song)
    }
    // 
}
// 2.利用类创建对象 new
var ldh = new Star('刘德华',18)
var zxy = new Star('张学友',20)
console.log(ldh.uname)  // 打印一个对象:刘德华,18
console.log(zxy.uname)  // 打印一个对象:张学友,20
// 调用方法
ldh.sing('冰雨')
zxy.sing('李香兰')

🍊类的继承

  • extends关键字
  • 子类 继承 父类里面的属性和方法
class Father{
    constructor(){
        
    }
    money(){
        console.log(100)
    }
}
class Son extends Father{
    
}
var Son = new Son();
son.money();   // 打印 100

🍊super关键字

🍊调用构造函数
  • super 关键字用于访问和调用父类对象的函数,可以调用父类构造函数,也可以调用父类的普通函数

错误用法-----sum函数中的 this 是指向父类的,父类中的 this 未定义

class Father{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    sum(){
        console.log(this.x+this.y);
    }
}
class Son extends Father{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
}
var Son = new Son(1,3);
son.sum();   // 打印 100

正确用法

class Father{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    sum(){
        console.log(this.x+this.y);
    }
}
class Son extends Father{
    constructor(x,y){
		super(x,y)  //调用了父类的构造函数
    }
}
var Son = new Son(1,3);
son.sum();   // 打印 100
🍊调用普通函数
  • 若子类中有调用的方法就输出子类的方法 ---------------重写
  • 若子类没有该方法 就去父类查找 调用父类的方法------继承
class Father{
    say(){
        return '我是爸爸'
    }
}
class Son extends Father{
    say(){
        console.log('我是儿子')
    }
}
var son = new Son();
son.say(); 
  • 用 super 关键字直接调用父类的方法
class Father{
    say(){
        return '我是爸爸';
    }
}
class Son extends Father{
    say(){
        // console.log('我是儿子')
        console.log(super.say()+'的儿子')  // super 可以看做Fathe类
    }
}
var son = new Son();
son.say(); 
🍊既要调用子类的方法,也要掉用父类的方法
class Father{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    sum(){
        console.log(this.x+this.y);
    }
}
class Son extends Father{
    constructor(x,y){
        super(x,y)  //调用了父类的构造函数
        // super 必须要在this之前调用
        this.x = x;
        this.y = y;
    }
    constructor(){
        console.log(this.x-this.y)
    }
}
var Son = new Son(4,3);
son.constructor(); // 输出 1
son.sum();   // 输出 7

注意:

  • 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象

  • 类里面的共有的属性和方法一定要加 this 使用

  • 类里面 this 的指向问题

constructor 里面的 this 指向的是创建的实例对象 
方法里面的 this 指向的是调用者

🍊Tab 栏切换案例

抽象对象:Tab 对象

  1. 该对象具有切换功能
  2. 该对象具有添加功能

image-20220328150258219

  1. 该对象具有删除功能

image-20220328153733829

  1. 该对象具有修改功能

image-20220328162732732

class Tab{
    var that;
    constructor(id){
        that = this;
        // 获取元素
        this.main = document.querySelector(id);
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
        this.add = this.main.querySelectorAll('section');
        // li 的父元素
        this.ul = this.main.querySelector('.fisrstnav ul:first-child');
        // section 的父元素
        this.fsection = this.main.querySelector('.tabscon');
        // 方法可以直接放在构造器中,因为在外面 new 了Tab 这个实例对象会调用
        // 构造器里面的方法
        this.init();
    }
    // 初始化
    init(){
        this.updateNode();
        // init 初始化操作让相关的元素绑定事件
        this.add.onclick = this.addTab;
        for (var i = 0;i<this.lis.length;i++){
            this.lis[i].index = i;
            // 这里 toggleTab 后面不需要加小括号,否则页面加载后就直接				
            // 调用了;不加小括号就是点击之后才调用
            this.lis[i].onclick = this.toggleTab;
            this.remove[i].onclick = this,removeTab;
            this.spans[i].ondbclick= this.editTab;
            this.sections[i].ondbclick= this.editTab;
        }
    }
    // 获取所有的小 li 和 section
    updateNode(){
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
        this.remove = this.main.querySelectorAll('.icon-guanbi');
        this.spans = this.main.querySelectorAll('.firstnav li span:first-child');
    }
 	// 1.切换功能
    toggleTab(){
        this.clearClass();
        this.className = 'liactive';
        that.sections[this.index].className = 'concative'
    }
    // 清空样式
    clearClass(){
        for (var i = 0;i<this.lis.length;i++){
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }
    // 2.添加功能
    addTab(){
        that.clearClass();
        // 创建 li 元素 和 section 元素
        let li = `<li class="liactive"><span>新选项卡</span><span class="iconfont 						icon-guanbi"></span></li>`;
        let section = `<section class="conactive">测试1</section>`;
        // 把这两个元素追加到对应的父元素中
        // insertAdjacentHTML 方法可以将 字符串添加到父元素中
        // beforenend 表示在父元素的最后面追加
        that.ul.insertAdjacentHTML('beforeend',li);
        that.fsection.insertAdjacentHTML('beforeend',section);
        that.init();
    }
    // 3.删除功能
    removeTab(e){
        // 防止冒泡,阻止 tab 切换效果
        // 使用stopPropagation()函数可以阻止当前事件向祖辈元素的冒泡传递,也就是说该事件不会触		 // 发执行当前元素的任何祖辈元素的任何事件处理函数。
        e.stopPropagation();
        // remove 没有索引号,可以用remove 父亲的索引号
        let index = this.parentNode.index;
        // remove 方法可以直接删除指定的元素
        that.lis[index].remove();
        that.sections[index].remove();
        that.init();
        // 当我们删除的不是选中状态的 li 则只需要删除 li 不改变选中状态
        if(document.querySelector('.liactive')) return;
        // 当我们删除了选中状态的li 的时候,让它前一个li 处于选中状态
        index--;
        // click() 这个方法手动调用我们的点击事件,不需要用鼠标触发
        // that.lis[index] && that.lis[index].click(); 前面为真则执行点击事件
        // 否则不执行
        that.lis[index] && that.lis[index].click();
    }
    // 4.修改功能
    editTab(){
        // 获取原本的内容
        var str = this.innerHTML;
        // 双击机制选定文字
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        this,innerHTML = '<input type="text"/>'
        var input = this.children[0];
        input.value = str;
        input.select(); // 让文本框的文字处于选中状态
        // 当离开文本框(失去焦点)就把文本框里面的值给 span
        input.onblur = function(){
            this.parentNode.innerHTML = this.value
        }
        // 按下回车也可以吧文本框里面的值给 span
        input.onkeyup = function(e){
            if(e.keyCode === 13){
                // 手动调用表单失去焦点事件 不需要鼠标离开操作
                this.blur();
            }
        }
    }
}
new Tab('#tab')

🍊构造函数和原型

🍊概述

创建对象的三种方式:

  1. 对象字面量

    var obj2 = {}

  2. new Object()

    var obj2 = new Object();

  3. 自定义构造函数

    function Star(uname,age){
        this.uname = uname;
        this.age = age;
        this.sing = function(){
            console.log('我会唱歌')
        }
    }
    var ldh = new Star('刘德华',18);
    console.log(ldh)
    

    new 在执行时会做四件事情

    1. 在内存中创建一个新的空对象
    2. 让 this 指向这个新对象
    3. 执行构造函数里面的代码,给这个新对象添加属性和方法
    4. 返回这个新对象(所以构造函数里面不需要 return)

🍊构造函数

  • 实例成员- 就是构造函数内部通过 this 添加的成员
    • 实例成员只能通过实例化的对象来访问
      • console.log(ldh.uname)
    • 不可以通过构造函数来访问实例成员
      • console.log(Star.uname)
  • 静态成员- 在构造函数本身上添加成员
    • Star.sex = '男'; 这就是一个静态成员
    • 只能通过构造函数来访问 console.log(Star.sex)
    • 不能通过对象来访问 console.log(ldh.sex) “不行”

🍊构造函数的问题

  • 同一个函数放在不同构造函数,会浪费内存空间

image-20220329101205750

🍊构造函数原型 prototype

  • 构造函数通过原型分配的函数时所有对象所共享的

  • javaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。注意这个 prototype 就是一个对象。这个对象的所有方法和属性,都会被构造函数所拥有

  • 可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法了

Star.prototype.sing = function(){
    console.log('我会唱歌')
}
ldh.sing(); // 输出: 我会唱歌
zxy.sing(); // 输出: 我会唱歌

问答:

1. 原型是什么?
	是一个对象,我们也称为 prototype 为原型对象
2. 原型的作用是什么?
	共享方法

🍊对象原型 __proto__

  • 对象都会有一个属性 __proto__,指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数的属性和方法,就是因为对象有__proto__原型的存在
  • __proto__对象原型和原型对象 prototype是等价的
  • 方法的查找规则:首先看看 ldh 对象上是否有 sing 方法,如果有就执行这个对象上的 sing 方法;如果没有 sing 这个方法,因为有__proto__ 的存在,就去构造函数原型对象 prototype 身上去查找 sing 这个方法
  • 注意:__proto__对象的原型的意义在于为对象的查找机制提供一个方向,或者说一条线路,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype
Star.prototype === ldh.__proto__ // 返回 TRUE

🍊constructor 构造函数

  • 对象原型(__proto__)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性,constructor 我们称为构造函数,因为他指向构造函数本身
  • constructor 主要用于记录对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数
Star.prototype = {
    // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利	   用constructor指回原来的构造函数
    construtor:Star,
    sing:function(){
        console.log('我会唱歌')
    },
    movie:function(){
        console.log('我会演电影')
    }  
}
var ldh = new Star('刘德华',18);
var zxy = new Star('张学友',19);
console.log(Star.prototype.construtor);
console.log(ldh.__proto__.construtor);

image-20220330151733631

🍊原型链

image-20220330153307444

🍊js 中成员查找机制(规则)

  • 从 ldh 对象实例中 层层往上找,如下图所示
  • 优先级 (最下层优先),若在找到了该对象 则不会继续往上找

image-20220330153910758

🍊原型对象的this指向

  • 原型对象里面的 this 指向的是实例对象
var that;
Star.prototype.sing = function(){
    console.log('我会唱歌');
    that = this
}
var ldh = new Star('刘德华',18)
ldh.sing();
console.log(that === ldh) // 打印: true

🍊扩展内置对象

Array.prototype.sum = function(){
   var sum = 0;
   for(var i = 0;i<this.length;i++){
       sum += this[i]
   }
   return sum;
}
var arr = [1,2,3]
console.log(arr.sum()); // 6
var arr1 = new Array(11,22,33);
console.log(arr1.sum());

🍊继承

🍊 call()

调用这个函数,并修改函数运行时的 this 指向

fun.call(thisArg,arg1,arg2,...);
// 含有几个参数
// 1. thisArg: 当前调用函数 this 指向对象
// 2.arg1,arg2: 函数需要传递的参数

几个作用:

  1. 调用函数

    例:fn.call();

  2. 修改函数里的this指向

    // 例如
    function fn(){
        console.log('我想喝手磨咖啡');
        console.log(this) // this 指 向 window
    }
    var o = {
        name:'andy';
    }
    fn.call() // 原本 fn 的this是指向调用者也是就是window this=>window
    fn.call(o)// this 指向o 此时fn函数里面的console.log(this) 会打印 o 这个对象
    // -----------------------------
    fn.call(0,1,2) // 后面两个参数是需要传进fn里面的参数,fn 需要接受这个参数
    

🍊继承

🍊继承属性

// 借用福构造函数继承属性
// 1. 父构造函数
function Father(uname,age){
    // this 指向父构造函数的对象实例
    this.uname = uname;
    this.age = age;
}
// 2.子构造函数
function Son(uname,age){
    // this 指向子构造函数的对象实例
    // call 把父构造函数的 this 改成 指向子构造函数的 this
    Father.call(this,uname,age);
}
var son = new Son('刘德华',18)
console.log(son)

🍊继承方法

// 借用福构造函数继承属性
// 1. 父构造函数
function Father(uname,age){
    // this 指向父构造函数的对象实例
    this.uname = uname;
    this.age = age;
}
// 父构造函数的原型对象
Father.prototype.money = function(){
    console,log(10000)
}
// 2.子构造函数
function Son(uname,age){
    // this 指向子构造函数的对象实例
    // call 把父构造函数的 this 改成 指向子构造函数的 this
    Father.call(this,uname,age);
}
// Son.prototype = Father.prototype 这样直接会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
// 一般这么采用,实例化一个 Father 对象 跟原来的构造函数分格开来
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用 constructor 指回原来的原型对象
Son.prototype.constructor = Son;
var son = new Son('刘德华',18)
console.log(son)

image-20220401111150538

🍊es5 中新增的方法

🍊数组方法

  • foreach 方法

    • 遍历这个数组

    • var arr = [1,2,3]
      arr.forEach(function(value,index,array){
          console.log('每个数组元素'+value);
          console.log('每个数组元素的索引号'+index);
          console.log('数组本身'+array)
      })
      
  • filter 筛选数组

    • 筛选数组

    • var arr = [12,66,4,88];
      var newArr = arr.filter(function(value,index){
          return value >= 20;
      })
      console.log(newArr) // 打印 [66,88]
      
  • **some **

    • 检测数组中的元素是否满足条件,返回布尔值

    • var arr = [10,30,4]
      arr.some(function(value){
          return value >= 20;
      })
      console.log(flag); // 返回 TRUE
      

some 和 forEach 的区别

  • 在 forEach 里面 return 不会终止迭代
  • 在 some 里面 遇到了return true 就是终止遍历
  • filter 也不会终止迭代

🍊字符串方法

str.trim()

  • 该方法会从一个字符串的两端删除空白字符
  • 中间的空格不会去除
  • trim() 方法不影响字符串本身,它返回的是一个新的字符串

🍊函数的进阶

🍊函数的定义和调用

🍊函数的定义

  1. // 自定义函数 (命名函数)
    function fn(){};
    
  2. // 函数表达式(匿名函数)
    var fun = function(){};
    
  3. // 利用 new Function('参数1','参数2','函数体')
    var f = new Function();
    

image-20220412101252922

🍊函数的调用

  1. // 普通函数
    function fn(){
        console.log('人生的巅峰')
    }
    
  2. // 对象的方法
    var o = {
        sayHi:function(){
           console.log('人生的额巅峰')
        }
    }
    0.sayHi();
    
  3. // 构造函数
    function Star();
    new Star();
    
  4. // 绑定事件函数
    btn.onclick = function(){};
    
  5. // 计时器函数
    setInterval(function(){},1000); // 这个函数时定时器自动1秒钟调用1次
    
  6. // 立即执行函数
    (function(){
        console.log('人生的巅峰')
    })();
    

🍊this

  1. // 普通函数 this指向 window
    function fn(){
        console.log('人生的巅峰')
    }
    
  2. // 对象的方法 this 指向该方法的所属对象
    var o = {
        sayHi:function(){
           console.log('人生的额巅峰')
        }
    }
    o.sayHi();
    
  3. // 构造函数 this 指向实例对象,原型对象里面的方法也指向实例对象
    function Star();
    new Star();
    
  4. // 绑定事件函数 this 指向 绑定事件对象
    btn.onclick = function(){};
    
  5. // 计时器函数 this 指向 window
    setInterval(function(){},1000); // 这个函数时定时器自动1秒钟调用1次
    
  6. // 立即执行函数 this指向 window
    (function(){
        console.log('人生的巅峰')
    })();
    

改变函数内部的this指向

  1. call 方法
  1. apply 方法
    • 调用函数
    • 可以改变函数内部的 this 指向
    • 参数必须是数组(伪数组)

image-20220412111427415

🍊严格模式

🍊什么是严格模式

image-20220418110101430

  1. 为脚本开启严格模式
    为整个脚本开启严格模式,需要在所有语句之间放一个特定语句“use strict”;(或 ‘use strict’;)。

    image-20220418113056835

  2. 为某个函数开启严格模式

    image-20220418113135451

🍊严格模式的变化

  1. 严格模式下必须先声明再使用

  2. 严禁删除已经声明过的变量

  3. 严格模式下的this指向

    ​ 严格模式下全局作用域中的函数的 thisundefined

  4. 严格模式下,如果构造函数不加 new调用,this 会报错

    image-20220418115624370

  5. new 实例化构造函数指向创建的对象实例

  6. 定时器this指向window

  7. 事件、对象还是指向调用者

🍊函数的变化
  1. 不能有重名的参数

🍊高阶函数

  • 高阶函数是对其他函数进行操作的函数,它接受函数作为参数或将函数作为返回值输出----- 函数可以作为参数传递
<script>
    // 高阶函数- 函数可以作为参数传递
	function fn(a,b,callback){
        console.log(a+b);
        callback && callback();
    }
    fn(1,2,function(){
        console.log('我是最后调用的')
    })
</script>

🍊闭包

什么是闭包

  • 闭包是指有权访问另一个函数作用域中变量的函数
  • 简单理解就是,一个作用域可以访问另外一个函数内部的局部变量
// 闭包:我们fun 这个函数作用域 访问了另一个函数 fn 里面的局部变量 num
function fn(){
    var num = 10;
    function fun(){
        console.log(num);
    }
    fun();
}
fn();  // 打印 10

闭包的作用

  • 延伸了变量的作用范围
// 作用: 我们 fn 外面的作用域可以访问 fn 内部的局部变量
// 延伸了变量的作用范围
function fn(){
    var num = 10;
    function fun(){
        console.log(num);
    }
    return fun;
}
var f = fn();
f(); // 打印 10

🍊浅拷贝和深拷贝

  1. 浅拷贝知识拷贝一层,更深层次对象级别的只拷贝引用
  2. 深拷贝拷贝多层,每一级别的数据都会拷贝

🍊浅拷贝

  • 方法:for in 循环
// 只拷贝一层
var obj = {
    id:1,
    name:"andy",
}
var o = {};
for(var k in obj){
    o[k] = obj[k];
}
console.log(o);
// 若有多层数据进行浅拷贝,修改拷贝后的数据  只是把obj的地址给了 o 如果修改了 o 里面的值, obj的值也会改变

// 例如:
var obj = {
    id:1,
    name:'andy',
    msg:{
        age:18
    }
}
var o = {};
for(var k in obj){
    o[k] = obj[k];
}
// 修改多层结构里面的数据
o.msg.age = 20;
console.log(o);
console.log(obj);
// 上面这两个对象相等


// ES6 中浅拷贝的方法 Object.assgin(o,obj)

🍊深拷贝

  • 方法 for in 循环 + 递归
// 拷贝多层
var obj = {
    id:1,
    name:"andy",
    msg:{
        age:18
    },
    color:['pink','red']
}
var o = {};
// 封装函数
function deepCopy(newobj,oldobj){
    for(var k in oldobj){
        // 判断属性值数据哪种数据类型
        // 1.获取属性值 
        var item = oldobj[k];
        // 2.判断这个值是否是数组
        if (item instanceof Array){
            newobj[k] = [];
            deepCopy(newobj,oldobj)
        }else if(item instanceof Object){
         	// 3.判断这个值是否是对象
            newobj[k] = {};
            deepCopy(newobj,oldobj)
        }else{
            // 4.属于简单数据类型
            newobj[k] = item;
        }
    }
}
deepCopy(o,obj)
console.log(o);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值