JS 继承
来源:互联网 发布:js格式化日期函数 编辑:程序博客网 时间:2024/06/05 05:54
最近在阅读红宝书,刚好重新过来一遍继承,拿来和大家分享下,继承是JS核心之一,面试必问。
在继承之前大家需要了解的就是js创建对象,常见的创建对象方式有工厂模式,构造模式,原型模式。
**理解原型对象**
1.只要创建了一个函数,就会为该函数创建一个prototype属性,指向函数的原型对象。
2.原型对象会自动获得一个constructor属性,指向所在的构造函数。
3.每个对象实例都包含一个内部属性,该属性指向原型对象
4.通过构造函数,还可以继续为原型对象添加其他属性和方法。
5.当给对象实例添加一个属性时,这个属性会屏蔽原型对象中保存的同名属性,
即添加这个属性只会阻止我们访问原型中的属性,而不会修改那个属性
最主要的创建对象的方法
组合使用构造函数模式和原型模式
创建自定义类型最常见的方式,定义引用类型的一种默认模式。
思想:
构造函数模式:用于定义实例属性
原型模式:用于定义方法和共享的属性
每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。支持向构造函数传递参数。
function Person(name,age){ this.name = name; this.age = age; this.friends = ["小红","小明"];}Person.prototype = { constructor : Person, getAge : function(){ console.log(this.age); }}var zhangsan = new Person("zhangsan",23);var lisi = new Person("lisi",30);zhangsan.friends.push("小三");console.log(zhangsan.friends); //["小红","小明","小三"]console.log(lisi.friends); //["小红","小明"]console.log(zhangsan.friends === lisi.friends); //falseconsole.log(zhangsan.getAge === lisi.getAge); //true
有了以上这些知识我们再来看继承
由于函数没有签名,在ECMAScript中无法实现接口继承,只支持实现继承,而实现继承主要是依靠原型链来实现。
继承:
原型链 借用构造函数 组合继承 原型式继承 寄生式继承 寄生组合式继承
JavaScript主要通过原型链实现继承。使用最多的是组合继承。
原型链:
通过将一个类型的实例赋值给另一个构造函数的原型实现。(问题对象实例共享所有继承的属性和方法,不适宜单独使用)
借用构造函数:
在子类型构造函数的内部调用超类型构造函数。(每个实例都具有自己的属性)
组合继承:
使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性。
原型式继承:
可以不必预先定义构造函数的情况下继承(执行对给定对象的浅复制,复制得到的副本还可以进一步改造)
寄生式继承:
与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强对象,返回对象。(为了解决组合继承由于多次调用超类构造函数而导致低效率问题,可将这个模式与组合继承一起使用。)
寄生组合式继承:
集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。
原型链
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数想指针(constructor),而实例对象都包含一个指向原型对象的内部指针(proto)。如果让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针(proto),另一个原型也包含着一个指向另一个构造函数的指针(constructor)。假如另一个原型又是另一个类型的实例……这就构成了实例与原型的链条。
function animal(){ this.type = "animal"; } animal.prototype.getType = function(){ return this.type; } function dog(){ this.name = "dog"; } dog.prototype = new animal(); dog.prototype.getName = function(){ return this.name; } var xiaohuang = new dog();//原型链关系 xiaohuang.__proto__ === dog.prototype dog.prototype.__proto__ === animal.prototype animal.prototype.__proto__ === Object.prototype Object.prototype.__proto__ === null
缺点:
包含引用类型值的原型。
在创建子类型的实例时,不能向超类型的构造函数中传递参数。(没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数)
借用构造函数
优点:
解决原型中包含引用类型值带来的问题。
可以在子类型构造函数中向超类型构造函数传递参数。
思想:
在子类构造函数内部调用超类构造函数。
通过apply()和call()方法可以在新建的对象上执行构造函数。
function Animal(){ this.colors = ["red","blue"];}function Dog(){ //继承Animal Animal.call(this);}var xiaohuang = new Dog();xiaohuang.colors.push("yellow");console.log(xiaohuang.colors): // ["red","blue","yellow"]var xiaohei = new Dog();xiaohei .colors.push("black");console.log(xiaohei .colors); // ["red","blue","black"]//Dog的每个实例都会有自己的colors属性副本//传递参数//优点:在子类构造函数中向父类构造函数传递参数(相比于原型链的优点)function Animal(name){ this.name = name;}function Dog(){ //继承Animal,同时还传递了参数 Animal.call(this,"xiaohuang"); this.age = 10; //实例属性}var xiaohuang = new Dog();console.log(xiaohuang .name); //"xiaohuang”console.log(xiaohuang .age); //10
缺点:
构造函数模式存在的问题—方法都在构造函数中定义,函数复用无从谈起。
在超类型的原型中定义的方法,在子类型是不可见的。
结果所有的类型都只能使用构造函数模式
借用构造函数很少单独使用
组合继承
组合继承/伪经典继承–最常用的继承模式
优点:
将原型链和借用构造函数组合到一起,发挥两者之长。
思想:
使用原型链实现对原型属性和方法的继承,(实现了函数的复用)
通过借用构造函数实现对实例属性的继承 (保证每个实例都有自己的属性)
function Animal(name){ this.name = name; this.colors = ["red","blue"];}Animal.prototype.getName = function(){ console.log(this.name);}function Dog(name,age){ //继承属性 Animal.call(this,name); this.age = age;}Dog.prototype = new Animal();Dog.prototype.constructor = Dog;Dog.prototype.getAge = function(){ console.log(this.age);}var xiaohuang = new Dog("xiaohuang",10);xiaohuang.colors.push("yellow");console.log(xiaohuang.colors); //"red","blue","yellow"xiaohuang.getAge(); //10xiaohuang.getName(); //"xiaohuang"var xiaohei = new dog("xioahei",3);console.log(xiaohei.colors); //"red","blue"xiaohei.getAge(); //3xiaohei.getName(); //"xioahei"
解释:
animal的构造函数定义了name和colors两个属性
dog的原型定义了getName()方法。
dog构造函数在调用animal构造函数时传入了name参数,
又定义了自己的属性age
将animal实例的赋值给dog的原型,又在新原型上添加方法getAge(),两个不同的实例可以分别拥有自己的属性name,colors,又可以使用相同的方法getName()
instanceof,isPrototypeOf()也能够识别基于组合继承创建的对象。
缺点:
无论什么情况下,都会调用两次超类型构造函数。
(1.创建子类原型的时候 2.子类型构造函数内部) 看 寄生组合式继承
有两组 name和colors属性,dog的原型中有,dog的实例中有,实例中会屏蔽原型的的两个同名属性。
原型式继承
思想:
没有严格意义上的构造函数。
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
必须要有一个对象可以作为另一个对象的基础。
function object(o){ function F(){}; F.prototype = o; return new F();};//object对传入的对象进行了一次浅复制var xiaoming = { name : "xiaoming", friends : ["f1","f2"]};var xiaohong = object(xiaoming);xiaohong.__proto__ === xiaoming; //truexiaohong.name = "xiaohong";xiaohong.friends.push("f3");var xiaohua = "xiaohua";xiaohua.friends.push("f4");console.log(xiaoming.friends);//["f1","f2","f3","f4"]
缺点 :
和原型模式一样,包含引用类型值的属性始终都会共享相应的值
寄生式继承
思路:
与寄生构造函数和工厂模式类似,
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象。
function createAnother(o){ var clone = object(o); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象}var person = { name : "fangfang", friends : ["f1","f2"]};var anotherperson = createAnother(person);anotherperson.sayhi(); //"hi"//anotherperson具有person的所有属性和方法,还有自己的sayhi方法
缺点:
适用场景:在主要考虑对象,而不是自定义类型和构造函数的情况
寄生组合式继承
最理想的继承方式
优点:
不必为了指定子类型的原型而调用父类型的构造函数(解决了组合继承至少两次调用超类构造函数)
(只调用了一次animal构造函数,避免了dog.prototype上面创建多余的属性)
(还能正常使用instanceof和isPrototypeOf())
思想:
通过借用构造函数来继承属性,
通过原型链的混成形式来继承方法
不必为了指定子类型的原型而调用父类型的构造函数,
我们所需的只是父类原型的一个副本。
就是使用寄生式继承来继承父类的原型,然后将结果指定给子类型的原型
function inheritPrototype(Dog,Animal){ var prototype = Object(Animal.prototype); //创建父类原型的一个副本 prototype.constructor = Dog; //副本添加constructor属性 Dog.prototype = prototype; //把副本赋值给子类原型}function Animal(name){ this.name = name; this.colors = ["red","blue"];}Animal.prototype.getName = function(){ console.log(this.name);}function Dog(name,age){ Animal.call(this,name); this.age = age;}inheritPrototype(Dog,Animal);Dog.prototype.getAge = function(){ console.log(this.age);}//此时 Animal.prototype === Dog.prototype
https://github.com/zgfang1993/blog/issues
- JS继承--组合继承
- JS继承-类继承
- Js继承。
- js继承
- js继承
- js 继承
- js继承
- JS 继承
- JS 继承
- js继承
- js继承
- JS继承
- JS继承
- js继承
- JS继承
- JS继承
- js继承
- JS继承
- 如何在win10下安装IMSL6.0
- Linux中hadoop安装及配置详解
- fastboot烧录bootimage和aboot
- VS2015 当前不会命中断点问题
- mysql约束和修改数据表
- JS 继承
- Windows socket基础
- BeanFactory和ApplicationContext简易阐述
- apk文件重新签名
- 利用Javascript框架——D3.js制作力导向关系图普
- SpringMVC的运行流程
- eclipse使用及优化
- 浏览器打开微信公众号h5页面,增加cookie绕过微信授权登录
- iOS UITableView多选操作