06-面向对象(2)[构造函数、、、、、]

一、hasOwnProperty

(1)、遍历

  • for in 遍历对象和数组,返回的是下标索引和属性名

  • for of遍历对象,返回的是值,不能直接遍历对象

<script>
        var obj = {
            name: 'jack',
            age: 33
        }
​
        //遍历对象
        //for in 返回的是对象的属性名
        //for of 不能直接遍历对象
        for (i in obj) {
            console.log(i);
        }
​
        // for (i of obj) {
        //     console.log(i);
        // }
        var arr = ['a', 'b', 'c', 'd'];
        //遍历数组
        //for in :返回的是索引下标
        //for of : 返回的是值
        for (var i in arr) {
            console.log(i);
        }
        for (var i of arr) {
            console.log(i);
        }
    </script>

(2)、hasOwnProperty

如何判断属性是在构造函数里的实例里,还是在原型里

语法:对象名.hasOwnProperty('属性名')

实例返回true,否则返回属性

  • 如果返回true,则表示这个属性是构造函数里面定义的

  • 如果返回false,则表示这个属性是原型里面的,或者未被定义

 <script>
        var obj = {
            name: '东东',
            age: 17
        }
        for (var i in obj) {
            console.log(i, obj[i], obj.hasOwnProperty(i));
        }
​
        var person = function(name, age) {
            this.name = name;
            this.age = age
        }
        person.prototype.sex = '女'
        var p = new person('东东', 16)
        console.log(p.hasOwnProperty('name')); //true表示name是构造函数里面定义的
        console.log(p.hasOwnProperty('age')); //true表示age是Person构造函数里定义的
        console.log(p.hasOwnProperty('sex')); //false表示sex是原型上面定义的
        console.log(p.hasOwnProperty('hight')) //false表示未定义的
    </script>

二、constructor

在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性(是一个指针)指向prototype属性所在的函数

  • constructor返回构造函数,如果不是构造函数返回object

person.prototype.constructor===person  //返回true

(1)、prototype与constructor的关系

(2)、返回构造函数

  • 通过字面量创建的对象,返回Object

<script>
        function boy(name) {
            this.name = name;
        }
        var b = new boy('东东')
        console.log(b);//返回对象实例
        console.log(b.constructor);//返回构造函数
        console.log(boy.prototype.constructor)//返回构造函数
    </script>
<script>
        var obj = {
            name: '东东',
            age: 18
        }
        console.log(obj);
​
        function p(name) {
            this.name = name;
        }
        var a = new p('小网')
        console.log(a);
    </script>

三、原型链继承

(1)、含义:

  • 原型和原型之间进行继承,形成一个链条,称为原型链

(2)、语法:

  • 子元素.prototype=父元素实例

Student.prototype = new Person();
SmallStudent.prototype = new Student();
   
  <!-- 原型链继承 -->

<script>
        //类:人、学生、小学生、一年级学生、一年级一班学生
​
        //人
        function person() {
            this.name = '人'
        }
        //学生
        function student(school) {
            this.school = school
        }
        //小学生
        function smallstudent(name, age, school) {
            this.age = age;
        }
​
        //原型与原型之间进行继承,形成一个链条,称为原型链
        student.prototype = new person();
        smallstudent.prototype = new student('向阳小学')
​
        var s = new smallstudent('小明', 12, '花园小学')
        console.log(s);
        console.log(s.name); //人
        console.log(s.school); //向阳小学
        
         // 给原型上添加constructor属性,形成双向链条
        student.prototype.constructor = student;
        smallstudent.prototype.constructor = smallstudent;
    </script>

四、对象冒充继承

(1)、对象冒充的使用

  • 通过改变this指向来调用另外一个对象和自身对象相同的属性和方法,当然值是不一样的,传递的参数还是自身对象去传递

  • 语法:写在本构造函数里面,

    • 引用的构造函数名.call(this,参数1,参数2……)

    • call动态修改this指向,将引用的类改为本对象指向的类,后面跟的是属性值的形参

  • 对象冒充继承的对象不能继承它父类原型中的属性和方法

(2)、对象冒充的原理

  • 调用父类函数时改变this指向,定义子类的属性和方法

  • 在子类中:父类型.call(this,参数1,参数2,……);

  • 可以解决传参的问题,但是不能继承父类原型中的属性和方法

 <!-- 对象冒充继承 -->
    <script>
        function person(name) {
            this.name = name;
        }
​
        function student(name, school) {
            //将person的this指向动态改变为student
            person.call(this, name)
            this.school = school;
        }
​
        function smallstudent(name, age, school) {
            //为什么要这么设计?
            //创建子类之前,先调用父类,将父类里面的this改为smallstudent,给smallstudent添加学校
            student.call(this, name, school);
            this.age = age;
​
        }
​
        //好处;提取多个类的共性做成一个父类,把共性的属性和方法都放父类里面
        //子类里面只设置属于自己的属性
        function highstudent(name, height, school) {
            student.call(this, name, school)
            this.height = height;
        }
