重学前端-面向对象

对象

属性

数据属性

1.value 值

2.writable 能否被赋值

3.enumerable 能否被枚举 for in Object.keys

4.configurable 能否被删除或者改变属性值

var a ={a:1}
Object.getOwnPropertyDescriptor(a,'a') //{configurable: true,enumerable: true,value: 1,writable: true}

Object.defineProperty(a,'a',{value:5,configurable: false,enumerable: false,writable: false})

访问器属性

1.Getter 取值

2.setter 赋值

3.enumerable 能否被枚举 for in

4.configurable 能否被删除或者改变属性值

let o = {
  b: 1,
  get a() {
    return this.b;
  },
  set a(i) {
    this.b = i;
  },
};

console.log(o.a); // 1
o.a = 5;
console.log(o.a); // 5


var o = { b: 1 };
Object.defineProperty(o, 'a', {
  set: function (value) {
    this.b = value + 100;
  },
  get: function () {
    return this.b;
  },
});

console.warn(o.a); // 6
o.a = 6;
console.warn(o.a); // 106

创建对象

对象的key只能是字符串 和 symbol

对象字面量

var id = Symbol();
var o = { name: 'a', age: 18, [id]: 1 }; // 对象的key 键名是数值

console.warn(o[id]); // 1
// 获取key string
console.log(Object.getOwnPropertyNames(o)); //[ 'name', 'age' ]
console.log(Object.keys(o)); //[ 'name', 'age' ]
// 获取key Symbol
console.log(Object.getOwnPropertySymbols(o)); // [ Symbol() ]

// 获取所以属性
console.log(Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))); // [ 'name', 'age', Symbol() ]
console.log(Reflect.ownKeys(o)); // [ 'name', 'age', Symbol() ]

// 获取属性
console.log(Object.getOwnPropertyDescriptor(o, 'name')); // { value: 'a', writable: true, enumerable: true, configurable: true }
console.log(Object.getOwnPropertyDescriptors(o));
// {
//   name: { value: 'a', writable: true, enumerable: true, configurable: true },
//   age: { value: 18, writable: true, enumerable: true, configurable: true },
//   [Symbol()]: { value: 1, writable: true, enumerable: true, configurable: true }
// }

for (let i in o) {
  console.log(i); // name age
}

console.log(o.hasOwnProperty('name')); // true
console.log(o.hasOwnProperty(id)); // true

缺点:产生大量重复代码

Object构造函数

var id = Symbol();
var o = new Object({ name: 'a', age: 18, [id]: 1 }); // 对象的key 键名是数值

console.warn(o[id]); // 1
// 获取key string
console.log(Object.getOwnPropertyNames(o)); //[ 'name', 'age' ]
console.log(Object.keys(o)); //[ 'name', 'age' ]
// 获取key Symbol
console.log(Object.getOwnPropertySymbols(o)); // [ Symbol() ]

// 获取所以属性
console.log(Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))); // [ 'name', 'age', Symbol() ]
console.log(Reflect.ownKeys(o)); // [ 'name', 'age', Symbol() ]

// 获取属性
console.log(Object.getOwnPropertyDescriptor(o, 'name')); // { value: 'a', writable: true, enumerable: true, configurable: true }
console.log(Object.getOwnPropertyDescriptors(o));
// {
//   name: { value: 'a', writable: true, enumerable: true, configurable: true },
//   age: { value: 18, writable: true, enumerable: true, configurable: true },
//   [Symbol()]: { value: 1, writable: true, enumerable: true, configurable: true }
// }

for (let i in o) {
  console.log(i); // name age
}

console.log(o.hasOwnProperty('name')); // true
console.log(o.hasOwnProperty(id)); // true

缺点:产生大量重复代码

Object.create()

使用现有的原型来创建对象

var id = Symbol();
var o = Object.create({ name: 'a', age: 18, [id]: 1 }); // 对象的key 键名是数值

console.warn(o[id]); // 1
// 获取key string
console.log(Object.getOwnPropertyNames(o)); //[ ]
console.log(Object.keys(o)); //[  ]
// 获取key Symbol
console.log(Object.getOwnPropertySymbols(o)); // [  ]

// 获取所以属性
console.log(Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))); // [ ]
console.log(Reflect.ownKeys(o)); // [ ]

