//对象的继承,这里采用构造函数继承+类式继承 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写的组合继承差不多。