​
        var s = new smallstudent('小明', 2, '蜗牛')
        var h = new highstudent('大名', 11, '阳光小学')
        console.log(s);
        console.log(h);
    </script>

五、混合继承

原型链继承+对象冒充继承

原型链继承:把父类的方法放进原型中

对象冒充继承:构造函数的动态参数

<script>
        //混合继承
        // 对象冒充:构造函数的动态参数
        // 原型链:把父类的方法放进原型中
        function person(name, age) {
            this.name = name;
            this.age = age;
            this.eat = function() {
                console.log('吃饭');
            }
        }

        function student(name, age, grade) {
            //对象冒充继承
            person.call(this, name, age)
            this.grade = grade
        }

    //原型继承
        student.prototype = new person();
        student.prototype.constructor = student;

      

        var s = new student('班长', 223, '3班')
        console.log(s);
        s.eat();
    </script>

六、ES6中的类

  • /get和set访问器中,访问属性时要加下划线,防止出现无限递归问题

  • get和set一个是取值,一个是存值/设置值,设置传参过去的值显示的样式

  • new Animal("x",2).name;//当获取name值的时候,实际上是调用了 get name()

  • new Animal("x",2).name="j"//当给name赋值的时候,实际上调用了set name()

(一)

 <script>
        //创建类
        class Anima {
            //通过new运算符在创建对象时才会调用的构造函数
            constructor(name, age) {
                this.name = name;
                this.age = age;
            };
            //原型里面的方法
            hunter() {
                console.log('捕猎');
            }
        }

        var a = new Anima('老虎', 12)
        console.log(a); //l老虎
        console.log(a.name); //捕猎
        a.hunter()
    </script>

(二)、动物类案例

class Animal{
        //通过new运算符在创建对象时才会调用的构造函数
        constructor(name,age){
            this.name=name;
            this.age=age;
        }
        hunter(){
            console.log(捕猎);
        }
        //get和set访问器中,访问属性时要加下划线,防止出现无限递归问题

		//得到值,取值
        get name(){
            return this._name;
        }
		//设置值,存值
        set name(value){
            this._name=value;
        }
    }
    new Animal("x",2).name;//当获取name值的时候,实际上是调用了 get name()
    new Animal("x",2).name="j"//当给name赋值的时候,实际上调用了set name()

 <script>
        class Animal {
            //通过new运算符在创建对象时才会调用的构造函数
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
            hunter() {
                console.log(捕猎);
            }
        }

        // get和set一个是取值,一个是存值,设置传参过去的值显示的样式
        var a = new Animal("x", 2);

        console.log(a) //Animal {_name: "x", age: 2}

        a.name; //相当于get,获取值

        a.name = '东东'; //相当于set, 存储值

        console.log(a); //Animal {_name: "东东", age: 2}

        a.gender = '男';
        console.log(a); //Animal {_name: "东东", age: 2, gender: "男"}
    </script>

语法糖

 <script>
        //语法糖
        class Phone {
            constructor(brand, price, contact) {
                this.brand = brand;
                this.price = price;
                this._contact = contact;
            }

            //属性访问器:set、get
            set contact(newContact) {
                console.log("set contact", newContact)
                if (newContact.length > 0) {
                    this._contact = newContact;
                }
            }

            get contact() {
                this._contact = this._contact.map(item => {
                    //substr(从哪里开始截2取,截取几个) substring(从哪开始截取,截取的结束位置-1)
                    return "**" + item.tel.substring(2)
                })
                return this._contact;
            }
        }

        //创建一个实例对象
        var p = new Phone("MI", 2999, [{
            name: "小明",
            tel: "12312"
        }, {
            name: "小红",
            tel: "678"
        }]);



        p.contact = [];
        console.log(p.contact);
        p.contact = [{
            name: "小王",
            tel: "998282"
        }, {
            name: "小绿",
            tel: "736338"
        }];
        console.log(p.contact);
    </script>

案例:

 <script>
        class person {
            constructor(name, age, sex) {
                this.name = name;
                this.age = age;
                this.sex = sex;
            }

            // 设置年龄
            set age(value) {
                if (value > 18) {
                    this._age = value
                } else {
                    // console('年龄不能小于18')
                    this._age = '年龄不能小于18'

                }
            };
            //得到获取年龄
            get age() {
                return this._age
            }

            //设置姓别
            set sex(gender) {
                if (gender == '男' || gender == '女') {
                    this._sex = gender
                } else {
                    this._sex = '只能是男和女'
                }
            };
            //获取值
            get sex() {
                return this._sex
            }

        }

        var p = new person('东东', 1, '2')
        var d = new person('小黄', 44, '男')
        console.log(d);
        console.log(p);
    </script>

ES6类的继承

  • 继承:类 extend 被继承的类

  • 调用父类构造函数:super(被继承的行参)

 <!-- <script>
        //手机(父类)
        class Phone {
            constructor(brand, price, contact) {
                this.brand = brand;
                this.price = price;
                this.contact = contact;
            }
        }

        //智能手机(子类)
        class SmartPhone extends Phone {
            constructor(brand, price, contact, OS) {
                //调用父类构造函数
                super(brand, price, contact)
                this.OS = OS;
            }
        }

        var p = new SmartPhone("MI", 2999, [{
            name: "小明",
            tel: "12312"
        }, {
            name: "小红",
            tel: "678"
        }], 'Android');
        console.log(p);
    </script> -->

