c语言sscanf函数的用法是什么
287
2022-08-28
JavaScript 中的六种继承方式
直接进入主题:
继承的操作需要有一个父类,这里使用构造函数外加原型来创建一个:
// superfunction Person(name){ this.name = name;}Person.prototype.job = 'frontend';Person.prototype.sayHello = function() { console.log('Hello '+this.name);}var person = new Person('jia ming');person.sayHello(); // Hello jia ming
原型链继承
// 原型链继承function Child() { this.name = 'child';}Child.prototype = new Person();var child = new Child();console.log(child.job); // frontend// instanceof 判断元素是否在另一个元素的原型链上// child是Person类的实例console.log(child instanceof Person); // true
关键点:子类原型等于父类的实例Child.prototype = new Person()
原型链的详细讲解自己之前有一篇文章说到深入理解原型对象和原型链
特点:
实例可继承的属性有:实例的构造函数的属性,父类构造函数的属性,父类原型上的属性。(新实例不会继承父类实例的属性)
注意事项:
新实例无法向父类构造函数传参继承单一所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改)
借用构造函数
// 借用构造函继承function Child() { Person.call(this, 'reng');}var child = new Child();console.log(child.name); // rengconsole.log(child instanceof Person); // falsechild.sayHello(); // 报错,继承不了父类原型上的东西
关键点:用call或apply将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))Person.call(this, 'reng')
针对call, apply, bind的使用,之前有篇文章谈谈JavaScript中的call、apply和bind提到。
特点:
只继承了父类构造函数的属性,没有继承父类原型的属性解决了原型链继承的注意事项(缺点)1,2,3可以继承多个构造函数的属性(call可以多个)在子实例中可以向父实例传参
注意事项:
只能继承父类构造函数的属性无法实现构造函数的复用。(每次用每次都要重新调用)每个新实例都有构造函数的副本,臃肿
组合继承
组合继承是原型链继承和借用构造函数继承的组合。
// 组合继承function Child(name) { Person.call(this, name);}Child.prototype = new Person();var child = new Child('jia');child.sayHello(); // Hello jiaconsole.log(child instanceof Person); // true
关键点:结合了两种模式的优点--向父类传参(call)和复用(prototype)
特点:
可以继承父类原型上的属性,可以传参,可复用每个新实例引入的构造函数属性是私有的
注意事项:
调用了两次父类的构造函数(耗内存)子类的构造函数会代替原型上的那个父类构造函数(call相当于拿到了父类构造函数的副本)
原型式继承
// 先封装一个函数容器,用来承载继承的原型和输出对象function object(obj) { function F() {} F.prototype = obj; return new F();}var super0 = new Person();var super1 = object(super0);console.log(super1 instanceof Person); // trueconsole.log(super1.job); // frontend
关键点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了可以随意增添属性的实例或对象。Object.create()就是这个原理。
特点:
类似于复制一个对象,用函数来包装
注意事项:
所有的实例都会继承原型上的属性无法实现复用。(新实例属性都是后面添加的)
**Object.create()方法规范了原型式继承。**这个方法接收两个参数,一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
// 传一个参数的时候var anotherPerson = Object.create(new Person());console.log(anotherPerson.job); // frontendconsole.log(anotherPerson instanceof Person); // true
// 传两个参数的时候var anotherPerson = Object.create(new Person(), { name: { value: 'come on' }});anotherPerson.sayHello(); // Hello come on
寄生式继承
关键点:就是给原型式继承外面套个壳子。
特点:
没有创建自定义类型,因为只是套了个壳子,返回对象,这个函数顺理成章就成了创建的新对象。
注意事项:
没用到原型,无法复用
寄生组合继承
它跟组合继承一样,都比较常用。
寄生:在函数内返回对象然后调用
组合:
函数的原型等于另一个实例在函数中用apply或call引入另一个构造函数,可传参
// 寄生function object(obj) { function F(){} F.prototype = obj; return new F();}// object是F实例的另一种表示方法var obj = object(Person.prototype);// obj实例(F实例)的原型继承了父类函数的原型// 上述更像是原型链继承,只不过只继承了原型属性// 组合function Sub() { this.age = 100; Person.call(this); // 这个继承了父类构造函数的属性} // 解决了组合式两次调用构造函数属性的特点// 重点Sub.prototype = obj;console.log(Sub.prototype.constructor); // Personobj.constructor = Sub; // 一定要修复实例console.log(Sub.prototype.constructor); // Subvar sub1 = new Sub();// Sub实例就继承了构造函数属性,父类实例,object的函数属性console.log(sub1.job); // frontendconsole.log(sub1 instanceof Person); // true
重点:修复了组合继承的问题
在上面的问题中,你可能发现了这么一个注释obj.constructor = Sub; // 一定要修复实例。为什么要修正子类的构造函数的指向呢?
因为在不修正这个指向的时候,在获取构造函数返回的时候,在调用同名属性或方法取值上可能造成混乱。比如下面:
function Car() { }Car.prototype.orderOneLikeThis = function() { // Clone producing function return new this.constructor();}Car.prototype.advertise = function () { console.log("I am a generic car.");}function BMW() { }BMW.prototype = Object.create(Car.prototype);BMW.prototype.constructor = BMW; // Resetting the constructor propertyBMW.prototype.advertise = function () { console.log("I am BMW with lots of uber features.");}var x5 = new BMW();var myNewToy = x5.orderOneLikeThis();myNewToy.advertise(); // => "I am BMW ..." if `BMW.prototype.constructor = BMW;` is not // commented; "I am a generic car." otherwise.
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~