美文网首页
js面向对象

js面向对象

作者: Remeo | 来源:发表于2016-10-31 19:04 被阅读0次

    定义一个类

    使用构造函数 + 原型 的方法定义一个类。 eg:

    // 定义一个名为Person的构造函数  
    function Person(name, age, sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
      }
    //原型
      Person.prototype = {
        constructor: Person //--> 就是上面定义的构造函数
        sayName : function(){
          console.log('My name id ', this.name);
        }
      }
    // 实例化
    var person1 = new Person('Tim', 15, 'male');
    var person2 = new Person('Remoo', 20, 'famale');
    person1.sayName(); // 输出Tim
    person2.sayName(); // 输出Remeoo
    

    类的继承

    我们通过原型链实现继承,原型链是将子类的实例赋值给父类的构造函数的原型。eg:

      //父类
      function Person(){
        this.name = 'Tinna';
      }
      Person.prototype = {
        constructor: Person,
        setName: function(name){
          this.name = name;
        },
        getName: function(){
          return this.name;
        }
      }
      //子类
      function Man(){
        this.age = 19;
      }
      Man.prototype = {
        constructor: Man,
        setAge: function(age){
          this.age = age;
        },
        getAge: function(){
          return this.age;
        }
      }
      //子类继承父类
      Person.prototype = new Man();
      //给子类添加新的方法
      Man.prototype.sayName = function(){
       console.log('my name is ',this.name);
      }
      // !子类如果想使用父类的方法,需要重写父类的方法
      // 重写父类的方法
      Man.prototype.setName = function(name){
        this.name = name;
      }
    Man.prototype.getName = function(){
      return this.name;
    }
      // 实例化
      var man1 = new Man();
      man1.setName('linna'); 
      man1.getName(); //输出Sam
      man1.setAge(23)
      nam1.getAge(); //输出23
    

    闭包

    如果一个函数可以访问两一个函数作用域中的变量,那么前者,就是闭包。因为,子函数才可以访问局部变量,那么,闭包也可以是 *** 定义在一个函数内部的函数***。
    由于JavaScript可以返回函数,那么,创建闭包的最好方式就是在一个函数内部创建另一个函数,在父函数中创建子函数,那么子函数就可以访问父函数的作用域中的变量。
    子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

    function superFun(){
      var subFuncs = new Array(); 
      for (var i = 0; i < 10; i++) { 
        subFuncs[i] = function() { return i; };
      }
      return subFuncs ;
    }
    var result = superFun(); //此时result是一个包含10个函数的数组
    result[0](); //输出结果为:10
    result[1](); //输出结果为:10
    result[2](); //输出结果为:10
    result[3](); //输出结果为:10
    result[5](); //输出结果为:10
    .
    .
    result[9](); //输出结果为:10
    

    为什么我们得到的i其实一直都是10呢?因为,当我们返回subFuncs后,superFunc中的i=10,所以输出的结果都为10.

    code.png
    result.png
    这就是闭包的缺陷:*** 子函数对多函数作用域中变量的引用,是在父函数运行结束之后的变量 ***
    !如何解决这个问题?
      原理: 缺陷的本质是子函数对父函数作用域中变量的引用是在父函数运行结束之后的变量状态。
      解决方式: 子函数对父函数作用域中变量的引用,使用父函数运行时状态的变量。所以,在子函数表达式上加上自执行就可以了。
      function superFunc() {
       var subFuncs = new Array();
       for (var i = 0; i < 10; i++) {
         subFuncs[i] = function(num) { 
            return function() { return num; }; 
          }(i); 
        } 
        return subFuncs;
      }
     
    

    闭包的作用

    闭包的左右除了上面说的可以读取函数内部的变量,另一个就是可以让这些变量始终保持在内存和中。eg:

    function fun1(){
        var n=999;
        nAdd=function(){return n+=1}
        function fun2(){
          console.log(n);
        }
        return fun2;
      }
      var result=fun1();
      result(); // 999
      nAdd();
      result(); // 1000
    

    在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
    为什么会这样呢?原因在于fun1函数是fun2的父函数,而fun2倍赋值给一个全局变量,这导致fun2始终在内存中,而fun2依赖于fun1,因此, fun1也始终在内存中,不会在调用结束之后就被垃圾回收机制回收。
    还有一个就是 nAdd=function(){return n+=1} 这一行,首先nAdd前没有var关键字,所以aAdd是全局变量,其次,nAdd的值是一个匿名函数,而匿名函数本身也是一个闭包,所以nAdd相当于一个setter,可以在函数外部对函数内部的局部变量进行操作。

    相关文章

      网友评论

          本文标题:js面向对象

          本文链接:https://www.haomeiwen.com/subject/fwlputtx.html