// 获取属性
console.log(Object.getOwnPropertyDescriptor(o, 'name')); // undefined
console.log(Object.getOwnPropertyDescriptors(o)); // {}

for (let i in o) {
  console.log(i); // name age
}

console.log(o.hasOwnProperty('name')); // false
console.log(o.hasOwnProperty(id)); // false

工厂模式

function createPerson(name,age) {
    var o = new Object()
    o.name = name;
    o.age = age;
    o.sayName=function() {
        console.log(this.name)
    }
    return o
}

var p1 = createPerson('a',18)
var p2 = createPerson('b',18)

console.log(p1 instanceof Object) // true
console.log(p2  instanceof Object) // true

console.log(p2.__proto__ === p1.__proto__)

优点:能一次创建多个对象

缺点:创建的对象没法区别 所有实例的原型都指向同一个对象

构造函数模式

function Person(name,age) {
    this.name = name;
    this.age = age;
    this.sayName = function() {
        console.log(this.name)
    }
}
var p3 = new Person('a',18)
p3.sayName() // q
p3.name = 'aa'
p3.sayName() // qq
var p4 = new Person('b',18)
p4.sayName() // b
console.log(p3 instanceof Person) // true
console.log(p4 instanceof Person) // true

console.log(p4.__proto__ === p3.__proto__)

优点:显式的创建了对象 可以识别为一种特点类型
缺点:每次创建对象时方法都要被创建一次

原型模式

function Person1() {

}
Person1.prototype.name = 'a'
Person1.age = '18'
Person1.sayName = function() {
    console.log(this.name)
}
var p5 = new Person('a',18)
p5.sayName() // a
p5.name = 'aa'
p5.sayName() // aa
var p6 = new Person('b',18)
p6.sayName() // b
console.log(p5 instanceof Person) // true
console.log(p5 instanceof Person) // true

console.log(p6.__proto__ === p6.__proto__)

优点:方法不会重建
缺点:所有属性和方法都共享 不能初始化参数

  • 原型模式优化
    优点:方法不会重建 封装更好 更简单
    缺点:所有属性和方法都共享 不能初始化参数 完全重写了原型 ,导致constructor指向不对,要明确指向constructor
/**
 * 原型模式优化
 * 优点:方法不会重建 更简单
 * 缺点:所有属性和方法都共享 不能初始化参数 完全重写了原型 ,导致constructor指向不对,要明确指向constructor
 * */
function Person11() {

}
Person11.prototype = {
    constructor: Person11,  // 完全重写了原型 ,导致constructor指向不对,要明确指向constructor
    name : 'a',
    age: 18,
    sayName:function() {
        console.log(this.name)
    }
}
var p55 = new Person11()
p55.sayName() // a
p55.name = 'aa'
p55.sayName() // aa
var p66 = new Person1()
p66.sayName() // a
console.log(p55 instanceof Person11) // true
console.log(p55 instanceof Person11) // true

console.log(p66.__proto__ === p55.__proto__) // false
console.log(Person11.prototype.constructor === Person11) // true

组合模式

就是把构造模式和原型模式组合起来,私有变量放在构造函数里面,公用方法放在原型链里面

function Person2(name,age) {
 this.name = name;
 this.age = age
}
Person2.prototype.sayName = function() {
    console.log(this.name)
}
var p7 = new Person2('a',18)
p7.sayName() // a
p7.name = 'aa'
p7.sayName() // aa
var p8 = new Person2('b',18)
p8.sayName() // b
console.log(p7 instanceof Person2) // true
console.log(p7 instanceof Person2) // true

console.log(p8.__proto__ === p7.__proto__)

优点:有私有变量 和 共有 方面

动态原型模式

就是把组合模式改变下 原型链定义的方法放在构造函数里面,如果实例没有这个方法 就定义这把这个方法放在原型里,
相比组合模式 封装更多

function Person3(name,age) {
    this.name = name;
    this.age = age
    if(typeof this.sayName !== 'function') {
        Person3.prototype.sayName = function() {
        console.log(this.name)
       }
        // 或者
        // Person3.prototype = {
        //     constructor: Person3, // 对象字面量会导致原型被覆盖 实例的原型指向错误 需要明确指向constructor
        //     sayName: function() {
        //         console.log(this.name)
        //     }
        // }
    }
}
var p7 = new Person3('a',18)
p7.sayName() // a
p7.name = 'aa'
p7.sayName() // aa
var p8 = new Person3('b',18)
p8.sayName() // b
console.log(p7 instanceof Person3) // true 改为对象字面量 变为 false
console.log(p7 instanceof Person3) // true 改为对象字面量 变为 false
console.log(p7.__proto__)

