Js进阶四天

成长必经之路

目录

  • 构造函数: ES5继承
  • ES6类的相关
  • call/apply/bind

构造函数

继承

目标: 掌握属性和方法继承

为什么要学习继承: 有的构造函数上原型对象上已经实现一部分方法; 我们需要这些方法, 就需要把这个部分功能继承过来( 内存地址上指向是同一个地址), 而不是重新再写一次;

实例属性的继承: 直接复制?

  1. //参数1:Other构造函数内部属性即将要去到这个对象上
  2. //参数,参数1后面的参数,就是我们自己传入的属性值!/
  3. // Other.call(obj);
  4. // 结论: other被某个对象打电话: 某个对象上就会有other内部的属性名和值;

实例属性的继承: call语法

  1. // 2---------------------新的语法:一次性把对方身上所有属性全部拿过!
  2. // call:打电话呼叫;基础语法
  3. //
  4. function other(housemoney,car){
  5. this.house = house;
  6. this.money = money;
  7. this.car = car;}
  8. var obj = {
  9. info:"我就是个单独对象"
  10. };
  11. other.call(obj102010);
  12. // call语法规则:【需要重点记忆】
  13. // 1.Other丞数肯定是要执行!
  14. // 2.参数:第一个参数other执行,other内部this上的所有的属性名即将要去到这个参数上;
  15. // 3.剩余参数,必须逗号分隔;就是oTher执行时,需要传入的实参;
  16. console.log(obj);

实例属性的继承: call方式实现

  1. function My(a, b, c) {
  2. // Other.call(this) 继承对方构造函数内部的压性名
  3. //( ,a,b,c); 自己规定内部压性值,设置为形参,没有固定!
  4. Object.call(this, a, b, c)
  5. //不能这样写,上面代码相当于结果下面这样结果:
  6. // this.money = a;
  7. // this.cars = b;
  8. // this.house = c;
  9. }
  10. let m1 = new My()
  11. console.log(m1); //My {}
  12. let m2 = My()
  13. console.log(m2); //undefined

继承

原型对象上的方法继承

  1. //别人写好杓造函数+原型对象
  2. function Other(money, cars, house) {
  3. // 初始化属性
  4. this.money = money;
  5. this.cars = cars;
  6. this.house = house;
  7. }
  8. Other.prototype.show = function () {
  9. console.log(`你看老子多有钱:有钱${this.money}、有车${this.cars}、有房${this.house}`);
  10. };
  11. };
  12. Other.prototype.sing - function() {
  13. console.log(“你看老子多有钱,我会唱歌“);
  14. };
  15. //自己:
  16. function My (house){
  17. other.call(thishouse);
  18. }

方式1: 把其他构造函数的原型对象直接使用( 不可取)

  1. function My(a, b, c) {
  2. Object.call(this, a, b, c)
  3. }
  4. // 方式1,不推荐!My原型对象不要了,被重新赋值了, 指向Other原型对象;
  5. // 原因:此时My原型对象和0ther原型对象其实公用一个原型对象:如果现在继续在
  6. //My . prototype添加方法,无形中就给other.prototype添加新了的方法:可能出现问题!
  7. // 不允许,你可配用你同事封装好原型对象方法,绝对不能修改同事的原型对象!
  8. My.prototype = Object.prototype
  9. My.prototype.abc = function () {
  10. console.log("my自己新增的方法");
  11. }
  12. let m = new My(44, 55, 66)
  13. console.log(m); //My {}
  14. let o = new Object(77, 88, 99)
  15. console.log(o); //Number {77}

方式2: 直接修改原型对象的proto属性值为 对方的原型对象

  1. // -----------------------自己---------------------------
  2. function My(a, b, c) {
  3. Other.call(this, a, b, c)
  4. }
  5. //方式2:My.prototype普通对象:__proto__--->默认Object.prototype
  6. //思路完全正确,__proto__是标准属性,不能出现在代码当中!
  7. My.prototype.__proto__ = Other.prototype;
  8. My.prototype.sing = function () {
  9. console.log("我会脱衣舞"); //我会脱衣舞
  10. }
  11. let m = new My(10, 55, 99)
  12. m.show()
  13. m.sing()
  14. let o = new other(1, 1, 1);
  15. o.sing()

