构造函数创建对象
function Person() {}var person = new Person();person.name = 'Kevin';console.log(person.name) // Kevin
prototype
每个函数都有一个 prototype 属性, 其实 函数的 prototype属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型。
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个就是我们说的原型。每个对象都会从原型继承属性。
proto
每一个JavaScript对象(除了null)都具有的一个属性,叫做 **proto**这个属性会指向该对象的原型。
constructor
每个原型都有一个constructor属性指向关联的构造函数。
实例与原型
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查找不到,就出找原型的原型,一直找到最顶层为止。
原型的原型
原型对象就是通过 Ojbect构造函数生成的,结合之前所讲,实例的proto指向构造函数的prototype。
原型链
补充
constructor
function Person() {}var person = new Person();console.log(person.constructor === Person); // true
当获取 person.constructor时,其实person中没有 constructor属性,当不能读取到constructor属性时,会从person的原型也就是 Person.prototype中读取,正好原型中有该属性。
proto
绝大部分浏览器都支持这个非标准的方法访问原型,然而它并存在于Person.prototype中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。
真的是继承吗?
继承意味着复制操作,然而JavaScript默认并不会复制对象的属性,相反,JavaScript只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。
继承实现:探究JS常见的6种继承方式
继承概念的探究
继承可以使得子类别具有父类的各种方法和属性, 也可以重写或者覆盖某些属性和方法,使其获得父类不同的方法。
JS实现继承的几种方式
第一种:原型链继承
每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,实例则包含一个原型对象的指针。
function Parent1() {this.name = 'parent1';this.play = [1, 2, 3]}function Child1() {this.type = 'child2';}Child1.prototype = new Parent1();console.log(new Child1());
第二种:构造函数继承(借助call)
function Parent1(){this.name = 'parent1';}Parent1.prototype.getName = function () {return this.name;}function Child1(){Parent1.call(this);this.type = 'child1'}let child = new Child1();console.log(child); // 没问题console.log(child.getName()); // 会报错
第三种:组合继承(原型与借助call)
function Parent3 () {this.name = 'parent3';this.play = [1, 2, 3];}Parent3.prototype.getName = function () {return this.name;}function Child3() {// 第二次调用 Parent3()Parent3.call(this);this.type = 'child3';}// 第一次调用 Parent3()Child3.prototype = new Parent3();// 手动挂上构造器,指向自己的构造函数Child3.prototype.constructor = Child3;var s3 = new Child3();var s4 = new Child3();s3.play.push(4);console.log(s3.play, s4.play); // 不互相影响console.log(s3.getName()); // 正常输出'parent3'console.log(s4.getName()); // 正常输出'parent3'
第四种:原型式继承
Object.create方法。参数一 作为新对象原型的对象, 为新对象定义额外属性的对象(可选)
多个实例的引用类型属性指向相同的内存,存在篡改的可能。
寄生式继承
let parent5 = {name: "parent5",friends: ["p1", "p2", "p3"],getName: function() {return this.name;}};function clone(original) {let clone = Object.create(original);clone.getFriends = function() {return this.friends;};return clone;}let person5 = clone(parent5);console.log(person5.getName());console.log(person5.getFriends());
寄生组合式继承
function clone (parent, child) {// 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程child.prototype = Object.create(parent.prototype);child.prototype.constructor = child;}function Parent6() {this.name = 'parent6';this.play = [1, 2, 3];}Parent6.prototype.getName = function () {return this.name;}function Child6() {Parent6.call(this);this.friends = 'child5';}clone(Parent6, Child6);Child6.prototype.getFriends = function () {return this.friends;}let person6 = new Child6();console.log(person6);console.log(person6.getName());console.log(person6.getFriends());
ES6的extends关键字实现逻辑
总结

