js进阶学习笔记

171 阅读6分钟

1.ES6新特性

1.1let & const

        //变量定义
        var num1=100
        console.log(num)
        let num2=200
        const num3=100  //常量
        let特点:
           //let声明的变量,不能变量提升,必须先声明再使用。
           //不允许重复声明变量
        //let声明的变量具有 块作用域 {}
        区别:
        //const声明是常量 ,声明的不会改变
        //let声明的时候可以不赋值,const声明的时候必须赋值
        let num
        num=100
        console.log(num)  //100
        const num //这里就会报错

let 与const都不会变量提升

1.2箭头函数

简化函数写法

function fun(){

let fun=function(){}

let fun1=()=>{}

} 1.当形参只有一个时,小括号可以不写 参1 =>{}

  1. 当函数体只有一条语句时,大括号可以不写 参1 => console.log(参1)
  2. 当函数体只有一条return语句, 大括号和return都可以不写

特点: 箭头函数中的this指向应用上下文本 箭头函数中如果出现this, 它指向的上一作用域this指向的对象

<div>
      <button>按钮</button>
 </div>
<script>
const divEle = document.querySelector('div')
  const btn = document.querySelector('button')
        // btn.onclick = function(){
        //     console.log(this);
  //这里的this指向btn 
        // }
    // console.log(this)
​
    divEle.onclick = function () {
​
        btn.onclick = () => {
            
            setTimeout(() => {
                console.log(this)
            }, 1000);
        }
    }
</script>

1.3函数传递参数的时候的默认值

我们在定义函数的时候,有的时候需要一个默认值出现,就是当我不传递参数的时候,使用默认值,传递参数了就使用传递的参数

 function fun(m = 100){
            console.log(m);
        }
        // function fun(m){
        //     m = m || 100 //函数参数默认值
        //     console.log(m);
        // }
        fun()

1.4解构赋值

简化访问简单对象和数组成员方式。

解构对象

var obj={
    name:'jack',
    age:20,
    gender:'男'
}
//解析obj对象,将obj对象名为name,age,gender属性的值赋给,大括号中的同名变量
let{name,age,gender}=obj
console.log('name',name,'age',age,'gender',gender)

解构数组

  //解构数组arr, 将数组中第一个开始的元素分别赋值给变量a,b,c
var arr=['jace','rose','tom']
let [a,b,c]=arr
console.log(a,b,c)

1.5展开运算符

...

用于展开数组元素或对象属性

let arr=[1,2,3]
console.log(...arr)   //1   2   3

应用:

//应用:
合并数组
[1,2,3]  [4,5,6]
[1,2,3,4,5,6]
例如: var arr1=[1,2,3] 
     var arr2=[4,5,6]
     var arr3=[...arr1,...arr2]  //[1,2,3,4,5,6]

1.6字面量简化

 <!-- 
​
        字面量简化
​
           当简单对象的属性名和属性值同名时,只写一个
     -->
<script>
        let name = 'jack'
        let age = 20
​
        // let person = {
        //     name: name,
        //     age: age
        // }
        let person = {
            name,
            age
        }
​
​
        console.log(person);
​
    </script>

2.面向对象编程

面向过程:分析除解决问题需要的步骤,然后按照步骤解决问题。

面向对象:把事务分解成一个个为对象,以对象功能划分问题。

面向对象特性:封装性、继承性、多态性

优缺点:

  1. 面向过程性能更高,和硬件联系更紧密。
  2. 面向对象性能虽然低,但易复用、易维护、易扩展,灵活性更高。

对象是什么?

  • 一组无序的相关属性和方法组成的集合。

类抽象了对象的公共部分。

面向对象的思维特点:

  • 抽取对象共用的属性和行为封装成一个类(模板)
  • 对类进行实例化,创建对象。 类里面有一个最重要的函数 constructor,可以接收传递过来 的参数,同时返回实例对象,只要用new生成实例,就会自动调用。就算不写这个函数,也会被自动生成。

constructor是构造函数。

2.1类的继承

super可以调用父类的构造函数。

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;
    }
}
var son = new Son(1,2);
var son1 = new Son(11,22);
son.sum();
son1.sum();

super关键字也能调用父类的普通函数。

class Father {
    say(){
    return '我是大大';
    }
}
class Son extends Father {
say(){
    console.log(super.say()+'的小小');
}
}
var son = new Son();
son.say();
//继承中,实例化子类对象输出一个方法,先看看子类有没有,若有,则执行子类;若无,则看父类有无,若有则继承执行(就近原则)

