js高级

js高级

箭头函数

正常函数

function get() {
 console.log("10");
}
get(); //10

将函数赋值给变量

const get2 = function () {
  console.log("20");
};
get2(); //20

箭头函数传参

只传递一个参数时,小括号可以省略

const get = a => {
 console.log(a);
};
get("40"); //40

不传参或传一个以上时不能省略小括号

 const get = (a, b) => {
  console.log(a, b);
};
get(1, 2); //1  2

返回值简写

当返回值只有一行时,大括号可以省略,不能写return,计算结果直接返回

const arr = () => 123 + 1; //代码不能换行
console.log(arr());  //124

当返回值为对象时,应该给大括号外面加一个小括号,否则大括号会被读取为函数结构

 const arr2 = () => ({ name: "张三" });
 console.log(arr2()); // { name: "张三" }

错误示范

错误原因:不传参或传参一个以上时,小括号不能省略

const func = => console.log(123)  
console.log(func()); //报错

默认值

传不传参数会出现不同的值,常规写法

 function get(str) {
        if (str === undefined) {
          console.log("你好");
        } else {
          console.log(str);
        }
   }
get();
get("你不好");

定义函数的时候,可以给形参设置默认值

const get1 = (box = "默认值") => box;

传参如果没有实参,就使用默认值

const get1 = (box = "你好") => box;
console.log(get1());// 输出 你好

如果有对应的实参,就使用参数

const get1 = (box = "你好") => box;
 console.log(get1(123)); //输出  123

默认值为数组时

当没有实参时,输出默认值

const getLength = (arr = []) => console.log(arr.length);
getLength(); // 0

当有传参时,输出对应的值

const getLength = (arr = []) => console.log(arr.length);
let list = ['a','b'];
getLength(list); //2

函数的传参

当未传参时,返回值为NaN

 const num = (a, b) => a + b;
 console.log(num()); // NaN

当实参等于形参时,值正常返回

 const num = (a, b) => a + b;
 console.log(num(3, 4)); // 7

当实参少于形参时,返回NaN,没有实参传入的形参为undefined

 const num = (a, b) => a + b;
 console.log(num(3)); //NaN

当实参多于形参时,正常返回,多余的实参没有形参接收,不参与计算

 const num = (a, b) => a + b;
 console.log(num(3, 4, 5));// 7

结论:函数中的形参可以少于实参的数量,但不能多于

解构

数组解构

常规获取数组中数据的方法

const arr = ["a", "b", "c"];
      // 常规获取数组数据方法
      // const str1 = arr[0]
      // const str2 = arr[1]
      // console.log(str1,str2) //a b

数组解构

const arr = ["a", "b", "c"];
const [str1, str2] = arr;//['a','b','c']
console.log(str1, str2); // a  b

交换变量

常规交换变量

let num1 = 100;
let num2 = 200;
let temp = num1; // 先把num1的值100赋值给临时变量
num1 = num2; //再将num2的值赋值给num1
num2 = temp; //最后将临时变量的值赋值给num2 完成交换
console.log(num1, num2); // 200 100

解构交换变量

//  声明数组,然后使用解构
let a = 100;
let b = 200;
 //   let arr2 = [100,200]
[b, a] = [a, b];   //   [b,a] = arr2
console.log(a, b); // 200 100   

对象解构

常规方法

const obj = { uname: "张三", age: "18" };
const uname = obj.uname;
const age = obj.age;
console.log(uname,age); // 张三  18

使用解构

const obj = { uname: "张三", age: "18" };
const { uname, age } = obj;// { uname: "张三", age: "18" };
console.log(uname, age); // 张三  18

函数参数解构

常规方法

function fn(option) {
// 传入对象
   console.log(option.username);
  }
fn({ username: "八戒" });

使用解构

function fn({ username }) {  //解构要加大括号
 // 传入对象
 console.log(username);
}
fn({ username: "八戒" });

对象简写

对象简写---如果对象名和变量名一致的写法

 const username = '悟空';
 const skill = '72';
 const obj = {
 username,
 skill,
 };

函数简写

