乐趣区

js-的原型-原型链-原型链的继承

对象的方法

Object.assign()
对象可以简写,如果 key 和 value 相等则可以简写
let name = 'xm';
let age = 2;
let obj = {
    name,age,
    fn(){ // 可以省略函数关键字和冒号:console.log(22);
    }
}
对象新增的方法 Object.setPrototypeOf()

let o2 = {
    age: 22,
    name: 'mazz'
}
let o1 = {
    name: 'zz',
    __proto__: o2
    getO2Name(){return super.name}
}
// __proto__ 每一个对象上都有这个东西,如果自己家找不到 会通过这个链向上找
Object.setPrototypeOf(o1,o2); // 通过这个方法 把 o1 的链指向 o2
// super 在子对象中指向的是 __proto__对应的内容
// 等价于 o1.__proto__= o2;
console.log(o1.age); // 22
console.log(o1.getO2Name())

class

js 没有类的概念,js 的继承是通过 prototype 实现的,每个构造函数上都有一个 prototype 属性,指向他的原型对象,原型对象上的 constructor 指向了构造函数,构造函数实例化后有一个 proto 指向原型对象 原型对象的 constructor 指向构造函数 就实现了 继承

1. 原型链是怎么实现继承的?
2. 可以围绕构造函数说一下的?
3. 构造函数实例化后是怎么继承构造函数的属性
4. 怎么向原型对象上添加属性

function Person (){} // 声明一个函数 js 中 函数是对象 也是构造函数
console.log(Person.prototype); // Person 对象的原型
// 由此打印出来的结果 可以看出 Person 对象的原型上有 一个 constructor 属性, 它指向 Person 的构造函数 也就是 Person 本身 还有一个__proto__属性
 function Person(name) {this.name = name; // 私有的}
 Person.prototype.eating = function() {// 给对象的原型对象上添加一个 eating 的方法,new 出来的实例 都会共享此方法的
     console.log('eat food')
 }
 Person.prototype.age = 12;// 给对象的原型对象上 添加一个 age 属性
    var p1 = new Person("blob");
   var p2 = new Person("lisa");
console.log(p1.age,p2.age); // 12,12
console.log(p1.eating(),p2.eating()); // eat food eat food
![图片描述][1]
// 所以只要是 Person 的对象 他们都会共享原型对象上的方法和属性的
**WHY?? 这个实例 能够访问 原型对象上的方法及属性的 **
  // 其实 p1 的实例上有一个指针,这个指针指向 构造函数的原型对象(通俗点 也就是所属类的原型)此时原型对象中的方法及属性自然也就能访问到的 

总结下 构造函数 原型 和实例的关系:

  1. 每一个构造函数都有一个原型对象 (prototype) 原型对象上 拥有一个指向构造函数的指针(constructor)
  2. 实例上拥有一个指向原型对象的指针 即 proto

类 以前就是构造函数 分为私有和公有

 function Parent () {this.name = 'maz'; // 当前 parent 的私有的属性 实例上自己调用的}
// new 出来的实例可以调用原型上的方法
Parent.prototype.coding = function(){  // 公有的 别人继承了 都可以用的
    console.log("有思想的 coding");
}

function Child () {}

Child.prototype = new Parent() // 核心 主要就是 子类的原型指向 父类的实例
let c = new Child();
console.log(c.constructor); // Parent
console.log(c.name,c.coding()); // 拿到 公有方法和私有属性

原型链继承的一种基本模式 其原理就是 对象的实例 拥有一个指向原型对象的指针(指向所属类的原型)Child 的 原型对象拥有了 Parent 的实例后,自然也拥有了一个指向 Parent 原型对象的指针了。此时 我们 new 一个 Child 的实例 c 时,c 实例包含着一个指向 Child 原型的指针, Child.prototype 拥有一个指向 Parent 原型对象的指针,Parent 原型本身包含着一个指向自身构造函数的指针,这样一来,就构成了实例与原型的链条,也就是所谓的原型链的概念了
** 注意 **:这里的 c 对象的 constructor 现在指向了 Parent 了,因为 Child 的原型指向了 另外一个对象 Parent 的原型,而这个原型对象的 constructor 指向的是 Parent。![图片描述][2]


缺点是:1. 无法实现多继承
2. 可以在 Child 构造函数中,为 Child 实例添加实例属性。如果要新增 原型属性或者方法的话 则必须放在 new Child() 实例化之后执行。3. 来自原型对象的所有属性被所有的实例共享
4. 创建子类实例时,无法向父类构造函数传参

// 一般就不用 上面 这种方式了
// Object.Create()  // 只是继承公有方法
Parent.fn = funciton (){ // 属于 Parent 类上的私有属性}
![图片描述][3]
function create(parentProto,param){function Fn(){} // 相当于构建一个类 类的原型链指向了父类的原型
    Fn.prototype = parentProto;
    let fn = new Fn();
    fn.constructor = param.constructor.value; // 手动改变 constructor 的指向
    return fn;
}
// 子类查找时 可以查到父类的原型,所以可以拿到父类的公共方法
Child.prototype =create(Parent.prototype);
let child = new Child();
console.log(child.coding())
console.log(child.constructor);// Parent
** 希望这里的 constructor 是 Child 怎么实现呢?**
Child.prototype =create(Parent.prototype,{constructor:{ value: Child}})
let child = new Child;
console.log(child.constructor);// Child
// 静态属性 是可以继承的
Child.__proto__ = Parent;
Child.fn();

退出移动版