2021-11-29

十二、类和对象进阶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>

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

推荐阅读更多精彩内容