注意:

  1. 在es6中类没有变量提升,所以必须先定义类,才能通过类实例化对象。
  2. 类里面的共有属性和方法一定要加this使用。
  3. constructor里面的this指向实例化对象,方法里面的this指向这个方法的调用者(调用者有可能是实例化对象,也有可能是其他。) 注意
ES6class 与构造函数的关系
  class 为  构造函数的语法糖,即 class 的本质是 构造函数。class的继承 extends  本质 为构造函数的原型链的继承。
​
  例如:
​
  类的写法
​
  class Person{  //定义一个名字为Person的类
​
    constructor(name,age){ //constructor是一个构造方法,用来接收参数
​
      this.name = name;  //this代表实例对象
​
      this.age = age;
​
    } 
​
    say(){  //这是一个类的方法,注意千万不要加上function
​
      return   this.name + this.age
​
    }
​
  }
​
  var obj = new Person('老铁'18);
​
  console.log(obj.say());
​
  构造函数的写法
​
    function Person(name,age){   //构造函数和实例化构造名相同且大写(非强制,但这么写有助于区分构造函数和普通函数)
​
      if(!(this instanceof Person)){ //避免使用者不小心讲Person当作普通函数执行
​
         throw new Error(''请使用 new Person"); //仿ES6 class 中的写法
​
      }
​
      this.name = name;
​
      this.age = age;
​
    }
​
    Person.prototype.say = function(){
​
      return   this.name + this.age
​
    }
​
    
​
  var obj = new Person('老铁',18);   //通过构造函数创建对象,必须使用new运算符
​
  console.log(obj.say());
​
 
​
  // 总结:通过class定义的类 和通过构造函数定义的类 二者本质相同。并且在js执行时,会将第一种转会为第二种执行。所以 ES6 class的写法实质就是构造函数。

2.2 面向对象的tab栏切换

功能需求:

对应tab栏应该实现切换,添加,删除,修改功能。

抽象对象:Tab对象

该对象具有以上切换、添加、删除、修改 功能。

其中修改功能的核心思路: 双击文字时在里面生成一个文本框,当失去焦点或者按下回车然后把文本框输入的值给原本的元素即可

 var that; 
class Tab {
    constructor(id){
        //获取元素
        that = this;
        this.main = document.querySelector(id);
        this.add = this.main.querySelector('.tabadd');
        //li的父元素
        this.ul = this.main.querySelector('.fisrstnav ul:first-child');
   //section的父元素
        this.fsection = this.main.querySelector('.tabscon');
        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;
             this.lis[i].onclick = this.taggleTab;
                                            this.remove[i].onclick = this.removeTab;
                                          this.spans[i].ondblclick = this.editTab;
                                      this.sections[i].ondblclick = this.editTab;
         }
     }
     //由于动态添加元素引起的bug,需要重新获取对应的元素
     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('.fisrstnav li span:first-child');
        } 
    //1.切换
    taggleTab(){
        that.clearClass();
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
     //清除类
     clearClass(){
         for(var i = 0;i < this.lis.length;i++){
             this.lis[i].className = '';
             this.sections[i].className = '';
         }
     }
    //2.添加
    addTab(){
        that.clearClass();
        //创建
        var random = Math.random();
        var li = '<li class="liactive"><span>新的选项卡</span><span class="iconfont icon-guanbi"></span></li>'
            var section = '<section class="conactive">测试 ' + random + '</section>';
        //追加到父元素
        that.ul.insertAdjacentHTML('beforeend',li);
        that.fsection.insertAdjacentHTML('beforeend',section);
        that.init();
    }
    //3.删除
  removeTab(e) {
            e.stopPropagation(); // 阻止冒泡 防止触发li 的切换点击事件
            var index = this.parentNode.index;
            console.log(index);
            // 根据索引号删除对应的li 和section   remove()方法可以直接删除指定的元素
            that.lis[index].remove();
            that.sections[index].remove();
            that.init();
            // 当我们删除的不是选中状态的li 的时候,原来的选中状态li保持不变
            if (document.querySelector('.liactive')) return;
            // 当我们删除了选中状态的这个li 的时候, 让它的前一个li 处于选定状态
            index--;
            // 手动调用我们的点击事件  不需要鼠标触发
            that.lis[index] && that.lis[index].click();
        }
    //4.修改
      editTab() {
        var str = this.innerHTML;
        // 双击禁止选定文字
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        // alert(11);
        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');

注意:有些事件会点击子元素同时触发了父元素,产生事件冒泡,需要阻止冒泡。

\