console.log(p8.__proto__ === p7.__proto__) // true 改为对象字面量 变为 false

寄生构造函数

就是把工厂方法写在构造函数里面 和工厂方法的区别是实例通过new

function Person4(name,age) {
    var o = new Object()
    o.name = name;
    o.age = age;
    o.sayName=function() {
        console.log(this.name)
    }
    return o
}
var p7 = new Person4('a',18)
p7.sayName() // a
p7.name = 'aa'
p7.sayName() // aa
var p8 = new Person4('b',18)
p8.sayName() // b
console.log(p7 instanceof Person4) //  false
console.log(p7 instanceof Object) //  true

console.log(p8.__proto__ === p7.__proto__) // true

用途:对某个类型进行属性增强时 出于安全考虑不能直接修改原型,可以考虑这种方式

function SpecialArray() {
     var values = new Array();
     values.push.apply(values, arguments);
     values.toPipedString = function() {
         return this.join("|");
     };

     return values;
 }
 var colors = new SpecialArray("red", "blue", "green");
 console.log(colors.toPipedString());    //"red|blue|green"

稳妥构造函数

不用this 没有公共属性 不用new
优点:安全

function person9(name){
    var o = new Object();
    o.sayName = function(){
        console.log(name);
    };
    return o;
}

var person1 = person9('kevin');

person1.sayName(); // kevin

person1.name = "daisy";

person1.sayName(); // kevin

console.log(person1.name); // daisy

区别

工厂模式 构造函数模式 原型模式 组合模式 动态模式 寄生构造函数 稳妥构造函数
描述 一个function 里面返回一个对象 一个构造函数 this new()声明 Prototype 构造函数(属性)+原型模式(方法) 组合模式改进 把方法定义放在构造函数里面 就是工厂函数 只是用new声明 就是工厂函数 只是不用this 没有共有属性 只有方法 返回传入的值
优点 简单 能一次创建多个对象实例 显式的创建一种类型 方法只创建一次 既有共有方法也有私有属性 封装更好
缺点 创建的对象没法区分类型 都指向object 方法每次创建都要创建一次 属性和方法公用 不能初始化属性
用途 类型属性增强 安全场景

方法

  • 获取属性

    • Object.getOwnPropertyDescriptor(o, ‘name’) 获取o.name属性 不能获取原型链上的

    • Object.getOwnPropertyDescriptors(o) 获取o全部属性 不能获取原型链上的

  • 枚举

    • Object.getOwnPropertyNames(o) 获取string 的键名 不能获取原型链上的
    • Object.keys(o) 获取string 的键名 不能获取原型链上的
    • Object.getOwnPropertySymbols(o) 获取symbol键名 不能获取原型链上的
    • For in能获取原型链上的键名 拿不到symbol
    • Reflect.ownKeys(o) 不包括原型链上的 包括Symbol
  • o.hasOwnProperty(‘name’) 判断是否是原生属性 不能获取到原型链上的

var id = Symbol();
var o = { name: 'a', age: 18, [id]: 1 }; // 对象的key 键名是数值
co[id]; // 1
// 获取key string
Object.getOwnPropertyNames(o); //[ 'name', 'age' ]
Object.keys(o); //[ 'name', 'age' ]
// 获取key Symbol
Object.getOwnPropertySymbols(o); // [ Symbol() ]

// 获取所以属性
Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o)); // [ 'name', 'age', Symbol() ]
Reflect.ownKeys(o); // [ 'name', 'age', Symbol() ]

// 获取属性
Object.getOwnPropertyDescriptor(o, 'name'); // { value: 'a', writable: true, enumerable: true, configurable: true }
Object.getOwnPropertyDescriptors(o); 
// {
//   name: { value: 'a', writable: true, enumerable: true, configurable: true },
//   age: { value: 18, writable: true, enumerable: true, configurable: true },
//   [Symbol()]: { value: 1, writable: true, enumerable: true, configurable: true }
// }

