JS高阶-函数构造:ES5继承,ES6类相关语法,this指向call/apply/bind,构造函数

JS高阶-函数构造:ES5继承,ES6类相关语法,this指向call/apply/bind,构造函数

成长必经之路

目录

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

构造函数

继承

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

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

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

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

实例属性的继承: call语法

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

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

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

继承

原型对象上的方法继承

//别人写好杓造函数+原型对象
function Other(money, cars, house) {
            // 初始化属性
            this.money = money;
            this.cars = cars;
            this.house = house;
        }
 Other.prototype.show = function () {
 console.log(`你看老子多有钱:有钱${this.money}、有车${this.cars}、有房${this.house}`);
    };
};
Other.prototype.sing - function() {
	console.log(“你看老子多有钱,我会唱歌“);
};
//自己:
function My (house){
other.call(this,house);
}

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

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

        let o = new Object(77, 88, 99)
        console.log(o);   //Number {77}

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

JS高阶-函数构造:ES5继承,ES6类相关语法,this指向call/apply/bind,构造函数

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

方式3: 最终方案

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

继承-示意图

JS高阶-函数构造:ES5继承,ES6类相关语法,this指向call/apply/bind,构造函数

ES6类

基本语法

目标: 知道什么类

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

  • 作用: 创建对象

  • 语法:

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

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

constructor:构造函数

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

  • 在constructor内部添加, 相当于构造函数内部;

    // 1.创建类c1ass创建一个明星类
    class star {
    	//类的共有属性放到constructor里面
        constructor (name,age) {
            this.name = name;
            this.age = age;
        }
    }
    //2.利用类创建对象new
    var 1dh = new star ('刘德华',18);
    console. log(1dh);
    
  • 在constructor下面直接添加方法, 无符号分隔, 不需要写function关键字

//1.创建类class创建一个类
 //ES6:类   Person:后面没有()
        class Person {
            //构造函数:前面没有function关键词,结尾没有【,】分隔符!
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
            sing() {
                //方法,直接放下面写,要求和constructor一样
                console.log(this.name + "会唱歌");
            }
            eat() {
                console.log(this.name + "会干饭");
            }
        }
        //使用:
        let p = new Person("zs", 19)
        console.log(p);   //Person: age: 19   name: "zs"

继承

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

super的使用

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

补充知识

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

改变this指向

call方法的使用

  • 语法:函数.call();

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

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

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

apply方法

  • 作用: 1. 函数在该次的调用的时候, 其函数内部this 指向 我们指定参数的那个对象;
      1. 这个函数要执行的!
  • 参数: 1. this 指向 我们指定参数的那个对象
      1. fn要执行的时候, 把 参数 作为一个数组传入
//  apply: 作用和call一样!
    //    语法:函数.apply(参数1)
    //          在本地调用中,把函数内部this上属性,给了参数1;
    //    相同:call 与 apply 参数1:内部属性即将要去到新对象!前面函数肯定要执行!
    //  不同点:call  后面参数 【,】 隔开!
    //          apply 后面只有一个参数,把即将要传入实参,形成为数组!
// call演示:
    function fn(a, b) {
      this.a = a;
      this.b = b;
    }
    let obj1 = {
      info: "我是普通对象obj1"
    }
    fn.call(obj1, 99, 88);
    console.log(obj1);
//  apply演示:
    let obj2 = {
      info: "我是普通对象obj2"
    }
    fn.apply(obj2, [77, 66]);
  console.log(obj2);

bind方法

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

  • 如果只是想改变 this 指向, 并且不想调用这个函数的时候, 可以使用bind

    //bind;
    //知识改变函数内部this指向,不会让函数执行!
    //内部已经在强制性滚顶了,不管接下来该函数如何被调用!
    
    //语法:函数.bind(参数)
    //返回:返回新的函数(和旧的函数长一样),内部this已经被我们固定了!
    

JS高阶-函数构造:ES5继承,ES6类相关语法,this指向call/apply/bind,构造函数

  • Swiper插件的优化: 右侧点击功能, 下面这样写会构成闭包! 一个功能就是一个闭包! 多个功能就是多个闭包!
//bind;
//知识改变函数内部this指向,不会让函数执行!
//内部已经在强制性滚顶了,不管接下来该函数如何被调用!

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

call / apply/ bind 方法异同点

  • this: 大白话
    • 一般情况: 谁调用就是谁 !
    • 函数遇见call、 apply、 bind: 遇见第一参数是谁就是谁!
  • 相同点: 这样的调用方式, 都可以把本次调用的内的this 改变函数内部this指向!
  • 不同点
    • call 和 apply 会调用执行函数! bind 不会执行函数!
    • call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递 ;
上一篇:JavaScript数组(Array)方法大全


下一篇:ES5严格模式下的保护对象