JS-面向对象

本文详细探讨了JavaScript中构造函数、原型对象、对象冒充继承和ES6类的使用,包括创建对象的不同方式,原型链的继承机制,以及私有属性的实现。通过实例解析了构造函数与原型的关系,展示了如何利用它们进行高效、灵活的对象设计。
摘要由CSDN通过智能技术生成

创建对象

字面量: var obj = {}


实例创建对象:var obj = new Object()


工程模式创建对象:在函数内部创建对象,且return出来。(解构不明确)

​ 好处:外部无需关注工程函数里面具体怎么实现的【隐藏细节】

function createObject = {
	var obj = new Object
}
createObject()

构造函数创建对象

    <script>
      // 构造函数 -> 类
      function Play(phone, brank, type, screen) {
        // 在构造函数中不要用this,用普通的函数和变量创建就是私有的
        let myPhone = phone;
        let myBrank = brank;
        // 在构造函数中用this点出来的属性和方法都是public的【公开】
        this.myType = type;
        this.myScreen = screen;
        this.fun = function (call, text, photo, Internet, GPS) {
          // 一般参数都写在外部函数中
          this.myCall = call;
          this.myText = text;
          this.myPhoto = phone;
          this.myInternet = Internet;
          this.myGPS = GPS;
          console.log("大叫好");
          return 123;
          fun2(); // 外部无法获取
        };
        // 私有的方法虽然写在Play里面,但是它是属于window的,本质上与Play无关
        function fun2() {
          console.log(this);
        }
      }
      //创建Play实例
      let Phone = new Play("智能机", "苹果", 1, 4.7); // 有new就相当于改变了this的指向,把他由window改为了Play
      Phone.fun("打电话", "发短信", "拍照", "上网", "GPS");
      console.log(Phone); // Play {myType: 1, myScreen: 4.7} phone, brank为私有的外部无法调用
      console.log(Phone.fun());
    </script>

构造函数的原型对象:ProtoType

<script>
	// 每个对象都有__prototype__属性
    function Student(){}
    // 给构造函数挂在一个原型propoType,目的是减少某些函数的调用
    Student.propotype.style = function(){}
</script>
    <script>
      // 每个对象都有__proto__属性
      function Person(name) {
        this.myName = name;
      }
      var p = new Person("张三");
      console.log(p); // Person {myName: "张三"}
      console.log(p.__proto__); // {constructor: ƒ}

      var arr = new Array()
      console.log(arr.__proto__); // [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]
    </script> 
    <script>
      // prototype原型的好处:
      // 给构造函数挂挂载一个原型prototype,目的是减少某些函数的调用
      // 只需在原型上创建一次,以后不论创建出来多少个对象,大家都共用
      function Student(name) {
        this.name = name;
      }
      //构造函数名.prototype(共享)
      Student.prototype.school = function () {
        console.log("蜗牛");
        console.log(this); // Student {name: "XX"}
        this.age = 18;
      };
      Student.prototype.home = "天涯海角";
      //给Student设置一个原型,就是{},{}的原型是Object
      Student.prototype.obj = {
        school: function () {},
        home: function () {},
      };
      var name1 = new Student("小王");
      var name2 = new Student("老王");
      // name1.school();
      console.log(name1);
      console.log(name2);
      // 调用prototype【调取的时候不需要__proto__】
      name2.school(); // 蜗牛
      // 修改prototype【想要修改时才需要通过__proto__】
      name1.__proto__.home = "中华大饭店"; // 虽然是在name1上修改,但是因为proto为公用的,所以大家都变
      Student.prototype.home = "超级大酒店";
      console.log(name1.__proto === Student.prototype); // true 两个方法效果相同
      // 对象的默认原型Object,Object是根
      console.log({ name: "张三" });
      // 创建一个没有原型的对象
      let obj = Object.create(null);
      console.log(obj);
      // 创建一个带有原型【run: function () {}】的对象
      let obj2 = Object.create({ run: function () {} });
      console.log(obj2);
    </script>

原型模型的优先级(就近原则)

当构造函数内部的成员与原型上的内容重名了,寻找规则:就近原则

hasOwnProperty

hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

    <script>
      let obj = {
        name: "张三",
        age: 18,
      };
      for (let i in obj) {
        console.log(i, obj[i], obj.hasOwnProperty(i)); // 检查i对应的属性是否是在obj构造函数中定义的
      }

      let liList = document.querySelectorAll("li");
      for (let i in liList) {
        console.log(i, liList.hasOwnProperty(i));
      }
    </script>

constructor(构造函数)

constructor:构造函数

对象.constructor【对象所在的类(构造函数)】

p1.constructor【对象所在的类(构造函数)】

构造函数.prototype.constructor

p1.prototype.constructor
    <script>
        function Person(){}
        // Person.prototype.name="jack"
        Person.prototype = {
            constructor:Person,
            name:"Nicholas",
            age:29,
            job:"Software Engineer",
            sayName:function(){}
        }
        var p1 = new Person();
        var p2 = new Person();
        console.log(p1)
        console.log(p1.constructor);//对象.constructor 【对象所在的类(构造函数)】
        console.log(Person.prototype.constructor);//构造函数名.prototype.constructor 【构造函数】

    </script>

