-
何谓对象?
对象是具有属性和方法的一个变量。
-
何谓原型?
我们创建了一个函数: function A(){}, A本质上也是一个对象。 此时会隐含的创建一个对象b,A的prototype属性会指向对象b,b就称为function A的原型对象,对象b的constructor属性同时又指向对象A, 即A.prototype === b, b.constructor === A。
-
原型对象(prototype)存在的意义?
prototype用于与其他对象共享属性。
如何理解这句话?
function A(){} A.prototype.print = function(name){ console.log(name) } let a1 = new A(); let a2 = new A(); a1.print('wang'); // wang a2.print('li'); // li 以上代码中,a1, a2均为A的实例对象,a1, a2共享在构造函数A的原型对象上定义的print方法。 那 a1 和 a2 是如何找到print方法呢? 由于我们并未在 a1 和 a2 对象上定义print方法,所以当在a1上调用print方法时,会隐性的去原型对象上去寻找print方法,即
执行 a1.print 时,就是在执行 a1.proto.print,即
console.log(a1.print === a1.__proto__.print) // true // 我们还可以得出如下结论 console.log(a1.__proto__.print === A.prototype.print) // true 看到这里我们可以知道,A.prototype类似于Java中的父类,A.prototype.print类似于父类中定义的方法,可以用于不同对象间共享同样的方法和属性。
-
原型链又是什么鬼?
上文我们知道,当一个对象访问一个方法或属性时,如果在当前对象无法找到,会自动通过 __proto__属性访问原型对象去寻找,即a1.print === a1.proto.print。假如我们现在要访问 a1的toString方法,我们看下会是什么结果
console(a1.toString()) // [Object Object]由此可见,a1是可以访问toString方法。但是a1及 a1的原型上都没有定义toString方法,那这个方法是哪来的呢?先抛出一个结论,toString方法定义在Obhect.prototype上。
// a1.__proto__ 指向的是A的原型对象,即A.protptype a1.toString === a1.__proto__.toString // true // 由于a1.__proto__(即A.prototype)上也并未定义toString,故继续向上寻找 // A.prototype本身也是一个对象,故其自身也会存在__proto__属性,通过__proto__找到对应的原型对象 // A.prototype.__proto__ === Object.prototype, Object.prototype上定义了toString方法,故找到了toString a1.__proto__.toString === a.__proto__.__proto__.toString // true // 即 a1.toString === a1.__proto__.toString === a.__proto__.__proto__.toString由此可见,原型链是一条可以向上级原型对象查找方法和属性的工具,通过__proto__的链式调用实现。
-
构造函数和原型对象的关系?
以 function A(){} 为例,A 上有prototype属性,其指向A的原型;A的原型上有constructor属性,其指向A,即A.prototype.constructor === A
-
原型对象之于继承的作用?
function Person(name){ this.name = name; this.eat = function(){ console.log(this.name, ' is eating'); } } Person.prototype.say = function(){ console.log(this.name, ' is saying'); } function Student(name, sex){ this.name = name; this.sex = sex; this.learning = function(){ console.log(this.name, ' is learning'); } } Student.prototype = new Person(); // Student的原型指向A的实例,即Student.prototype.__proto__ = A.prototype // Student.prototype本身是没有构造函数的,当我们调用Student.prototype.constructor时会去A实例的原型寻找。 // 即Student.prototype.constructor === Student.prototype.__proto__.constructor; // 此时Student原型的构造函数指向已经发生了改变,指向了构造函数A,我们需要手动修改回来。(也可以说Student.prototype本身没有构造函数,我们需要手动添加构造函数) Student.prototype.constructor = Student; // 添加Student自己的方法 Student.prototype.write = function(){ console.log(this.name, ' is running') }由此可见,原型对象可以用于实现JavaScript的继承操作。