js中的对象/构造函数

  <script>
    // 七:对象

    // 一、对象
      var obj = {} // 字面量创建
      var obj1 = new Object() // 构造函数创建

    //二、构造函数
    Car.prototype.run = function() {
      this.height --
      console.log('height',  this.height);
    }
    // Car.prototype = {
    //   constructor: Car,
    //   run: function() {},
    //   start: function() {}
    // }
    function Car() {
      this.name = 'BMW'
      this.color = 'red'
      this.height = 100
      // this.run = function() {
      //   this.height --
      //   console.log('height',  this.height);
      // }
    }
    const car1 = new Car()
    console.log('__proto__', car1.__proto__);
    console.log('prototype', Car.prototype);
    car1.run()
    const car2 = new Car()
    car2.run()

    /*
      实例原型 prototype
      实例对象 __proto__
      

      一、内存浪费?
        如果调用两次new就会单独开辟两个空间来存放this.run ,如果创建100个呢,那么就容易内存浪费。
        this.run = function() {
          this.height --
          console.log('height',  this.height);
        } 

      二、如何解决?
        一般情况下,我们公共的属性定义到构造函数中,公共方法放在原型对象上(prototype)
        Car.prototype.run = function() {
          this.height --
          console.log('height',  this.height);
        }
        
      三、每个实例对象都有一个 __proto__ 、指向构造函数的 prototype 原型对象,实例对象中的
        car1.__proto__ === Car.prototype
        
      四、如果有多个原型对象,改为对象形式,那么constructor就会丢失,这时候就需要我们修改constructor
        Car.prototype = {
          constructor: Car,
          run: function() {},
          start: function() {}
        }
        const car1 = new Car()
        console.log(car1.__proto__); // constructor丢失
        console.log(Car.prototype); // constructor丢失
    */

    // 三、原型链
    let that = null
    Person.prototype.run = function() {
      that = this
    }
    Object.prototype.age = 15
    // Person.prototype.age = 14
    function Person() {}
    const person1 = new Person()
    // person1.age = 13
    person1.run()
    console.log('age', person1.age);
    console.log('this指向实例对象', person1 === that);
    /*
        原型链: 访问age,实例对象上没有,向Person.prototype中查找,还没有,向Object.prototype中查找,如果都没有就没有
    */
    
    // 原型链 ,最后直到访问 null,就是最顶级的。Person.prototype指向Person原型对象,在向上访问到__proto__指向Object原型对象,在向上访问为null
    console.log('person.proto指向Person原型对象', person1.__proto__);
    console.log('Person.prototype指向Person原型对象', Person.prototype);
    console.log('Person.prototype.__proto__指向Object原型对象', Person.prototype.__proto__);
    console.log('Object原型对象.__proto__指向 null 万物皆是空 null', Person.prototype.__proto__.__proto__);


    // 四、es5中使用实例对象继承、es6中使用class 类继承, 如何实现?
    // 1、如何让孩子继承父亲的属性
    // 2、如何让孩子继承父亲的方法,(存在问题?) 自己来一遍吧
    Father.prototype.run = function() { console.log('都需要运动')}
    function Father(name, age) {
      this.name = name
      this.age = age
    }
    const father = new Father()
    function Son(name, age) {
      //1、 继承属性
      Father.call(this, name, age)
      this.study = '学习'
    }
    /*
      // 2、继承方法 存在的问题,给孩子添加方法时,父级也会添加,不可取
      Son.prototype = Father.prototype
      Son.prototype.start = function() { console.log('开始运动')}
    */
    Son.prototype = father // 相当于 son.prototype = {},重新修改了原型对象,需要执行constructor
    Son.prototype.constructor = Son
    const son = new Son('孩子', 10)
    console.log('实例对象', son);
    console.log('原型对象', Son.prototype);
    son.run()
    console.log(Father.prototype);
    console.log(Son.prototype.constructor);
  </script>
 /*
    // 第一种, 直接改变原型中的属性,原来的属性值也会受到影响
      Person.prototype.name = '小一'
      function Person() {

      }
      Son.prototype = Person.prototype
      function Son() {}
      Person.prototype.name = '小二'
      const son = new Son()
      console.log('son.name: ', son.name); // 观察Person.prototype 赋值之后打印的name
      Person.prototype.name = '小三'
    */

    /*
     // 第二种 引用赋值,直接将Person.prototype 赋值给 Son.prototype,会开辟新的空间,不会影响原来的值
     Person.prototype.name = '小一' //let obj = { name: 'a'}
      function Person() {
        // this = {
        //   __proto__ : Person.prototype // 隐士调用 
        // }
        
      }
      Son.prototype = Person.prototype // let obj1 = obj
      function Son() {}
      Person.prototype = { // obj = {name: 'b'}
        name: '小二'
      }
      const son = new Son()
      console.log('son.name: ', son.name); // 会影响原来 Son。prototype 指向的name 吗?
      

      let obj = { name: 'a'}
      let obj1 = obj
      obj = {name: 'b'}
      console.log(obj1.name);
    */

    /*

    一、...args剩余参数(展开运算符)  返回一个数组,可以使用数组原型中的方法

      允许一个表达式在某处展开。展开运算法 在 多个参数(函数调用)、多个元素(用于数组和字面量)和多个变量(用于解构赋值) 地方使用。剩余参数语法允许我们将一个不定数量的参数表示为一个数组。

      如果函数的最后一个命名参数以 ... 为前缀,则它会将所有后面剩余的是实参个数包裹成一个数组。

      // 例子

      function test(a, b, ...args) {

      console.log(args)

      }

      test(1,2,3,4) // [3, 4]

      二、arguments对象  返回一个 类数组对象,不具有数据的方法

      在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。arguments对象并不是一个数组,是一个类数组对象,在调用时请注意。

      arguments 中包含了函数传递的参数、length、和 callee 属性。

      length 属性表示的是实参的长度,即调用函数的时候传入的参数个数。

      callee 属性则指向的函数自身,我们可以通过它来调用自身函数。

      arguments 是一个经典的类数组对象,我们可以通过Function.call 或者 Function.apply 方法来间接调用数组的方法,也可以直接通过 Array.prototype.slice 或 Array.prototype.splice 等方法把类数组对象转换成真正的数组。
   
    */

    /* 
      // new实现过程
      function myNew(_constructor, ...args) {
        debugger
  
        // 1. 创建一个空对象
        const obj = {}; 

        // 2. 将obj的_proto_属性指向构造函数的原型对象
        obj.__proto__ = _constructor.prototype; 
        
        // 3.将_constructor执行的上下文this绑定到obj上,并执行
        const result = _constructor.apply(obj, args);

        //4. 如果构造函数返回的是对象,则使用构造函数执行的结果。否则,返回新创建的对象
        return result instanceof Object ? result : obj;  // 如果使用自己函数的对象,那么原型中的函数将无法使用

      }

      function Person(name, age){
  
        this.name = name;

        this.age = age;
        return { name: 123}

      }

      Person.prototype.sayHello = function(){

        console.log("hello" + this.name)

      }
      const person1 = myNew(Person, 'Tom', 20)
      const person2 = new Person('Tom', 20)

      console.log(person1) //Person {name: "Tom", age: 20}
      console.log(person2) //Person {name: "Tom", age: 20}
      // person1.sayHello() //helloTom
      // person2.sayHello() //helloTom

      function myNew1(_construtor, ...args) {

      }

    */

    // 注意
    Object.create() //在括号里面只能放 null 或者 Object,其余会报错





7种继承的方式

参考链接:https://blog.csdn.net/wuliyouMaozhi/article/details/125905733

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值