super:调用继承

ES6中的继承,用extends定义,用super调用,需要放在最前面

<script>
        class person {
            constructor(name, age) {
                    this.name = name;
                    this.age = age;
                }
                //在外面写的是属于原型里面的方法和属性
            work() {
                console.log('原型里的方法');
            }
        }
​
        class student extends person {
            constructor(name, age, major) {
                    //调用父类的构造函数,并传参数
                    super(name, age)
                    this.major = major;
                }
                // 子类重写(覆盖)了父类函数:父类函数内容太广泛,笼统,不具体,不能完成体现子类的特点
            work() {
                //用super.xxx可以获取父类的成员
​
                super.work();
                console.log('学生的工作就是学习');
            }
​
        }
        var s = new student('东东', 11, 'Web前端开发')
        console.log(s);
        s.work(); //原型里的方法,学生的工作就是学习
    </script>

ES6中的静态方法

  • 被stastic修饰的成员,不属于对象

  • 静态成员,属于类,通过类名调用,不再是对象调用

  • 被stastic修饰的成员属于类的,不在归属对象

  • 被stastic修饰的成员是该类创建的时候一起创建的

  • 平时用过的静态成员,大多数是工具函数

 <!-- ES6中的静态方法 -->
    <!-- <script>
        class Person {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
        }
​
        class Student extends Person {
            constructor(name, age, major) {
                super(name, age);
                this.major = major;
            }
            static role = 'kid'
            static getMyName() {
                console.log('getmyname:' + this.name); //返回当前类名        
            }
        }
        var s = new Student('东东', 11, 'Web前端')
        console.log(s);
​
        //1、被static修饰的成员,不属于对象
        //2、静态成员,属于类,通过类名调用,不再是对象调用
        console.log(Student.role);
        Student.getMyName() //得到的是Student类名
            //3、被static修饰的成员属于类的,不再归属对象
            //4、被static修饰的成员是该类创建的时候一起创建的
​
        //5、平时用过的静态成员,大多数是工具函数
        console.log(Date.now());
        console.log(Math.PI);
    </script> -->

ES6私有属性

  • 私有成员:在名称前面加#,访问范围仅限于class大括号以内

  • 私有属性,必须先在constructor之前定义一下,普通属性不用先定义

<script>
        class Animal {
            a;
            #b;
            constructor(a, b) {
                this.a = a;
                this.#b = b;
            }
            run() {
                console.log("this.#b : " + this.#b)
            }
            #stop() {
                console.log("stop")
            }
        }
        var x = new Animal("123", "456")
        console.log(x.a)
        x.run();
    </script>

七、代码错误

  • 语法错误:字母单词拼错等

  • 逻辑错误:通过调试找到错误,并解决

  • 难以预料的错误,即不确定错不错的代码:通过try(试试)——catch(捕获)来解决

    • 普通情况下,有一行代码报错,它后面的代码就都执行不了了

    • try-catch解决了这个问题,用了try-catch之后,即使报错也不会影响后续的代码

    • //try-catch语法
      try{
          //代码块(不确定对不对的代码)
          //如果在这个大括号里面有错误代码,它前面的代码是好的,好的代码会执行,错的代码后面的代码就都不执行了,直接跳过去执行catch里面的代码以及后面的代码
      }catch(error){
          //如果上面的代码块有错误的话就会执行,如果没有错误的话就不执行
      }
  • 主动抛出异常(主动报错)

 <!-- <script>
        var a = '你好吗?';
        console.log(a);
        //如果try里面的代码是正确的,就会直接输出,而catch里面的代码不执行
        //如果try里面的代码是错误的,就不会输出它,就会去输出catch里面的代码
        try {
            console.log(a); //正常输出
            console.lo('你好');
            console.log(a); //不会输出
        } catch (error) {
            console.log('错误原因:' + error);
        }
        console.log(a);
    </script> -->

 <!-- <script>
        //1、语法错误
        //was s=123;
​
        //2、逻辑错误:调试找到错误
​
        //3、难以预料的错误:try(试试)——catch(获取,捕获)
        try {
            //1、将有可能报错的代码放在try里面
            //2、如果try里面的代码是正确的,则正常运行
            //3、如果里面的代码是错的,则执行catch里面的执行,里面正确的还是会执行
            console.log('试试');
        } catch (error) {
            //4、如果出错了,才会进入catch里面,执行这里的代码
            console.log(error);
        }
        //5、用了try-catch之后,即使报错也不会影响后续的代码执行
        console.log('执行完毕');
    </script> -->
    <!-- <script>
        //主动抛出异常(主动报错)
        /*  function play() {
             throw '当前函数不可用'
         }
         try {
             play()
         } catch (error) {
             console.log('nihao1');
         } */
​
        /*  function play() {
            throw '当前函数不可用'
        }
        play() */
    </script> -->

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值