zoukankan      html  css  js  c++  java
  • js 对象的封装,继承,多态的理解

    //对象的继承,这里采用构造函数继承+类式继承
    function Person(name,sex,age){
    	this.name = name;
    	this.sex = sex;
    	this.age = age;
    }
    
    Person.prototype.getName = function(){
    	return this.name;
    }
    
    function Student(school,name,sex,age){
    	Person.call(this,name,sex,age);//构造函数继承,保证实例之间不会互相影响
    	this.school = school;
    }
    
    Student.prototype = new Person();//类式继承,解决构造函数继承不能继承定义在外面的原型链的方法
    Student.prototype.constructor = Student;//不然student1.constructor = Person var student1 = new Student("西都小学1","1","男1",21); var student2 = new Student("西都小学2","2","男2",22); console.log(student1.getName());//1 student1.name = "修改"; console.log(student1.name);//修改 console.log(student2.name);//2 //多态就是构造函数根据传入的变量不同,对同一方法,有不同的返回结果 //比如 function Math(){ function zero(){ return 10; } function one(num){ return 10+num; } this.add = function(){ switch(arguments.length){ case 0: return zero(); break; case 1: return one(arguments[0]); break; } } } var math1 = new Math(); console.log(math1.add());//10 console.log(math1.add(10));//20 //封装就是有些私有的属性和方法,用户只能通过公有方法去访问这些私有属性 function Company(name){ var personNum = 0; this.name = name; this.getNum = function(){ return personNum; } this.addNum = function(){ personNum++; } } var company1 = new Company("保时捷"); var company2 = new Company("宝马"); console.log(company1.getNum());//0 company1.addNum(); console.log(company1.getNum());//1 console.log(company2.getNum());//0 console.log(company1.personNum);//undefined

    当然对象的继承不仅仅只有这种,但我觉得这是比较好的一种选择,ES6的class语法让我们更容易去实现面向对象编程。

    // 推荐 用 Object.create实现类式继承(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create

    //对构造函数+类式继承的完善,寄生组合继承

     1 function Person(name, sex, age) {
     2     this.name = name;
     3     this.sex = sex;
     4     this.age = age;
     5 }
     6 
     7 Person.prototype.getName = function() {
     8     return this.name;
     9 }
    10 
    11 function Student(school, name, sex, age) {
    12     Person.call(this, name, sex, age); //构造函数继承,保证实例之间不会互相影响
    13     this.school = school;
    14 }
    15 
    16 (function() {
    17     // 创建一个没有实例方法的类
    18     var Super = function() {};
    19     Super.prototype = Person.prototype;
    20     //将实例作为子类的原型
    21     Student.prototype = new Super();//通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免了上面组合继承的缺点
    Student.prototype.constructor = Student
    22 })();

     ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this

    如何理解这个的意思呢?!

     1 class a{
     2       constructor(y,z){
     3         this.y =y;
     4         this.z =z;
     5         console.log("a");
     6       }
     7       render(){
     8         console.log(this.y)
     9       }
    10  }
    11     
    12  class b extends a{
    13       constructor(m,n,x,y){
    14         super(x,y);//在super()前面定义this.n = n;是会报错的,这就是上面的意思,this还没有创建
    15         console.log("b");
    16         this.n=n;
    17         this.m=m;
    18      }
    19       
    20       render(){
    21         console.log(this.m);
    22       }
    23  }

    我们将其转为es5的代码

     1 "use strict";
     2 
     3 var _createClass = function() {
     4     function defineProperties(target, props) {
     5         for (var i = 0; i < props.length; i++) {
     6             var descriptor = props[i];
     7             descriptor.enumerable = descriptor.enumerable || false;
     8             descriptor.configurable = true;
     9             if ("value" in descriptor) descriptor.writable = true;
    10             Object.defineProperty(target, descriptor.key, descriptor);
    11         }
    12     }
    13     return function(Constructor, protoProps, staticProps) {
    14         if (protoProps) defineProperties(Constructor.prototype, protoProps);
    15         if (staticProps) defineProperties(Constructor, staticProps);
    16         return Constructor;
    17     };
    18 }();
    19 
    20 function _possibleConstructorReturn(self, call) {
    21     if (!self) {
    22         throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    23     }
    24     return call && (typeof call === "object" || typeof call === "function") ? call : self;
    25 }
    26 
    27 function _inherits(subClass, superClass) {
    28     if (typeof superClass !== "function" && superClass !== null) {
    29         throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    30     }
    31     subClass.prototype = Object.create(superClass && superClass.prototype, {
    32         constructor: {
    33             value: subClass,
    34             enumerable: false,
    35             writable: true,
    36             configurable: true
    37         }
    38     });
    39     if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
    40 }
    41 
    42 function _classCallCheck(instance, Constructor) {
    43     if (!(instance instanceof Constructor)) {
    44         throw new TypeError("Cannot call a class as a function");
    45     }
    46 }
    47 
    48 var a = function() {
    49     function a(y, z) {
    50         _classCallCheck(this, a);
    51 
    52         this.y = y;
    53         this.z = z;
    54         console.log("aaaa");
    55     }
    56 
    57     _createClass(a, [{
    58         key: "render",
    59         value: function render() {
    60             console.log(this.y);
    61         }
    62     }]);
    63 
    64     return a;
    65 }();
    66 
    67 var b = function(_a) {
    68     _inherits(b, _a);
    69 
    70     function b(m, n, x, y) {
    71         _classCallCheck(this, b);
    72      
           //this.n = n;
           //this.m = m;//对于es5,我们在这里写也是没问题的,但如果是在这里写,就是先创建了子类的实例,然后再去调用父类的,这就是上面那句话本人的理解 
    73 var _this = _possibleConstructorReturn(this, (b.__proto__ || Object.getPrototypeOf(b)).call(this, x, y)); 74 75 console.log("bbb"); 76 _this.n = n; 77 _this.m = m; 78 return _this; 79 } 80 81 _createClass(b, [{ 82 key: "render", 83 value: function render() { 84 console.log(this.m); 85 } 86 }]); 87 88 return b; 89 }(a);

    可以看到确实是想打印“aaa”,再打印“bbb”的,但是我们发现其继承方式与前面es5写的组合继承差不多。

  • 相关阅读:
    代码空间项目 -- InstantiationException的异常
    代码空间项目 -- 窗口移动
    代码空间项目 -- alert窗口自定义
    代码空间项目 -- 获取当前时间之前的某一天-Calender类的使用
    代码空间项目 -- cookie的基本使用
    Hibernate主要查询方式
    关于hibernate配置步骤
    线程创建后为什么要调用CloseHandle
    C++子类父类构造函数的关系
    socket API CSocket CAsyncSocket 用法及区别
  • 原文地址:https://www.cnblogs.com/luguiqing/p/7684800.html
Copyright © 2011-2022 走看看