常见的面向对象的面试题(附答案)
1、JavaScript是怎么样实现继承的?请举例说明。
JavaScript通过 prototype属性实现继承,继承的属性方法是共享的,例如Chid子类继承 Parent父类, Child. prototype= new Parento()。
在子类构造函数内执行父类构造函数,并传递子类作用域和参数,从而实现对父类构造函数的继承,例如 function Child(){ Parent. apply(this, arguments)}。
2、简述如何通过new构建对象?
通过new操作符构建对象的步骤如下。
(1)创建一个新的对象,这个对象的类型是 object.
(2)将this变量指向该对象。
(3)将对象的原型指向该构造函数的原型。
(4)执行构造函数,通过this对象,为实例化对象添加自身属性方法。
(5)将this引用的新创建的对象返回。
代码如下。
function demo(Base) {
var obj ={};
//this =obj
obj. __proto__= Base. prototype;
School.call(obj)
return obj
}
3、谈谈 JavaScript中继承的实现方法。
子类的实例可以共享父类的方法;子类可以覆盖从父类扩展来的方法。
4、说说构造函数的特点。
构造函数的函数名首字母大写,构造函数类似于一个模板,可以使用new关键字执行构造函数,创建实例化对象。
5、小贤是一条可爱的小狗(Dog),它的叫声很好听(wow),每次看到主人的时候就会乖乖叫一声(yelp)b根据这段描述,请用程序实现。
代码如下。
function Dog(){}
Dog.prototype.wow=function(){
console.log('wow')
}
Dog.prototype.yelp=function(){
this.wow();
}
var xx=new Dog()
xx.yelp();//wow
6、小芒( Mad Dog)和小贤一样,原来也是一条可爱的小狗,可是突然有一天疯了,一看到人就会每隔0.5s叫一声(wow),且不停叫唤(yelp)b根据描述,请用代码来实现。
代码如下
function MadDog(){}
MadDog.prototype= new Dog();
MadDog.prototype.yelp=function(){
var me= this:
setInterval(function(){
me. wow()
},500)
var madDog= new MadDog();
madDog.yelp()
7、列出 JavaScript常用继承方式并说明其优缺点。
常用继承方式及其优缺点如下。
(1)构造函数式继承是指在子类的作用域上,执行父类的构造函数,并传递参数构造函数式继承虽然解决了对父类构造函数的复用问题,但没有更改原型。
(2)类(原型链)式继承是指将父类的实例化对象添加给子类的原型。执行构造函数是没有意义的,因为我们只想继承原型链上的属性和方法,当执行父类的构造函数时,没有添加参数,所以执行构造函数的结果是不正确的。父类构造函数中的数据,没有直接添加在子类的实例化对象上,而是添加在原型上。子类型实例化时无法复用父类的构造函数。
(3)组合式继承是比较常用的一种继承方法,其背后的思路是,使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。这样,既在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。但其问题是导致父类的构造函数执行了两次:一次是在构造函数式继承中执行的;另一次是在类式继承中执行的。
使用上述继承要注意以下几点
(1)在构造函数式继承中,属性的赋值一定在继承的后面执行,否则会产生覆盖问题。
(2)在类式继承中,原型上属性或者方法的赋值一定在继承后面,否则会产生覆盖问题。
(3)在类式继承中,在原型上添加属性或者方法一定使用点语法的形式,不可以给对象赋值。
(4)在类式继承中,要为原型添加属性方法对象,可以在继承后面通过库的 extend方法(或 ECMAScript6提供了 assign方法)实现。
8、用 JavaScript写一个实现寄生式继承的方法。
以下代码实现了寄生式继承方法 inherit。
var inherit =(function(){
//定义寄生类
function F(){};
return function(sub, sup) {
//寄生类的原型指向父类
E.prototype= sup.prototype;
//继承父类的原型
sub.prototype=new F ();
//更正构造函数
sub.prototype.constructor =sub;
//返回子类
return sub;
}
})()
//父类
function Star(names){
this.names = names
}
Star.prototype.getNames = function(){
return this.names
//子类
function Moviestar(names, age) {
//构造函数式继承
Star.apply(this, arguments)
this.age = age;
//寄生式继承
inherit(Moviestar, star);
MovieStar.prototype.getAge =function (){
return this.age;
}
console. log(new Moviestar( 'xiao bai', 20))
9、说出你熟知的 Javascript继承方式。
有以下几种继承方式
(1)构造函数式继承。
(2)类(原型链)式继承。
(3)组合式继承(混合使用构造函数式和类式)。
(4)寄生式继承。
(5)继承组合式继承(混合使用构造函数式和寄生式)。
(6)原子继承。
(7)多继承。
(8)静态继承。
(9)特性继承。
(10)构造函数拓展式继承。
(11)工厂式继承
10、面向对象的特性有哪些?
有以下特性。
(1)抽象,就是忽略一个主题中与当前目标无关的那些方面,以便更充分地关注与当前目标相关的方面。
(2)封装,利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据存放在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口,使之与外部发生联系。
(3)继承,使用已存在的类的定义作为基础,建立新类的技术。新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
(4)多态,程序中定义的引用变量所指向的具体类型和通过该引用变量触发的方法调用在编程时并不确定,而在程序运行期间才能确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量触发的方法调用到底是哪个类中实现的方法,必须在程序运行期间才能决定。
11、面向对象编程的三大特点是什么?
封装、继承、多态。
(1)封装,即将描述同一个对象的属性和方法定义在一个对象中。
(2)继承,即父对象中的属性和方法被子对象使用。
(3)多态,即同一个对象在不同情况下呈现不同的形态(注意,在 JavaScript中无多态”的概念)。多态有以下两种形式。
重载,即同一方法名,根据传入的参数不同,而执行不同操作。
重写,即子对象在继承父对象的属性或方法后,重新定义一个新的属性或方法以覆盖从父对象中继承的属性或方法。
12、面向对象开发的好处是什么?
在代码开发中,如果一些功能可能在某些网页中是重复出现的,那么完全可以把这部分功能封装成一个对象,然后在多个地方进行调用,而不是每次遇到它的时候都重新书写一次,以此来实现对数据或者方法的复用。
13、方法重载( Overload)与方法重写( Override)的区别是什么?
方法重载属于编译时的多态,根据传递的参数不同,执行不同的业务逻辑,得到不同的结果。方法重写属于运行时的多态,子类原型指向父类原型,子类重写父类的方法,在调用子类方法的时候使用子类的方法,从而重写父类中定义的方法。
14、如何判断某个对象是否包含指定成员?
通过以下方式判断。
(1)使用 obj. hasOwnProperty(" ")。
如果找到,返回true;否则,返回 false。
(2)使用“属性名”in对象如果找到,返回true;否则,返回 false。
(3)直接使用ob属性名作为判断的条件,如下所示。
if (obj. demo === undefined)
若不包含,条件值为true;若包含,条件值为 false。
15、this通常指向谁?
在运行时,this关键字指向正在调用该方法的对象。
16、如何判断属性是自有属性还是原型属性?
方法如下
(1)要判断自有属性,使用 obj. hasOwn Property(“属性名”)
(2)要判断原型属性,使用“属性名” in obj&&!obj.hasOwn Property(“属性名”)的形式。
17、实现对象的继承有哪几种方式?
有以下几种方式
(1)修改对象的 _proto _ ,如下所示
Object.set Prototypeof(子对象,父对象)
(2)修改构造函数的原型对象,如下所示。
构造函数.prototype=对象
(3)使用原子继承方法 Object.create(父对象[,{属性列表}]),如下所示。
var demo = Object.create(obj)