JS高级04

本文深入探讨JavaScript中的函数执行模式,包括普通函数、方法及构造函数调用,并介绍如何通过call、apply和bind改变函数上下文。此外,还讲解了ES6类的创建、方法添加及继承方式。


小概

本章学习内容:函数基本执行模式(普通函数调用,方法调用,构造函数调用) 了解函数/方法中的this指向;函数上下文调用模式(call(),apply(),bind()) 修改函数中的this指向;ES6类的介绍(类的创建,类添加方法,类的继承),super关键字的用法介绍。


1. 函数的基本执行模式

函数执行的三种方式:清楚函数中this的指向

  1. 普通函数调用
        //1.普通函数调用. 
        //this就指向window对象. 
        function test(){
            console.log('test函数');
            console.log(this);
        }
        //test(); //相当于是window.test();
  1. 作为方法调用
let obj = {
	name:'小斐',
	age:18,
	sayHi:function(){
	console.log('你好');
	console.log(this);
}
obj.sayHi();   //this指向调用者obj

谁调用这个方法/函数,那这个方法/函数中的this就是指向谁.

  1. 作为构造函数调用
        function Student(name,age){
            this.name = name;
            this.age = age;
            console.log(this);
        }

        let s2 = new Student('德华',21);  //Student

        Student('倩倩',23); //window.Student('倩倩',23);

不要管方法/函数是如何声明的,要看她是如何调用的,牢记谁调用这个方法/函数,这个函数/方法中的this就是谁.

2. 函数上下文调用模式

上述的三种执行方式是无法更改函数/方法中的this指向,所以需要使用到函数的第四种调用模式:函数上下文调用模式。

2.1 call()

语法:函数名。call(this的新指向,arg1,agr2…);

        let obj = {
            name: '广坤'
        }
        function getSum(num1,num2){
            console.log(num1+num2);
            console.log(this);
        }
        //getSum(10,20);
        getSum.call(obj,100,200);

2.2 apply()

语法:函数名.apply(this的新指向,数组或者伪数组);apply方法只能传两个参数。

       function getSum(num1, num2) {
            console.log(num1 + num2);
            console.log(this);
        }
        //getSum(10,20);
        getSum.apply(obj,[30,40]); //依次的把数组的元素交给形参.

2.3 bind()

语法:函数名.bind(this的新指向[,arg1[,arg2…]])
注意:bind不会执行这个函数,而是返回一个this改变了而函数体一样的函数

       function getSum(num1, num2) {
            console.log(num1 + num2);
            console.log(this);
        }
        //getSum(10,20);
        let fn = getSum.bind(obj,10,20);//fn接收改变this指向的函数
        fn(100,300);//调用

2.4 应用场景

需求:查找数组中的最大值/最小值

	let arr = [1.,2,23,50,-10,];
	let max = Math.max.apple(Math,arr);//把arr的每一个元素依次的交给max函数

需求:把伪数组转成真数组

	let weiArr = {
		    0:'张三',
            1:'李四',
            2:'王五',
            3:'陈麻子',
            4:'狗蛋',
            5:'狗剩儿',
            length:6
	}
	    //2. push();
        // let arr = [];
        // arr.push.apply(arr,weiArr); //把weiArr的每一项依次的交给push.
        // console.log(arr);

        //3. concat();
        // let arr = [];
        // arr = arr.concat.apply(arr,weiArr); //把weiArr的每一项依次的交给concat.
        // console.log(arr);

        //4. slice();
        //如果weiArr可以调用数组的slice方法,那就会返回一个元素和weiArr一样的真数组,
        //let arr = weiArr.slice(0);//但是很遗憾,weiArr不能调用数组的slice方法,所以这里报错了. 
        //那怎么办? 借用
        // let arr = Array.prototype.slice.call(weiArr,0);
        // console.log(arr);

        //5.es6语法. 
        // let arr = Array.from(weiArr);
        // console.log(arr);

需求:对元素都是数组的伪数组进行排序

        let weiArr = {
            0: 1109,
            1: 110,
            2: 220,
            3: 215,
            4: 210,
            5: 500,
            6: 400,
            length: 7
        }
        //如果weiArr也能调用数组的sort方法,那就可以排序. 
        //但是他是伪数组,不能直接调用数组的sort方法. 
        Array.prototype.sort.call(weiArr,function(a,b){
            return a-b;
        });
        console.log(weiArr);

2.5 组合继承

        //组合继承. 

        function Person(name,age){
            this.name = name;
            this.age = age;
        }
        //替换Person的原型
        Person.prototype = {
            constructor:Person,
            sayHi:function(){
                console.log('你好,你吃了吗?');
            }
        }
        //实例化一个人对象
        let wangjianlin = new Person('王健林',58);
        wangjianlin.house = {address:'东京',price:'1000000'};
        console.log(wangjianlin);

        //------------------------------------------------------------
        function Student(name,age,score){
           //借用构造函数继承 
           Person.call(this,name,age);

           this.score = score;
        }
        //替换原型继承
        Student.prototype = wangjianlin;

2.6 万能数据检测

万能数据类型检测

		console.log(Object.prototype.toString.call(123));//'[object Number]'
      	console.log(Object.prototype.toString.call('abc'));//'[object String]'

3. ES6 类

3.1 类的创建

es6之前没有类的概念

        class Student {
            constructor(name,age,score){
                this.name = name;
                this.age = age;
                this.score = score;
            }
        }

        //实例化一个对象
        let s1 = new Student('龙龙',18,100);
        console.log(s1);

        //再实例化一个对象
        let s2 = new Student('伟哥',20,99);
        console.log(s2);

        //思考:
        //es6中的类,本质就是es5中的构造函数.  
        console.log(typeof Student);//function
        console.log(s1.__proto__ === Student.prototype);//true
        console.log(s2.__proto__ === Student.prototype);//true
        console.log(Student.prototype.constructor === Student); //true

注意:
1.声明类的时候,类名后面不要加小括号.
2.声明类的时候,类名首字母大写,类名也是一个名词.
3.用new关键字去实例化类的对象,会自动的调用constructor构造函数.
4.如果你声明类的时候,没有写constructor构造函数,那系统会自动的给你生成一个constructor构造函数.

3.2 类中添加方法

        class Student {
            constructor(name,age,score){
                this.name = name;
                this.age = age;
                this.score = score;
            }
            study(kcName){
                console.log('我是学生,我的名字是'+this.name+',我在学习'+kcName);
            }
        }
        //往原型中添加一个方法
        // Student.prototype.eat = function(){
        //     console.log('吃饭');
        // }
        // console.dir(Student.prototype);

3.3 类的继承

       //创建一个学生类. 
        class Student {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
            study(kcName) {
                console.log('我是学生,我的名字是' + this.name + ',我在学习' + kcName);
            }
        }
        //创建一个大学生类 继承自 学生类 
        class CollegeStudent extends Student{
        }

		//实例化大学生对象. 
        let cs1 = new CollegeStudent('龙龙',19);
        console.log(cs1);
        cs1.study('金瓶梅');

        //本质: 原型链继承
        console.log(cs1.__proto__ === CollegeStudent.prototype);//true
        console.log(cs1.__proto__.__proto__ === Student.prototype);//true

本质:原型链的继承

3.4 super关键字

super(); //调用父类的构造函数(构造器).
super.xx(); //调用父类的方法.

        //创建一个大学生类 继承自 学生类 
        class CollegeStudent extends Student{
            constructor(name,age,dx){
                //就是在子类的构造器中一定要调用父类的构造器.并且这句话一定要写在子类构造器的第一句.
                super(name,age);

                console.log(this === that);//true
                this.dx = dx;
            }
        }
        //实例化大学生对象. 
        let cs1 = new CollegeStudent('龙龙',19,'蒋毅');
        console.log(cs1);

如果子类constructor中需要新增属性,super()一定要写在子类构造器的第一句.
子类需要使用父类的方法:super.方法名().
注意:先写类,再用类实例化对象(写在类后面,不然会报错)。

总结

关键字:call,apply,bind;改变this指向,不同的环境用对应的关键字,call(指向对象,形参…)和apply(指向对象,[数组/伪数组])这两个修改this指向都会执行函数。bind则不会,但是bind会返回一个修改this指向后的函数,场景单击事件…
(子类)expends(父类) 类继承,super子类内部继承父类constructor/方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值