var b = Symbol('b');
function person() {
  this.name = 'a';
  this.age = 18;
  this[b] = 2;
}

person.prototype[id] = 1;
person.prototype.sex = 'girl';
var p = new person();
p[id]; // 1
// 获取key string
Object.getOwnPropertyNames(p); //[ 'name', 'age' ]
Object.keys(p); //[ 'name', 'age' ]
// 获取key Symbol
Object.getOwnPropertySymbols(p); // [ Symbol(b) ]

// 获取所以属性
Object.getOwnPropertyNames(p).concat(Object.getOwnPropertySymbols(p)); // [ 'name', 'age', Symbol(b) ]
Reflect.ownKeys(p); // [ 'name', 'age', Symbol(b) ]

// 获取属性
Object.getOwnPropertyDescriptor(p, 'name'); // { value: 'a', writable: true, enumerable: true, configurable: true }
Object.getOwnPropertyDescriptors(p);
// {
//   name: { value: 'a', writable: true, enumerable: true, configurable: true },
//   age: { value: 18, writable: true, enumerable: true, configurable: true }
//    [Symbol(b)]: { value: 2, writable: true, enumerable: true, configurable: true }
// }

for (let i in o) {
  console.log(i); // name age
}

for (let i in p) {
  console.log(i); // name age sex
}

console.log(o.hasOwnProperty('name')); // true
console.log(p.hasOwnProperty('name')); // true

console.log(o.hasOwnProperty(id)); // true
console.log(p.hasOwnProperty(id)); // false
console.log(p.hasOwnProperty(b)); // true

原型 vs 原型链

原型

定义:每个对象创建时都会与之关联一个原型对象,每个对象都会从原型继承属性。

对象是通过构造函数创建的 这个构造函数有一个属性prototype是一个对象,这个对象就是原型。原型包括了一些公用的属性和方法。构造函数创建的对象会从这个原型中继承这个属性。当找一个属性或者方法时在对象找不到会沿着原型链找。

function Person(){

}
Person.prototype.name = 'a'  // 这里的protype就是原型
var p = new Person()
console.log(p.name) // a  // p对象会从Person.protype原型那里继承name属性


console.log(Person.prototype) // {name:'a'} prototype指向原型对象
console.log(Object.getPrototypeOf(p) ) // {name:'a'} Object.getPrototypeOf 获取原型对象
console.log(p.__proto__ === Person.prototype) // true 对象的___proto__指向对象的原型
console.log(Object.getPrototypeOf(p)=== Person.prototype ) //true
console.log(Person === Person.prototype.constructor) // true 原型的constructor指向构造函数

console.log(Person.prototype.__proto__) // [Object: null prototype] {} 原型的原型是object

console.log(Person.prototype.__proto__.__proto__) // null 原型链的尽头是null

console.log(Person.prototype.__proto__ === Object.prototype) // true 原型的原型是object的原型


重学前端-面向对象_第1张图片

构造函数 实例 原型 的关系如上图:

  • 构造函数的prototype指向原型对象
  • 原型对象的constrctor指向构造函数
  • 构造函数new 出来的实例 通过__proto__指向原型对象 Object.getPrototypeOf(实例) 获取实例的原型对象

原型链

定义:就是相互关联的原型 形成的一个链条 相互之间通过__proto__连接。原型对象是通过obejct构造函数创建的,原型的原型是object的原型对象, 原型链的尽头时null。
重学前端-面向对象_第2张图片

new的原理 手动实现

  1. 首先创建了一个空对象

  2. 然后设置空对象的__proto__作为构造函数的原型prototype

  3. 然后让构造函数的this指向这个对象,允许构造函数

  4. 判断构造函数的返回值 如果是引用类型就返回这个引用类型,如果不是返回创建的对象

    function createNew(fn) {
     const obj = {};
     obj.__proto__ = fn.prototype;
     const result = fn.apply(obj,[...arguments].slice(1));
     return typeof result === 'object' ? result:obj
    }
    
    
    function Person(name,age) {
       this.name = name;
       this.age = age;
    }
    
    Person.prototype.sayName = function() {
          console.log(this.name)
    }
    
    Person.prototype.sayAge = function() {
          console.log(this.age)
    }
    
    const p = createNew(Person,'aa',18)
    p.sayName() // aa
    p.sayAge() // 18xxxxxxxxxx funcfunction createNew(fn) { const obj = {}; obj.__proto__ = fn.prototype; const result = fn.apply(obj,[...arguments].slice(1)); return typeof result === 'object' ? result:obj}function Person(name,age) {   this.name = name;   this.age = age;}Person.prototype.sayName = function() {      console.log(this.name)}Person.prototype.sayAge = function() {      console.log(this.age)}const p = createNew(Person,'aa',18)p.sayName() // aap.sayAge() // 18
    