方式3: 最终方案

  1. //方式3:
  2. My.prototype = new Other();
  3. My.prototype.abc = function () {
  4. console.log("abc");
  5. }
  6. //测试1:是否有show
  7. let m = new My(10, 20, 30)
  8. m.show()
  9. //测试2.如果我给MY.prototype新增一个方法,看Other是否 影响?
  10. m.abc();
  11. let o = new Other(44, 55, 66)
  12. o.abc()

继承-示意图

ES6类

基本语法

目标: 知道什么类

  • 概念: 将对象中公共的方法或者属性封装成一个模板 (es5中的构造函数)

  • 作用: 创建对象

  • 语法:

    1. //步骤1使用c1ass关键字name就是一大类的名称,可以理解为构造函数的名称class name {
    2. class name{}
    3. //步骤2使用定义的类创建实例注意new关键字
    4. var XX= new name();
  • 注意事项:

    • 通过类创建对象必须使用new关键字
    • 类的命名规范与构造函数的命名规范一样(帕斯卡命名法)
    • 创建对象后类名后面必须加()

constructor:构造函数

目标: 类里面添加属性和方法

  • 在constructor内部添加, 相当于构造函数内部;
    1. // 1.创建类c1ass创建一个明星类
    2. class star {
    3. //类的共有属性放到constructor里面
    4. constructor (nameage) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. }
    9. //2.利用类创建对象new
    10. var 1dh = new star ('刘德华'18);
    11. console. log(1dh);
  • 在constructor下面直接添加方法, 无符号分隔, 不需要写function关键字
  1. //1.创建类class创建一个类
  2. //ES6:类 Person:后面没有()
  3. class Person {
  4. //构造函数:前面没有function关键词,结尾没有【,】分隔符!
  5. constructor(name, age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. sing() {
  10. //方法,直接放下面写,要求和constructor一样
  11. console.log(this.name + "会唱歌");
  12. }
  13. eat() {
  14. console.log(this.name + "会干饭");
  15. }
  16. }
  17. //使用:
  18. let p = new Person("zs", 19)
  19. console.log(p); //Person: age: 19 name: "zs"

继承

  1. //我的:继承 extends 延伸扩展
  2. class My extends Other {
  3. abc() {
  4. console.log("握手ABC的方法");
  5. }
  6. }
  7. let m = new My("zs", 19)
  8. console.log(m); //My {house: "zs", car: 19}

super的使用

  • 使用场景1: 如果在子类中, 想调用父类中的方法;
  1. // super关键字调用父类普通函数
  2. class My extends Other {
  3. test() {
  4. super.show()
  5. }
  6. show() {
  7. console.log("我是 类的方法啊");
  8. }
  9. }
  10. let m = new My("zs,19")
  11. console.log(m); //My {house: "zs,19", car: undefined}
  12. //需求:继承别人方法和属性,现在想在test内部,调用下other原型链上 show方法;
  13. //细节:super关键词,帮助我们直接调用 被继承原型对象上的同名方法!
  • 使用场景2: 在子类的构造函数内部定义自己的属性时, 需要用super调用, 把父类的构造函数内参数传入, 且必须写在子类this的前面; 不然会报错
  1. // 2.设置自己构造函数;设置自己属性
  2. class My extends Other {
  3. //规定:extends帮助内部 设置形参 失效;
  4. //1.需要我们单独设置设置形参 2.super方法最终调用 必须在当前结构函数内部this之前;
  5. //extends继承了属性,没有属性值;
  6. constructor(a, b, c, name, age) {
  7. super(a, b, c);
  8. this.name = name;
  9. this.age = age; //不可避免要写自己的属性,下面自己原型上方法肯定需要自己的属性
  10. }
  11. }
  12. let m = new My(10, 20, 99, "zs", 29);
  13. console.log(m); //My {house: 10, car: 20, name: "zs", age: 29}

补充知识

  1. // function关键字声明函数: this可以用!看清楚是怎样调用的方式! 谁调用就是谁!
  2. function fn() {
  3. this.a = 10;
  4. this.b = 20;
  5. }
  6. // 1.常规 ===> window.fn(); this--->widnow;
  7. fn();
  8. console.log(window);
  9. // 2.内部this--->本次实例化对象
  10. let res = new fn();
  11. console.log(res); //fn { a: 10, b: 20 }
  12. // 3.被call
  13. let obj = {
  14. info: "我就是个普通对象"
  15. };
  16. fn.call(obj); // this----->obj
  17. console.log(obj); //{info: "我就是个普通对象", a: 10, b: 20}
  18. console.log(obj.a); //10
  19. // --------箭头函数:没有this!
  20. // 没有this:内部没有内置变量this,this用的外面的this;
  21. // 规则:箭头函数不看调用,看在出生哪个作用域创建,

改变this指向

call方法的使用

  • 语法:函数.call();

  • 作用: 函数在该次的调用的时候, 其函数内部this 指向 我们指定参数的那个对象; 这个函数要执行的 !

  • 参数: 参数1, 函数fn内属性名即将要去到这个参数上;

    1. //call改变 function形式 内部this指向:
    2. //语法:fn.call(参数1);
    3. // fn肯定会执行
    4. // 函数内部this在本次调用中,this===>参数1
    5. function fn() {
    6. this.a = 10;
    7. this.b = 20
    8. } //function My() {Other.My(this)}
    9. let arr = []
    10. fn.call(arr)
    11. //场景:用于ES5 构造函数内部属性继承!

apply方法

  • 作用: 1. 函数在该次的调用的时候, 其函数内部this 指向 我们指定参数的那个对象;

      1. 这个函数要执行的!
  • 参数: 1. this 指向 我们指定参数的那个对象

      1. fn要执行的时候, 把 参数 作为一个数组传入
  1. // apply: 作用和call一样!
  2. // 语法:函数.apply(参数1)
  3. // 在本地调用中,把函数内部this上属性,给了参数1;
  4. // 相同:call 与 apply 参数1:内部属性即将要去到新对象!前面函数肯定要执行!
  5. // 不同点:call 后面参数 【,】 隔开!
  6. // apply 后面只有一个参数,把即将要传入实参,形成为数组!
  7. // call演示:
  8. function fn(a, b) {
  9. this.a = a;
  10. this.b = b;
  11. }
  12. let obj1 = {
  13. info: "我是普通对象obj1"
  14. }
  15. fn.call(obj1, 99, 88);
  16. console.log(obj1);
  17. // apply演示:
  18. let obj2 = {
  19. info: "我是普通对象obj2"
  20. }
  21. fn.apply(obj2, [77, 66]);
  22. console.log(obj2);

bind方法

  • bind() 方法不会调用函数,但是能改变函数内部this 指向,返回的是原函数改变this之后产生的新函数

  • 如果只是想改变 this 指向, 并且不想调用这个函数的时候, 可以使用bind ```javascript //bind; //知识改变函数内部this指向,不会让函数执行! //内部已经在强制性滚顶了,不管接下来该函数如何被调用!

//语法:函数.bind(参数) //返回:返回新的函数(和旧的函数长一样),内部this已经被我们固定了!

  1. -
  2. Swiper插件的优化: 右侧点击功能, 下面这样写会构成`闭包! 一个功能就是一个闭包` 多个功能就是多个闭包!
  3. ```javascript
  4. //bind;
  5. //知识改变函数内部this指向,不会让函数执行!
  6. //内部已经在强制性滚顶了,不管接下来该函数如何被调用!
  7. //语法:函数.bind(参数)
  8. //返回:返回新的函数(和旧的函数长一样),内部this已经被我们固定了!

call / apply/ bind 方法异同点

  • this: 大白话

    • 一般情况: 谁调用就是谁 !
    • 函数遇见call、 apply、 bind: 遇见第一参数是谁就是谁!
  • 相同点: 这样的调用方式, 都可以把本次调用的内的this 改变函数内部this指向!
  • 不同点

    • call 和 apply 会调用执行函数! bind 不会执行函数!
    • call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递 ;