十二、类和对象进阶2

1.自执行方法

定义一个自执行函数,函数定义完成后,自己执行一次,函数名可以省略,因为没有任何意义

注意:要以分号结束,否则可能会影响后面的语句。

(function sayHello() {
    console.log('sayHello');
})();

自执行函数的简写形式

+ function sayYes() {
    console.log('sayYes');
}();

自执行函数,也可以直接定义成箭头函数

(()=>{
    console.log('aaa');
})()
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自执行函数</title>
</head>
<body>
    <script>
        function fun(){
            console.log('Hello');
        }
        fun();

        //自执行函数
        // 注意:要以分号结束,否则可能会影响后面的语句。
        (function fun2(){
            console.log('你好');
        })();

        //+号是自执行函数的简写
        +function fun3(){
            console.log('你好,中国');
        }();

        (()=>{
            console.log('你好,迪丽热巴');
        })();

        
    </script>
</body>
</html>

 控制台显示为:

2.rest参数

// ...args 就是rest参数
function fun1(a,b,c,...args){
    console.log(a,b,c);
    // arguments 是一个类数组对象,结构长得像数组,其实是一个object对象
    console.log(arguments);
    // rest参数 是一个数组对象,既然是数组,就可以直接使用数组的方法。
    console.log(args);
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>rest参数</title>
</head>
<body>
    <script>
        // 方法的形参前面添加...,就是方法的rest参数
        //...xxx 是函数的rest参数,用于接收剩余的实参,注意:通常情况下rest参数放在最后面
        //rest参数,解决了函数中arguments对象不是数组类型的缺陷
        function fun1(a,b,c,...args){
            console.log(a,b,c);
            console.log(args);
            let arr = args.map(r=>r*2)
            console.log(arr);
            // console.log(arguments);
        }
        fun1(100,200,300)
        fun1(100)
        fun1(10,20,30,40,50,60,70,80)
        console.log('------------------------');
        // 在定义函数时,可以给参数设置默认值
        function fun2(a,b=200,c=300){
            console.log(a,b,c);
        }
        fun2(1,2,3)
        fun2(1,2)
        fun2(1)
        fun2()
    </script>
</body>
</html>

控制台显示为:

3.展开运算符

展开运算符就是...,可以将一个数组全部展开

let arr3 = [...arr1,...arr2]

展开运算符,可以展开对象的全部成员,也可以将一个对象的成员,克隆给另一个对象

let lh2 = {...lh}

展开运算符,可以将多个对象的成员,合并到一个大的对象中,后面对象中的成员,如果跟前面对象中的成员同名,会覆盖前面的

let lxt = {...lh,...gxt}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>展开运算符</title>
</head>
<body>
    <script>
        let arr1 = [11,22,33]
        let arr2 = [44,55,66]
        let arr3 = arr1.concat(arr2)
        console.log(arr3);
        // ...在这里就是展开运算符,在这里,展开运算符用于展开数组中的所有成员。
        let arr4 = [...arr1,...arr2]
        console.log(arr4);
        console.log('---------------------------');
        let obj1 = {
            a:100,
            b:200
        }
        let obj2 = {
            c:300,
            d:400,
            a:500
        }
        // ...在这里,用于将对象的所有属性展开,并返回一个全新的对象
        let obj3 = {...obj1,...obj2}
        console.log(obj3);        
    </script>
</body>
</html>

控制台显示为:

4.解构赋值

ES6中的解构赋值语句,可以直接将数组中的每个元素提取出来

方式是:let [变量名1,变量名2,...] = 数组

ES6中的解构赋值语句,可以直接将对象中的每个元素提取出来

方式是:let {name,age,gender,job} = obj

通常情况下,对象的属性名称叫什么,就定义什么名称的变量去接,如果出现了同名,可以修改名称

方式是:let {name,age:age1,gender,job} = obj

在ES6中,定义对象时,属性的左右两边的表达式相同时,可以省略右边的表达式,该对象在定义的时候,会自动往父级作用域寻找同名属性名对应的值

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>解构赋值</title>
</head>
<body>
    <script>
        //定义变量
        let no = 1001
        let name = '小明'
        let age = 30
        let sex = '男'
        //定义对象
        let stu1 = {
            //属性名:属性值
            //这里的属性值是上面定义的变量保存的值
            no:no,
            name:name,
            age:age,
            sex:sex
        }
        console.log(stu1);
        console.log('-----------------');
        //对象的属性名和属性值的标识相同时,可以省略属性值
        let stu2 = {
            // 是no:no的简写
            no,
            name,
            age,
            sex
        }
        console.log(stu2);
        console.log('--------------------------------------');
        let stu3 = {
            username:'小明',
            userage:30,
            usersex:'男',
            car:{
                carName:'奔驰',
                carPrice:'100W'
            }
        }
        //过去我们这样写
        // let username = stu3.username
        // let userage = stu3.userage
        // let usersex = stu3.usersex
        //现在我们这样写(解构赋值)
        // usersex:usersex2 表示在解构的时候对变量名进行重命名
        let {username,userage,usersex:usersex2} = stu3
        console.log(username,userage,usersex2);
        console.log('-----------');
        // let {car} = stu3
        // let {carName,carPrice} = car
        let {car:{carName,carPrice}} = stu3  //这一行代码,最终会编译成下面的两行代码
        // let carName = stu3.car.carName
        // let carPrice = stu3.car.carPrice
        console.log(carName,carPrice);
        let arr = [11,22,33,44,55]
        // 解构数组中的元素,采用的[]
        let [a,b] = arr
        console.log(a,b);
    </script>
</body>
</html>

控制台显示为: 

5.值类型和引用类型

在js中,number,string,boolean,都是值类型,值类型的变量,直接将数据保存到内存的栈空间中。值类型的变量,在传递时,传的是副本。

在js中,对象,数组,都是引用类型,引用类型的变量,将数据保存在堆中,然后将堆的地址保存到栈中。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>值类型和引用类型</title>
</head>
<body>
    <script>
        function upateNum(num2){
            console.log('num2='+num2);
            num2+=5
            console.log('num2='+num2);
        }
        let num1 = 5  //number类型
        // 值类型在调用方法传递是,传的是值
        upateNum(num1)
        console.log('num1='+num1);//可以看出num1的值没变
        console.log('-------------------------');
        function updateArr(arr2){
            console.log('arr2',arr2);//[11,22,33,44,55]
            arr2.push(66)//[11,22,33,44,55,66]
            console.log('arr2',arr2);//[11,22,33,44,55,66]
        }
        //数组是引用类型
        let arr1 = [11,22,33,44,55]
        updateArr(arr1)
        console.log('arr1',arr1);//此时arr1与arr2的值都变了=>[11,22,33,44,55,66]
    </script>
</body>
</html>

控制台显示为:

6.原型对象

prototype属性是类的原型对象通常情况下,我们习惯将类的方法,定义到类的原型对象中,这样做的好处是,提高代码的利用率,不会开辟多余的内存空间。

__proto__属性对象的原型对象注意:同种类型多个对象上的原型对象 共同指向类型上的原型对象。类的原型对象上面的方法,类的对象,可以直接调用

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原型对象</title>
</head>
<body>
    <script>
        // 构造函数(类)有原型对象,其实就是构造函数身上的一个自带属性,这个属性是:prototype
        // 对象也有原型对象,其实就是对象身上的一个自带属性,这个属性是:__proto__
        // 所有同类型的对象身上的原型对象属性,都指向类的原型对象属性。
        // 类和对象的原型对象身上挂的方法,对象可以直接使用,不需要经过原型对象。
        function Student(name,age,sex){
            this.name = name
            this.age = age
            this.sex = sex
            // 如果将方法直接定义在类里面,将来根据这个类创建的每个对象,都要创建自己独立的这些方法
            // 如果要创建很多对象,对内存的开销会很大。
            /* this.sayHi = function(){
                console.log(`Hi!我叫${this.name},今年${this.age}岁,性别是${this.sex}`);
            }
            this.study = function(time){
                console.log(`Hi!我叫${this.name},我每天学习${time}小时`);
            }
            this.play = function(time){
                console.log(`Hi!我叫${this.name},我每天玩${time}小时`);
            } */
        }
        // 我们可以将类的方法,添加到类的原型对象身上
        Student.prototype.sayHi = function(){
            console.log(`Hi!我叫${this.name},今年${this.age}岁,性别是${this.sex}`);
        }
        Student.prototype.study = function(time){
            console.log(`Hi!我叫${this.name},我每天学习${time}小时`);
        }
        Student.prototype.play = function(time){
            console.log(`Hi!我叫${this.name},我每天玩${time}小时`);
        }

        let s1 = new Student('张三',20,'男')
        let s2 = new Student('李四',22,'女')
        let s3 = new Student('王五',24,'男')
        // 查看Student类的原型对象
        console.log(Student.prototype);
        // 查看三个对象的原型对象,一模一样。
        console.log(s1.__proto__);
        console.log(s2.__proto__);
        console.log(s3.__proto__);

        s1.sayHi()
        s1.study(8)
        s1.play(3)
        console.log('------------------');
        s2.sayHi()
        s2.study(6)
        s2.play(6)
        console.log('------------------');
        s3.sayHi()
        s3.study(10)
        s3.play(1)
        
    </script>
</body>
</html>

控制台显示为:

7.ES6中定义类的新语法

// 定义一个Person类型
class Person{
    // 构造函数
    constructor(name,age,gender){
        this.name = name,
        this.age = age
        this.gender = gender
    }
    // 给类添加一个方法
    sayHi = function(){
        console.log(this.name,this.age,this.gender);
    }
    //用这种方式定义的方法,是将方法定义的类的原型对象中去
    sayHello(){
        console.log('hello!');
    }
}

8.继承

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //ES5:
        // 定义一个人类
        function Person1(name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
        Person1.prototype.eat = function () {
            console.log(`我叫${this.name},我在吃饭...`);
        }
        Person1.prototype.say = function () {
            console.log(`大家好!我叫${this.name} 今年${this.age}岁 性别是${this.gender}`);
        }
        // 通过Person类型,创建出了两个对象
        let p1 = new Person1('张三', 20, '男')
        p1.say()
        p1.eat()
        let p2 = new Person1('李四', 21, '男')
        p2.say()
        p2.eat()
        console.log('-------------------------------------');

        //定义了学生类
        function Student1(name, age, gender, no) {
            // 继承Person类的属性
            Person1.call(this, name, age, gender)
            // Student类特有的属性
            this.no = no
        }
        // 给Student类的prototype属性 new一个Person类型的对象
        // 用于继承Person类的方法
        Student1.prototype = new Person1()
        Student1.prototype.study = function () {
            console.log(`我叫${this.name},我的学号是${this.no},我在学习...`);
        }
        let s1 = new Student1('王五', 20, '女', '1001')
        s1.study()
        s1.eat()
        s1.say()
        console.log("******************************************************");
        //ES6:
        // 定义人类
        class Person2 {
            // 定义构造函数
            constructor(name, age, gender) {
                this.name = name
                this.age = age
                this.gender = gender
            }
            // 说话方法
            say() {
                console.log(`大家好!我叫${this.name} 今年${this.age}岁 性别是${this.gender}`);
            }
            // 吃方法
            eat() {
                console.log(`我叫${this.name},我在吃饭...`);
            }
        }
        // 每个类型都一个prototype属性,我们称它为类的原型对象。
        // 类的原型对象上面的成员,给类的所有实例(实例就是类创建出来的对象)共享。
        console.log(Person2.prototype);
        // 通过Person类型,创建出了两个对象
        let p3 = new Person2('张三', 20, '男')
        console.log(p3);
        p3.say()
        p3.eat()
        let p4 = new Person2('李四', 21, '男')
        console.log(p4);
        p4.say()
        p4.eat()
        console.log('-------------------------------------');
        // extends关键字,表示继承
        class Student2 extends Person2 {
            // 构造函数
            constructor(name, age, gender, no) {
                // 调用父类的构造函数
                super(name, age, gender)
                // 学生特有的属性
                this.no = no
            }
            //学生学习的方法
            study() {
                console.log(`我叫${this.name},我的学号是${this.no},我在学习...`);
            }
        }
        let s2 = new Student2('王五', 20, '女', '1001')
        console.log(s2);
        s2.study()
        s2.eat()
        s2.say()
    </script>
</body>

</html>

控制台显示为: 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值