继承

原型链继承

利用原型链的特性 让child的prototype原型指向parent的实例 这样构造原型链 child就可以访问parent的元素

缺点是 1.构造函数的属性共享, 如果是引用类型 一个子类的实例修改了这个属性 其他实例继承到的属性也会改变 2. 无法向父类传参

/**
 * 原型链继承
 * */
function Parent(firstName,lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.friend = {
        firstName:'li',
        lastName:'si'
    }
}
Parent.prototype.sayName = function () {
    console.log(this.lastName+this.firstName)
}

function Child(firstName) {
    this.firstName = firstName;
}
const parent = new Parent('san','zhang');
Child.prototype = parent
const child = new Child('si');

const child1 = new Child('si');

child.sayName() // zhangsi
parent.sayName() // zhangsan
console.log(child.friend) // { firstName: 'li', lastName: 'si' }

// 缺点是 构造函数的属性共享, 如果是引用类型 一个子类的实例修改了这个属性 其他实例继承到的属性也会改变
child1.friend.firstName = 'hua'
console.log(child1.friend) // { firstName: 'hua', lastName: 'si' }
console.log(child.friend) // { firstName: 'hua', lastName: 'si' }

构造函数继承

可以解决原型链 引用属性共享会导致被子类修改的问题 可以向父类传递参

缺点:所有属性只能在构造函数创建 方法会被多次创建

/*构造函数继承*/
function Parent2(firstName,lastName) {
    this.firstName  = firstName;
    this.lastName = lastName;
    // 缺点是 只能在构造函数里面创建方法
    this.sayName = function () {
        console.log(this.lastName+this.firstName)
    }
    this.friend = {name:'li si'}
}

function Child2(name,age) {
    Parent2.call(this,...arguments)
}
const parent2 = new Parent2('san','zhang');
const child2 = new Child2('si','zhang');

const child21 = new Child2('wu','zhang');

child2.sayName() // zhangsi
parent2.sayName() // zhangsan
console.log(child2.friend) // { name: 'li si' }


// 可以解决原型链属性共享的问题,如果是引用类型 一个子类的实例修改了这个属性 其他实例继承到的属性不会改变
child21.friend.name = 'hua hua'
console.log(child21.friend) // { name: 'hua hua' }
console.log(child2.friend) // { name: 'li si' }

组合继承

利用构造函数+原型链 这样既可以在原型上定义方法,子类也可以继承,又可以让每一个子类有自己的属性 引用类型不会被子类改变 还可以向父类传参

/**
 * 组合继承
 * */
function Parent3(firstName,lastName) {
    this.firstName  = firstName;
    this.lastName = lastName;
    this.friend = {name:'li si'}
}

Parent3.prototype.sayName = function () {
    console.log(this.lastName+this.firstName)
}

function Child3(firstName,lastName) {
    Parent3.call(this,...arguments);
    this.firstName = firstName;
}
Child3.prototype = new Parent3() // 缺点是调用了两次父类构造函数
const parent3 = new Parent3('san','zhang');
const child3 = new Child3('si','zhang');

const child31 = new Child3('wu','zhang');

child3.sayName() // zhangsi
parent3.sayName() // zhangsan
console.log(child3.friend) // { name: 'li si' }

child31.friend.name = 'hua hua'
console.log(child31.friend) // { name: 'hua hua' }
console.log(child3.friend) // { name: 'li si' }

原型式继承

利用一个父类对象 作为原型 创建其他子类对象,子类对象就会继承父类对象

缺点:无法传递参数 引用类型会被改

/**
 * 原型式继承
 * */
