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写的组合继承差不多。

原文地址:https://www.cnblogs.com/luguiqing/p/7684800.html