原型链继承

原型与原型之间多层次之间的继承形成的链条称之为原型链。

子元素.prototype = new 父元素

<script>
    function father(name){
        this.myName=name;
    }
	function son(age){
        this.myAge=age;
    }
    son.prototype = new father('张三');
    let gogo = new son(13);
    console.log(gogo)
    //输出
    // son {myAge: 13}
        // myAge: 13
        // [[Prototype]]: father
            // myName: "张三"
                // [[Prototype]]: Object

</script>

对象冒充继承

好处:

  1. 提取了多个类的共性做成一个父类,把共性的属性和方法都放父类里面
  2. 子类里面只设计属于自己的属性

单继承

<script>
    function father(name){
        this.myName=name;	
    }
	function son(name,age){
        father.call(this,name);		// 创建子类之前,先调用父类,将父类里的this改成son,给son添加年龄属性
        this.myAge = age;
    }
    let gogo = new son('张三',13);
    console.log(gogo);	// son {myName: '张三', myAge: 13}
</script>

混合继承

原型链继承:无法传参

对象冒充继承:没有原型链

extends:扩展 super:超级

混合继承

  • 对象冒充:构造函数的动态参数
  • 原型链:把父元素的方法放到原型中
    <script>
      // 手机(父类)
      class Phone {
        constructor(pName, pMoney) {
          this.name = pName;
          this.money = pMoney;
        }
      }
      class SmartPhone extends Phone {
        constructor(pName, pMoney, pColor) {
        // 调用父级的构造函数并传参
            // 用super.xxx可以获取父类的成员
          super(pName, pMoney);
          this.color = pColor;
        }
      }
      let p = new SmartPhone("苹果", "8888", "red");
      console.log(p);
    </script>

ES6中的类

  • set必须有形参
  • get必须没有形参
<script>
    calss Father{
        constructor(name){
            this.Myname = name
        }
        work(){
            console.log('工作~~')
        }
        set name(name){}
        get name(){
            this Myname = name;
        }
    }
</script>

ES6面向对象

super:用于访问和调用一个对象的父对象上的函数。

super.propsuper[expr]表达式在对象字面量任何方法定义中都是有效的。

super必须放到第一行

<script>
      class Father {
        constructor(name) {
          this.Myname = name;
        }
        work() {
          console.log("工作~~");
        }
        set name(name) {
          // set必须有形参
        }
        get name() {
          // get不可以有形参
          console.log("♪(^∇^*)~~");
        }
      }
      // 子类
      class Son extends Father {
        constructor(name, age) {
          super(name);
          this.myAge = age;
        }
        work() {
          super.work(); // 解决同名情况下,子元素覆盖父元素的问题
          console.log("不想工作~~");
        }
      }
      var son = new Son("张三", 20);
      son.work(); // 输出不想工作~~ , 父元素的work被覆盖
    </script>

static

    <script>
      class People {
        constructor(name) {
          this.Myname = name;
        }
        static rolr = "kid";
        static getMyName() {
          return this.name; // name是自带的,表示类名
        }
      }
      let people = new People("张三");
      console.log(people);
      console.log(People.name);
      //1.被static修饰的成员,通过类名调用的,不是对象调用
      People.getMyName();
      //2.被static修饰的成员归属于类的,不归属于对象
      //3.被static修饰的成员是该类创建时也一起创建的

      //平时用过的静态成员(大多是工具函数)
      console.log(Date.now());
      console.log(Math.PI);
    </script>

面试题

ES5 定义私有属性	(有问题,还需修改)
<script>
	class Animal {
        constructor(a,b){
            this.A = a;
            let B = b;
        }
    }
    let letter = new Animal(123,456)
    console.log(letter.A)
    console.log(letter.B)
</script>
ES6 定义私有属性(由于IE兼容问题,大多数情况下依然使用ES5的写法)

    <script>
      class Animal {
        // 私有成员:在名称前加#,访问范围仅限于class大括号以内
        // 私有属性必须在constructor之前定义
        // 普通属性不用预先定义
        a;
        #b;
        constructor(a, b) {
          this.a = a;
          this.#b = b;
        }
        run() {
          console.log(this.#b);
        }
        #stop() {
          console.log("私有函数");
        }
      }
      var x = new Animal(123, 456);
      console.log(x.a); // 123
      x.run();  // 456
      // console.log(x.#b);  
      // console.log(x.#stop());
      // 报错:Private field '#b' must be declared in an enclosing class(私有字段'#b'必须在封闭类中声明)
    </script>

异常

  1. 语法错误
  2. 逻辑错误
  3. 难以预料(try(试试)-catch(buhuo(捕获))
用了try-catch后即使报错也不会影响后续代码的运行
<script>
	try{
        // 试一试
    }
    catch(error){
        // 如果出错执行此行代码
        // error 出错信息
    }
    
    // 主动报错
    function play(){
        throw '主动报错'
    }
</script>

练习

    <script>
      try {
        // 不适用于语法错误
        alertn(123);
      } catch (error) {
        console.log(error);
      }
      console.log("大家好");
    </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值