var o = {
    firstName:'san',
    lastName:'zhang',
    sayName:function () {
        console.log(this.lastName+this.firstName)
    },
    friend:{name:'li si'}
}
var o1 = Object.create(o)  // 以o为新对象的原型创建对象
var o2 = Object.create(o)
o2.firstName='si'
o1.firstName = 'wu'
o2.friend = 'haha'
o1.sayName() // zhangwu
o2.sayName() //zhangsi
console.log(o2.friend) // haha
console.log(o1.friend) //lisi

// Object.create 自己实现 本质是内部有一个构造函数 把这个构造函数的原型指向传入的对象,返回构造函数的实例
function object(o) {
    function fn() {}
    fn.prototype = o;
    return new fn();
}
var o11 = object(o)  // 以o为新对象的原型创建对象
var o22 = object(o)
o22.firstName='si'
o11.firstName = 'wu'
o22.friend = 'haha'
o11.sayName() // zhangwu
o22.sayName() //zhangsi
console.log(o22.friend) // haha
console.log(o11.friend) //lisi

寄生式继承

就是把 object.create 方法封装到了一个函数里面

/**
 * 寄生式继承
 * */
function object(obj) {
  function fn {}
  fn.prototype = obj
  return new fn();
}

function createAnother(parent) {
    var  o = object(parent)
    o.firstName='si'
    return o
}
const oo = {firstName:'san',lastName:'zhang',friend:{name:'lisi'},sayName:function (){console.log(this.lastName+this.firstName)}}
var o3 = createAnother(oo)
var o4 = createAnother(oo)
o3.sayName() // zhangsi
o3.friend.name = 'huahua'
console.log(o4.friend) // huahua

缺点:无法传递参数 引用类型会被改

寄生组合式继承

组合继承+寄生式 能解决组合继承父类构造函数会被调用两次的问题

function inherit(subType,superType) {
    var prototype = Object.create(superType.prototype);
    prototype.constructor = superType;
    subType.prototype = prototype;
}

function SuperType(firstName,lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.friend = {
        name:'lisi'
    }
}
SuperType.prototype.sayName= function () {
    console.log(this.lastName+this.firstName)
}
function SubType(firstName,lastName) {
   SuperType.call(this,...arguments)
    this.age = 18;
}

inherit(SubType,SuperType)
const parent5 = new SuperType('san','zhang')
parent5.sayName() // zhangsan
const child5 = new SubType('si','zhang')
const child6 = new SubType('wu','zhang')
child5.sayName() // zhangsi
child6.sayName() // zhangwu

console.log(parent5.friend) // { name: 'lisi' }
child5.friend.name ='haha'
console.log(child5.friend) // { name: 'haha' }
console.log(child6.friend) // { name: 'lisi' }
console.log(parent5.friend) // { name: 'lisi' }

区别

继承方式 描述 优点 缺点
原型链继承 利用原型链上可以访问上一级属性,让子类的protype属性等于父类的实例 SubType.prototype=new SuperType() 实现了继承 1.引用属性共享 子类可以篡改父类的属性 2. 子类无法向父类传递参数
构造函数继承 在子类的构造函数调用父类的构造函数 改变this指向子类 Super.call(this,…arguments) 1. 应用属性不会共享 2. 子类可以向父类传递参数 1. 所有属性只能封装在构造函数里面 每次创建实例 方法都会被创建一次
组合式继承 原型式继承+构造函数继承 ,利用构造函数继承父类的属性,利用原型继承父类的方法 1. 应用属性不会共享 2. 子类可以向父类传递参数3.方法也只会创建一遍 父类构造函数会被调用两次
原型式继承 Object.create 会以传入的对象作为原型创造一个新对象 本质是内部声明了一个构造函数 把这个构造函数的prototype属性指向这个函数 最后返回这个函数的实例 同原型链继承
寄生式继承 就是把原型式继承用一个函数封装起来 其实同原型式继承 同上
寄生组合式 组合式+寄生式 利用寄生式继承的特点 解决组合式继承父类构造函数会被调用两次的问题 function inhret(subType,superType){ var prototype = Object.create(superType.prototype);prototype.constructor=SuperType;subType.prototype=protptype} 1. 应用属性不会共享 2. 子类可以向父类传递参数3.方法也只会创建一遍 4.父类构造函数也只会调用一次

你可能感兴趣的:(重学前端,前端,javascript,vue.js)