【deep JS】从面试题出发(三)—— 深入理解面向对象

1,330 阅读3分钟

1、 请简述一下js原型链

原型链是Javascript实现类的底层原理,是一种继承机制。说到继承,这起源于JAVAC++的概念。上述两种语言的继承,本质上是一种拷贝行为,将父类的方法拷贝给子类供其使用。

但是JS中,子类的.prototype对象,通过原型链与父类的.prototype对象形成一条查询管道,如果子类中没有,通过管道返回到父类中寻找,一直回溯到Object.prototype为止。

比起拷贝继承,这种原型链形式,更加节省内存。另外由于javasctipt的面向对象object oriented OO,实际上叫做object linked other object OLOO更为准确。

2、 在原型链上Object再往上是什么?

Object.prototype是原型链的终点了。

3、 __proto__prototype分别指什么?哪种情况下__proto__prototype的指向是同一个?

考察的问题:__proto__(getPrototypeOf)prototype的指向。通过例子来说明:

function Workshop(teacher){
   this.teacher = teacher;
}
Workshop.prototype.ask = function (question){
   console.log(this.teacher,question);
}

let deepJS = new Workshop("Kyle");
let reactJS = new Workshop("Suzy");

deepJS.ask("Is prototype a class?");
reactJS.ask("Isn't prototype ugly?");
  • 解析本段代码,需要了解原型链的布线是什么样的 子类对象通过__proto__指向父类的对象,红色箭头;函数通过prototype指向同级对象,绿色右箭头。本例子中:
deepJS.__proto__ == Workshop.prototype;

上面的原型链布线图非常的重要,请多看几遍好好理解

4、 new生成了一个对象的过程(核心return this)

  • new关键字生成对象分为:
  1. 生成一个的空白新对象
  2. this指向该空白对象,通过this为空白对象添加属性。
  3. 返回一个新对象出来。
var Car = function(loc){
   //this = {};
   this.loc = loc;
   //return this;
}
var car1 = new Car(1);

5、 new和Object.create的区别

newObject.create完成的相同功能是:创建一个新的空对象,链接到另一个对象。但new有构造函数而Object.create没有。下面使用实例论证:

function Car(loc){
   this.loc = loc;
}
Car.prototype.move = function(){
   this.loc++;
}
function Van(loc){
   Car.call(this,loc);
}
var Van.prototype = Object.create(Car.prototype);

let amy = new Van(1);
console.log(amy.constructor);

amy.constructor指向的不是Van,而是Car,因为Van.prototype没有通过newVan.constructor创建好连接,所以要向上回溯找到具有constructor函数Car.prototype

  • 要注意的思维陷阱:
  1. Car的constructor函数在Car里。不对,在Car.prototype里。
  2. Car.prototype天生就与Car有这Car.prototype.constructor = Car的链接关系。不对,Car.prototype只是默认开辟的一块存储空间,是new创建了这种指向关系。Object.protoype.constructor = object除外,这是顶层设计。

6、 js的this理解, 如何改变this的指向

参看我的视频

7、 js的继承?实现方法?

Js的继承说到底,是委托查找。经典的实现方法是原型类,变体可以使用委托设计模式,ES6中加了class语法糖,但是本质是别人已经把背后特别丑的原型类包了起来而已。个人习惯使用ES5的语法,虽然丑但调试起来比较方便,另外我觉得这比较符合JavaScript的DNA,ES6这个语法在我看来是一场粉饰太平的迎合。个人观点仅供参考。

  • 原型类
function Workshop(teacher){
   this.teacher = teacher;
}
Workshop.prototype.ask = function (question){
   console.log(`${this.teacher},ask: ${question}`);
}
//继承部分
function AnotherWork(teacher){
   Workshop.call(this,teacher);
}
AnotherWork.prototype = Object.create(Worksop.prototype);
//多态
AnotherWork.prototype.speak = function(question){
   this.ask(question.toUpperCase());
}
  • ES6语法糖
class Workshop{
    constructor(teacher) {
         this.teacher = teacher;
    }
    ask(question){
        console.log(`${this.teacher},ask: ${question}`);
    }
}
//继承部分
class AnotherWork extends Workshop{
    constructor(teacher){
        super(teacher);
    }
    speak(question){
        this.ask(question.toUpperCase());
    }
}
  • 委托类
var Workshop{
   setTeacher(teacher){
       this.teacher = teacher;
   },
   ask(question){
       console.log(`${this.teacher},ask: ${question}`);
   }
}
//将Workshop assign 给 AnotherWork
var AnotherWork = Object.assign(
    Object.create(Workshop),
    {
   speak(question){
   this.ask(question.toUpperCase());
  }
});
//应用
let deepJS = Object.create(AnotherWork);
deepJS.setTeacher("Kyle");
deepJS.speak("Hello oloo?");

委托类的效率和灵活性是要比继承类都好的,但是继承类的可读性更好,在项目维护的时候,可读性要高于效率。