const uname = "悟空";
      //   函数简写
 const obj2 = {
 uname,
 say() {
   console.log("函数简写");
 },
 };
 console.log(obj2.say); //函数简写

拓展运算符||剩余运算符

剩余运算符可以获取剩余所有数据

获取数组剩余数据

let arr = ["a", "b", "c", "d"];
const [array1, array2, ...list] = arr;
console.log(list); // ['c','d']

数组合并

const list1 = [1, 2, 3];
      const list2 = [1, 2, 3];
      const list3 = [...list1, ...list2];
      console.log(list3);

获取对象剩余数据**

 let obj = {
        a: 1,
        b: 2,
        c: 3,
        d: 4,
      };
      const { a, b, ...obj2 } = obj;
      console.log(obj2); //  {c:3,d:4}

对象合并

对象合并,同名的属性名后面的会覆盖前面的

const object1 = { username: "悟空" };
      const object2 = { username: "八戒", height: 150 };
      const object3 = { ...object1, ...object2 };
      console.log(object3); // {username: '八戒', height: 150}
      //   下面的八戒和上面的悟空同名,在后面的同名覆盖前面的属性值

当函数中的值不确定时,可以使用剩余运算符

function cala(...params) {
        //   params 会获取到所有的传参,将这些参数存到一个数组中
        console.log(params);
      }
      cala(); // []
      cala(1); //[1]
      cala(1, 2); //[1,2]
      cala(1, 2, 3); // [1,2,3]

js数据类型

值类型 / 简单数据类型

数字 , 字符串 , 布尔值 , undefined , null

简单数据类型变量值改变,其他值不变

let a =1 ;
      let b = a;
      // b a 的一份复制 两个值 一样 但是两个数据是完全独立!
      b=10;
      // a 不会发生变化
      console.log(a);

引用类型 / 复杂数据类型

数组 , 对象 , 函数

const obj = { username: '悟空', height: 100 };
      const newObj=obj;
      newObj.username = '八戒';
//当修改新对象时,其他对象也会发生改变
      console.log(obj); // { username: '八戒', height: 100 }

复制引用类型

 const list = ['a', 'b'];
      // const newList = list; //
      const newList = [...list];
      newList.push('c');
//当改变新数组时,其他数组不会发生改变
      console.log(list); // ['a','b']

数组方法

for 和 foreach有什么区别 1 都是循环 2 for循环可以被中断 但是 foreach不可以!!

**数组方法map() **

遍历旧数组然后符合条件的元素返回一个新数组

map中回调函数可以有两个参数

1.元素本身

2.元素下标

数组的一个方法 也会遍历 数组 接收一个函数

const arr = ['a', 'b', 'c'];
const newArr = arr.map(function (value) {
        return `<li>${value}</li>`;
      });
      console.log(newArr);

结合箭头函数

const arr = ['a', 'b', 'c'];
const newArr = arr.map(value => `<li>${value}</li>`);

数组方法filter() 过滤

filter 检测数组元素,并返回符合条件所有元素的数组

filter会遍历每个元素,回调函数有两个参数,元素和下标

必须要满足return true或false 表示当前元素是否满足条件

const arr = [1,3,5,7,9];
const newArr = arr.filter(function(value){
if(value > 3){
return true;
} else {
return false;
}
})
console.log(newArr)  // [5,7,9]

简写

const arr = [1,3,5,7,9];
//const newArr = arr.filter(value => value > 3 ? true : false)
const newArr = arr.filter(value => value > 3) //当value大于3时直接返回true,否则返回false

数组方法every()

检测数组中每个元素是否都符合条件

全部都符合,返回 true 否则 返回 false

every 检测数组中的每一个元素是否都符合条件

every会接收一个回调函数

回调函数,接收两个参数

1.元素本身 item

2.元素下标 index

some是找到一个符合条件就返回,every是检测全部是否符合条件

 const names = ['黄圣飞', '梁聪', '王锦双', '韦嘉敏', '刘雅琴'];
      // 判断一下 上面所有同学的名称 是不是 长度 都是大于2   (每一个)

      const result = names.every(function (value) {
        console.log(value);
        if (value.length > 2) {
          return true;
        } else {
          return false;
        }
      });
