js中的继承

javaScript

继承的概念

  1. 一个对象能够访问另一个对象的属性,同时,这个对象还能够添加自己新的属性或是覆盖可访问的另一个对象的属性

实现继承的两种方式

  1. 创建一个对象并指定其继承对象(原型对象)
  2. 修改构造函数得原型属性(对象)

关于Object.create()和对象继承

  1. object.create()函数是一个创建对象时设置对象内部--proto--属性得api,通过修改--proto--属性的值,我们就能决定对象所继承的对象,从而以我们想要的方式实现继承;

    var x = { 
        name: 'tom',
        sayName: function() {
            console.log(this.name)
        }
    }
    var y = Object.create(x, {
        name: {
            configurable: true,
            enumerable: true,
            value: 'kitty',
            writable: true,
        }
    })
    y.sayName() // 'kitty'
    
    • 创建了一个空对象,并赋值给相应变量;
    • 将第一个参数对象设置为该对象__proto__属性的值;
    • 在该对象上调用defineProperty()方法,并将第二个参数传入该方法中;
    • 缺点:
      • 这种设置继承的方式是一次性的

关于prototype 和构造函数继承

  1. 几乎所有函数都拥有prototype属性;

  2. 构造函数生产实例对象的过程本身就是一种天然的继承。

  • 天然继承缺点:
    • 只存在两层继承-- 自定义构造函数的prototype对象继承Object构造函数的prototype属性,构造函数的实例对象继承构造函数的prototype属性。
  1. function Foo(x, y) {
        this.x = x
        this.y = y
    }
    Foo.prototype.sayX = function() {
        console.log(this.x)
    } 
    Foo.prototype.sayY = function() {
        console.log(this.y)
    }
    
    function Bar(z) {
        this.z = z 
        this.x = 10
    }
    Bar.prototype = Object.create(Foo.prototype) // 注意这里
    Bar.prototype.sayZ = function() {
        console.log(this.z)
    }
    Bar.prototype.constructor = Bar
    
    var o = new Bar(1)
    o.sayX() // 10
    o.sayZ() // 1
    o.sayY() // undefined
    
    • 造函数Bar的实例对象就会在查询属性时攀爬原型链,从自有属性开始,途径Bar.prototypeFoo.prototype,最终到达Object.prototype
  2. 如果要让o.sayY()不为undefined需要使用call(),apply()方法

    function Foo(x, y) {
        this.x = x
        this.y = y
    }
    Foo.prototype.sayX = function() {
        console.log(this.x)
    } 
    Foo.prototype.sayY = function() {
        console.log(this.y)
    }
    
    function Bar(z) {
        this.z = z 
        this.x = 10
        Foo.call(this, z, z) // 注意这里
    }
    Bar.prototype = Object.create(Foo.prototype) 
    Bar.prototype.sayZ = function() {
        console.log(this.z)
    }
    Bar.prototype.constructor = Bar
    
    var o = new Bar(1)
    o.sayX() // 1
    o.sayY() // 1
    o.sayZ() // 1
    
    • 首先我们知道构造函数也是函数,因此我们可以像普通函数一样调用他,让我们以单纯的函数视角看待构造函数Foo,它不过是往this所指的对象上添加了两个属性,然后返回了undefined值,当我们单纯调用该函数时,this的指向为window
    • 但是通过call()apply()函数,我们可以人为的改变函数内this指针的指向,所以我们将构造函数内的this传入call()函数中 。原先为Foo函数实例对象添加的属性现在添加到了Bar函数的实例对象上
  3. this的指向。

    1. 什么是this?

      • 在JavaScript中,this指针是在创建函数时,由系统默认生成的两个隐式参数之一(另一个是arguments)。
      • his指针指向与该函数调用进行隐式关联的一个对象,该对象被称为“函数上下文”。
    2. this指针指向哪?

      • 作为函数进行调用 :

      • 函数通常通过()操作符进行调用,此时函数内的this指针指向的是window对象。

      • var object = {
            way1 : function() {
                console.log(this);
                function innerFunc() {
                    console.log(this);   
                }
                innerFunc();
            }
        }    
        
        object.way1();
        
        //object
        //window
        
      • 作为方法进行调用 :

      • 一个方法所属的对象在该方法体内可以以this的形式进行引用,因此,当一个函数以方法的形式被调用时,this指针指向该方法的所有者。

      • 作为构造器进行调用:

      • function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        
        var jenny = new Person('jenny',24);
        
        console.log(jenny.name); //jenny
        

        构造函数的调用,返回值即为一个对象,而这个对象即为构造函数作用域内this指针的引用对象,即“函数上下文”。

      • call(),apply()方法调用

      • function getName(age,sex) {
            console.log(this.name);
            this.age = age;
            this.sex = sex;  
        }
        
        var jenny = { name : jenny };
        
        getName.call(jenny,24,female);
        
        getName.apply(jenny,[24,female]);
        
        //jenny
        
      • 两种调用方式的唯一区别在于,传入参数的形式,call方法依次写入参数,而apply方法则将所需传入函数的参数打包为一个数组统一传入。

      • 函数内部的this指针指向call与apply方法指定的对象。

  4. ​ call(),aply(),bind()方法

    1. call()调用函数 , 在调用是 改变this的指向-- 函数体.call(指向的对象,参数1 ,参数2…);(call用作继承时可以改变this指向)call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。

    2. apply()接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。

    3. bind()它会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。而原函数的 this 并没有被改变,依旧指向全局对象 window。

    4. var obj1 = {
          name: 'obj1',
          getName () {
              console.log(this.name)
          }
      }
      var obj2 = {
          name: 'obj2',
          getName () {
              console.log(this.name)
          }
      }
      obj1.getName() // obj1
      bind()
      (1)bind方法直接使用没反应,只是改变this指向obj2,不会立即执行; 
      (2)需要()手动执行方法 ,生成一个全新的函数; 
      (3)可以传多个参数;
        obj1.getName.bind(obj2) // 没反应,只是改变this指向obj2,不会立即执行,需要手动执行方法
        obj1.getName.bind(obj2)() // ()手动执行生成一个全新的函数
        obj1.getName.bind(obj2, 'aaa', 'bbb', 'ccc')() // 可以传无限多个参数
      
      call()
      (1)改变this指向obj2,会立即执行; 
      (2)可以传多个参数
      	obj1.getName.call(obj2) // obj2,改变this指向obj2,会立即执行 
      	obj1.getName.call(obj2, 'aaa', 'bbb', 'ccc') // 可以传无限多个参数
      
      apply()
      (1)改变this指向obj2,会立即执行 
      (2)两个参数(一个对象+一个数组)
          obj1.getName.apply(obj2) // obj2,改变this指向obj2,会立即执行 
          obj1.getName.apply(obj2, ['aaa', 'bbb', 'ccc']) // 只有两个参数,一个对象+一个数组
      
posted @ 2021-05-28 09:27  lixingqian  阅读(70)  评论(0)    收藏  举报