//箭头函数简写
    const result = names.every(value => value.length > 2) // 所有人的名字长度大于2就返回true
    if(result){
        console.log('名字长度全部大于2')
     }else {
        console.log('有名字长度不大于2的')
     }    

every 对空数组也会直接返回true

数组方法some()

数组中只要有一个符合要求就返回true

数组方法some会遍历数组,检测数组中是否有符合条件的元素,找到一个满足条件的就不再遍历

some会接收一个回调函数

回调函数,接收两个参数

1.元素本身

2.元素下标

some就会返回寻找的结果

const arr = [
        '健康',
        '健康',
        '健康',
        '健康',
        '健康',
        '健康',
        '健康',
        '健康',
        '健康',
        '健康',
      ];

      // some方法来判断 队列 是不是有危险
      const result = arr.some((value) => value === '中招');

      if (result) {
        console.log('有危险');
      } else {
        console.log('健康');
      }

数组方法find

find 寻找符合要求的一个数组元素,返回元素本身

回调函数有两个参数,元素本身和元素下标

返回了true表示找到了,就不会往下遍历 找不到返回undefined

 const arr = [
        { username: '悟空', height: 70 },
        { username: '八戒', height: 60 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
      ];
      const obj = arr.find((value) => {
        console.log(value);
        if (value.height === 60) {
          return true;
        } else {
          return false;
        }

      });
console.log(obj);  // {username: '八戒', height: 60}

简写

const obj = arr.find((value) => value.height === 60);
console.log(obj);

数组方法findIIndex

找到数组中符合条件的元素的下标,

找到了就返回true,如果没找到返回-1

功能相对indexof来说强大一些,可用于数组中复杂数据类型的查找

   const arr = [
        { username: '悟空', height: 70 },
        { username: '八戒', height: 60 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
        { username: '龙马', height: 30 },
      ];
      const index = arr.findIndex((value) => value.height === 660);// 找不到就返回 -1 
      console.log(index); // -1
arrr.splice(index,1)
console.log(arr)

数组方法includes()

判断一个数组是否包含一个指定的值

或者判断一个字符串里是否包含某个字符

包含就返回true,不包含就返回false

const arr = ['a', 'b', 'c', 'd'];
 const result = arr.includes('e');
console.log(result); //false

数组方法indexof

类似 findIndex indexOf 搜索数组中的元素,并返回它所在的位置(元素的下标) 一般是简单数据使用

找到了 就返回元素的下标,没有找到了 返回 -1

const arr = ['a', 'b', 'c', 'd'];
const index = arr.indexOf('h');
console.log(index);  //-1

数组方法join 转字符串

join 方法是将数组元素转字符串,常和map连用

const arr = ['a', 'b', 'c'].map((value) => `<li>${value}</li>`);
      // const arr = ['<li>a</li>', '<li>b</li>', '<li>c</li>'];
      const result = arr.join('');
      console.log(result); //  <li>a</li><li>b</li><li>c</li>  转成字符串了

数组方法for of

遍历输出每一个元素的值

let arr = [1,2,3,4]
for(let val of arr){
console.log(val) // 1  2  3  4  //输出每一个值
}

数组方法forEach

数组自带的一个遍历方法

forEach 数组方法,可以对数组做遍历,可以接收一个回调函数,每一次遍历自动执行回调函数

forEach可以接收两个参数,第一个是遍历的元素item,第二个是遍历元素的下标index

for可以被break打断,forEach不能被break打断,会报错

let arr = [1,2,3,]
arr.forEach(function(item,index){
   console.log(item)  // item 是数组的值
   console.log(index)  // index 是数组值所对应的下标
})
const arr = [1, 2, 3, 4];
      arr.forEach(function (item, index) {
        console.log(item, index);
      });
      console.log("-----------------------------------------");
      //   箭头函数简写
 arr.forEach((item, index) => console.log(item, index));

set对象

1 Set 是一个对象 不会存放重复数据

2 数组转成 set对象 const set = new Set([])

3 set对象 转成 数组 const arr=[...set]

4 set对象 添加数据 使用add方法

const list = [1, 4, 5, 6, 7];
const set = new Set(list);  // 将数组转成对象
      set.add(1);
      set.add(2);
      set.add(2);
      set.add(2);
      set.add(2);
      set.add(2);
      set.add(2);
      set.add(3);// 给对象添加元素 , set不会存放重复数据
const arr = [...set]; // 用剩余运算符将对象转换为数组
console.log(arr); // [1, 4, 5, 6, 7, 2, 3]

面向对象

一种编程行业通用的写项目级的代码的思维,引导我们如何编写高质量的代码,万物皆对象 - 看待事物的角度,(属性:数据,行为:动作(方法))。代码特点是封装和继承

创建对象

字面量

不适合创建多个同样类型的对象的场景

const obj ={ name:"悟空",height:100,age:5000};

工厂函数

可以批量创建对象

function fn(name, age) {
        return { // 不return会返回undefined
          name,
          age,
        };
      }
      const obj1 = fn("悟空", 600);
      const obj2 = fn("八戒", 1800);
      console.log(obj1);
      console.log(obj2);

构造函数es5

1.本质就是一个函数

2.命名,首字母建议大写

3.作用,必须用来new 创建对象 否则 没有意义 undefined

4.实例 p变量就是Person的实例

//  构造函数其实就是创建了一种创建对象的模板
      // 通过一个构造函数创建出来的实例的属性一模一样
      function Person() {
        //   this指的就是后面创建出来的实例
        this.username = "八戒";
      }
      Person(); // 普通函数
      const p1 = new Person(); // new了的就是构造函数     p就是Person的实例
      const p2 = new Person(); // new了的就是构造函数     p就是Person的实例
      const p3 = Person(); //  没有使用new来创建对象,返回undefined
      console.log(p1);
      console.log(p2);
      console.log(p3);
function Person(name, height) {
        //   每个实例属性名都一样,值为实例的传参
        this.username = name;
        this.height = height;
      }
      const p1 = new Person("八戒", 150);
      const p2 = new Person("悟空", 180);
      console.log(p1);
      console.log(p2);
构造函数的弊端
  1. 调用方法时,没一个方法都会占据一份内存

    方法和函数写在构造函数中都要在见面加this,否则实例找不到对应的属性和方法

    function Person(){
      this.say: function(){
       console.log('这个是say方法')
    }
    }
    const p1 = new Person()
    const p2 = new Person()
    p1.say()
    p2.say() 
    console.log(p1.say === p2.say) // false
    // 两个say方法不是同一个地址 
    

2.将say方法在构造函数外面设置一个函数,然后在构造函数里赋值

这种可以解决浪费内存的问题,但是会造成污染全局变量的问题

    // 提前将say 声明好
    function say() {  // 污染全局变量
      console.log(this.name);
    }
    function createStudent(name, age) {
      this.name = name;
      this.age = age;
      this.say = say
    }

    const obj = new createStudent("悟能", 83);
    const obj1 = new createStudent("悟能1", 84);

    console.log(obj.say === obj1.say); // true
构造函数,原型,实例

1.构造函数 父亲 只能有一个

2.实例 儿子 可以有多个

3.原型 DNA 父亲原型上面有的儿子原型可以继承

将方法直接挂载到构造函数的原型上,既没有浪费内存,也没有造成全局变量污染

// 在构造函数内部只会定义一些非函数类型的属性
      function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      //   只要是 方法和函数都定义在原型上
      Person.prototype.say = function () {
        console.log("这个是say方法");
      };
      Person.prototype.show = function () {
        console.log("这个是show方法");
      };
      //   原型上的方法可以使用this来调用构造函数中的属性
      Person.prototype.toggle = function () {
        console.log(this.age);
      };
      const p1 = new Person("八戒", 800);
      const p2 = new Person("悟净", 1800);
      const p3 = new Person("净坛使者", 1800);
      console.log(p1);
      console.log(p2);
      console.log(p3);
      console.log(p1.say === p2.say);
      p1.say();
      p1.show();
      p1.toggle();

在构造函数内部只会定义一些非函数类型的属性

只要是 方法和函数都定义在原型上

原型上的方法可以使用this来调用构造函数中的属性

    function createStudent(name, age) {
      this.name = name;
      this.age = age;
    }
    // 将刚才的全局函数say 直接挂载到 构造函数的原型上 即可
    // prototype 是个对象 每一个构造函数都会内置有的. 我们称之为原型
    createStudent.prototype.say = function () {
      console.log(this.name);
    }

    const obj = new createStudent("悟能", 83);
    const obj1 = new createStudent("悟能1", 84);

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

原型

  • 原型的单词是 prototype, 原型的这个名字是行业内共同认可的名字。
  • 原型本质是一个对象,理解为 JavaScript 自动帮我们添加的
  • 原型是 JavaScript 自动帮我们在定义构造函数的时候添加的
  • 所有构造函数的实例,共享一个原型
  • 原型上一般是挂载函数
原型链继承

利用代码的能力实现 面向对象的特性 封装继承

继承

1 父亲有的 儿子什么都不用做 直接就拥有

父亲 构造函数 儿子 构造函数

2 儿子要继承父亲

 属性(this里面一坨)

 方法 原型上定义的方法
// 属性写在构造函数内
function Parent(name, age) {
        this.name = name;   // this指向obj   // 规则,谁调用了方法,this就指向谁
        this.age = age;
      }
// 方法定义在原型上
      Parent.prototype.say = function(){
        console.log("这是父亲的方法");
      };

      function Son(name, age, height) {
          //call将指向父构造函数里的借调给子构造函数 继承父亲的属性
        Parent.call(this, name, age);
        this.height = height;
      }
//单个赋值
      Son.prototype.say = Parent.prototype.say;
      const son = new Son("八戒", 1800, 150);  //实例
      console.log(son);

call可以借调或者说是修改this的指向

 const obj = {
        say(a, b, c) {
          this.a = a;
          this.b = b;
          this.c = c;
        },
      };
      const newObj = {};
      obj.say.call(newObj, 10, 20, 30);
      console.log(newObj); // {a: 10, b: 20, c: 30}

对象新增属性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>06-对象新增属性.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <script>
      const obj = {
        say() {
          // this 指向谁  obj
          // obj.username="八戒";
          // this.username="八戒";
          this.a = 1;
          this.b = 2;
          this.c = 3;
        },
      };
      // 给对象添加属性
      // obj.username = '八戒';
      // 调用say方法
      obj.say();
   // 借用this的指向调用对象中的方法给对象增加属性
      console.log(obj);  // {a: 1, b: 2, c: 3, say: ƒ}
    </script>
  </body>
</html>

构造函数原型标准继承

      <script>
      //父构造函数属性
      function Parent(name, color, height, weight) {
        this.name = name;
        this.color = color;
        this.height = height;
        this.weight = weight;
      }
     //子构造函数 
      function Son(name, color, height, weight, money) {
        Parent.call(this, name, color, height, weight);
        this.money = money;
      }

      Parent.prototype.say = function () {
        console.log('这个是父亲的行为');
      };
      Parent.prototype.say1 = function () {
        console.log('这个是父亲的行为');
      };
      Parent.prototype.say2 = function () {
        console.log('这个是父亲的行为');
      };
      Parent.prototype.say4 = function () {
        console.log('这个是父亲的行为');
      };

      // 累,每一个都要赋值
      // Son.prototype.say = Parent.prototype.say;

      // 引用类型,赋值的是同一个地址,一变都变
      // Son.prototype = Parent.prototype;
      // 用拓展运算符
      Son.prototype = { ...Parent.prototype };
      // 我只想给儿子新增一个方法 不希望父亲有!!!
      Son.prototype.a = function () {
         console.log('这是儿子的新增方法')
      };      
      // const s = new Son(1, 2, 3, 4, 5);
      // console.log(s);
      console.log(Parent.prototype);
      console.log(Son.prototype);  // 父亲的方法和儿子的方法指向的不是一个地址
    </script>

案例-- 封装

<script>
      function Div(d) {
        this.div = document.createElement("div");
        this.div.innerText = d;
      }
      function Img(src) {
        this.img = document.createElement("img");
        this.img.src = src;
      }
      Div.prototype.appendBody = function () {
        document.body.appendChild(this.div);
      };
      Img.prototype.appendBody = function () {
        document.body.appendChild(this.img);
      };
      const divElement = new Div("这个是div的内容");
      const imgElement = new Img("./1629b0bdb08b467c6de909aee6fe9d11.png");

      setTimeout(() => {
        divElement.appendBody();
      }, 1000);

      setTimeout(() => {
        imgElement.appendBody();
      }, 3000);
    </script>

案例-- 以继承的思想来写

 <script>
      // 先创建一个父构造函数封装
      function Element(a) {
        //将需要创建的标签传参,根据不同的传参创建不同的标签
        //  创建标签
        this.dom = document.createElement(a);
      }
      // 父构造函数原型
      Element.prototype.appendBody = function () {
        //  将创建好的标签插入到body中
        document.body.appendChild(this.dom);
      };     
      // -------------------------------------------------------------------
      // 儿子1
      function DivElement(d) {
        // 将实例内容传参
        // 继承父构造函数属性
        Element.call(this, "div"); //将div作为参数传给父构造函数
        this.dom.innerText = d;
      }
      // 儿子1继承父构造函数原型上的方法
      DivElement.prototype = { ...Element.prototype };
      // -------------------------------------------------------------------

      // 儿子2
      function ImgElement(src) {
        // 将实例内容传参
        // 继承父构造函数属性
        Element.call(this, "img"); //将img作为参数传给父构造函数
        this.dom.src = src;
      }
      // 儿子2继承父构造函数原型上的方法
      ImgElement.prototype = { ...Element.prototype };
      // ------------------------------------------------------
      // 儿子1实例
      const div = new DivElement("这是一个div");
      // 儿子2实例
      const img = new ImgElement("./1629b0bdb08b467c6de909aee6fe9d11.png");
      setTimeout(() => {
        div.appendBody();
      }, 1000);
      // -------------------------------------------------------
      setTimeout(() => {
        img.appendBody();       
      }, 3000);
    </script>

es6

es6的class语法

es5 普通的属性 写在this上 函数写在 原型上

es6 第一种写法,不接收参数

// class 类  es6写法
      //   属性和方法直接写在class类中,方法可以在原型中直接被继承
      class Person {
        username = "悟空";
        say() {
          console.log("这是class类方法");
        }
      }
      // 实例
      const p1 = new Person();
      console.log(p1);

es6 第二种写法,接收参数

<script>
      class Person {
        constructor(username, height) {
          // 构造器,可以接收参数
          this.username = username;
          this.height = height;
        }
      }
      const p1 = new Person("悟空", 180);
      console.log(p1);
    </script>

es6 的继承

extends 可以直接继承父类的属性和方法

如果子类继承了父类,还有自己的属性和方法,在子类中方法可以直接写,属性有两种写法

1.要不就不要写构造器,代码默认给子类加一个super方法,调来父类的构造器 属性写死,不能传参

2.如果要写构造器,要在构造器里调用一个方法super,super === 父类.call(this) 指的是父类的构造器

class Person {
        constructor(username) {   // 构造器
          this.username = username;
        }
        say() {
          console.log("这是父类的say方法");
        }
      }
      class Son extends Person {
        constructor(username, age) {
          super(username);  //指向父类构造器
          this.age = age;
        }
        get() {
          console.log("这是子类的get方法");
        }
      }

      // 子类实例
      const s = new Son("悟空", 500);
      console.log(s);

案例

<script>
      // 父类
      class Element {
        // 创建元素
        constructor(e) {
          this.dom = document.createElement(e);
        }
        // 方法
        appendBody() {
          document.body.appendChild(this.dom);
        }
      }

      // 子类1
      class DivElement extends Element {
        constructor(content) {
          super("div"); // 传参给父类构造器
          this.dom.innerText = content;
        }
      }

      //   子类2
      class ImgElement extends Element {
        constructor(src) {
          super("img"); // 传参给父类构造器
          this.dom.src = src;
        }
      }
      // 子类1实例
      const divElement = new DivElement("这个是div的内容"); //传参给子类构造器
      //   子类2 实例
      const imgElement = new ImgElement(
        "./1629b0bdb08b467c6de909aee6fe9d11.png" // 传参给子类构造器
      );
      setTimeout(() => {
        divElement.appendBody();
      }, 1000);

      setTimeout(() => {
        imgElement.appendBody();
      }, 3000);
    </script>

检测数据类型

简单数据类型检测 typeof 不适合检测复杂数据类型

复杂数据类型检测 instanceof 检测实例是不是构造函数 的实例

// 简单数据类型检测   typeof   不适合检测复杂数据类型
      console.log(typeof 1213); //number
      console.log(typeof "abc"); //string
      console.log(typeof true); //boolean
      console.log(typeof []); //object
      console.log(typeof {}); //object
      console.log(typeof function () {}); // function

      // 复杂数据类型检测  instanceof  检测实例是不是构造函数 的实例
      function Person() {}
      function Boll() {}
      const p1 = new Person();
      const b1 = new Boll();
      console.log(p1 instanceof Person); // true
      console.log(p1 instanceof Boll); // false

this指向

<script>
      // 一般情况下  this指向  调用者 (谁调用代码 this 指向谁)
      // const obj={
      //   username:"八戒",
      //   say(){
      //     console.log(this);
      //   }
      // }
      // obj.say();

      // function say() {
      //   console.log(this);
      // }
      // say();// 指向谁 ????  window
      // window.say();

      // 我们在 全局中 通过function 来定义 函数 这个函数理解默认就添加到 window属性上!!
      window.say = function () {
        console.log(this);
        console.log('say方法被调用');
      };
      say();
    </script>

call apply bind之间的区别

call apply bind 三个都可以改变this的指向

call和apply可以之间调用

bind被调用时,不会触发原来的函数,而是会返回一个新的函数,需要用新函数去自己调用

call apply bind 的区别,传递参数的写法不同

 <script>
      /* 
      call-bind-apply 
      1 这三个 技术 都可以实现   修改this的指向 
        1 call 和 apply 直接调用 
          obj.say.call(newObj)
          obj.say.apply(newObj)
        2 bind被调用的时候  不会直接触发原来的函数 say 而是会返回一个新的函数 我们自己去调用新函数
      2 call 和 apply 区别   传递参数的写法 不同!! 
        1 obj.say.call(newObj,1,2);
        2 obj.say.apply(newObj,[1,2]);
        3 (obj.say.bind(newObj))(1,2);
       */
      const obj = {
        username: '八戒',
        say(a,b) {
          console.log(this);
          console.log(a,b);
        },
      };

      const newObj = {
        username: '悟空',
      };

      // obj.say();// obj

      // obj.say.call(newObj);// newObj
      // obj.say.apply(newObj); // newObj
      // const newSay = obj.say.bind(newObj); // newObj
      // newSay();
        // (obj.say.bind(newObj))(); // newObj

        // obj.say.call(newObj,1,2);// 传参
        // obj.say.apply(newObj,[1,2]);// 传参 数组
        (obj.say.bind(newObj))(1,2); // 之间调用时加括号可以传参 

    </script>

箭头函数 没有this指向 ,如果你的函数中 出现了this 慎用 箭头函数!!
很多的情况下 指向了window

// function say() {
      //   console.log(this);
      // }
      // const say=()=> console.log(this);

      // const obj = {
      //   username: '八戒',
      //   say: () => {
      //     console.log(this);
      //   },
      // };

      // obj.say();
      const button = document.querySelector('button');
      button.addEventListener('click', () => {
        console.log(this); // dom
      });

原型链

<script>
      /* 
      原型链   一层关系  多个对象 可以通过 原型 技术 层层的关联 
      prototype  构造函数点出来
      __proto__  实例点
       */
      // const div=document.querySelector("div")
      // console.dir(div)

      function Person() {}

      const p1 = new Person();
      // console.log(Person.prototype === p1.__proto__);
      p1._
    </script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容