js原型继承的几种方式
- 原型链继承
2,构造函数继承(对象冒充继承)
3,组合继承(原型链继承+构造函数继承)
4,原型式继承
5, 寄生组合式继承
一。原型链继承
function Show(){
this.name="run";
}
function Run(){
this.age="20";
}
// Run继承了Show,通过原型,形成链条
Run.prototype=new Show();
var show=new Run();
alert(show.name)//结果:run
二。构造函数继承(对象冒充继承)
为了解决引用共享和超类型无法传参的问题,我们采用一种叫借用构造函数的技术,或 者成为对象冒充(伪造对象、经典继承)的技术来解决这两种问题
2.优缺点 可以实现多继承,不能继承原型属性/方法
function Box(age){
this.name=['Lee','Jack','Hello']
this.age=age;
}
function Desk(age){
Box.call(this,age); //对象冒充,给超类型传参
}
var desk = new Desk(200);
alert(desk.age);//200
alert(desk.name);//['Lee','Jack','Hello']
desk.name.push('AAA'); //添加的新数据,只给 desk
alert(desk.name)//['Lee','Jack','Hello','AAA']
三。组合继承(原型链继承+构造函数继承)
借用构造函数虽然解决了刚才两种问题, 但没有原型, 复用则无从谈起。 所以, 我们需 要原型链+借用构造函数的模式,这种模式成为组合继承。
通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
function Box(age) {
this.name = ['Lee', 'Jack', 'Hello']
this.age = age;
}
Box.prototype.run = function () {
return this.name + this.age;
};
function Desk(age) {
Box.call(this, age); //对象冒充
}
Desk.prototype = new Box(); //原型链继承
Desk.prototype.constructor = Desk; // 组合继承也是需要修复构造函数指向的。
var desk = new Desk(100);
alert(desk.run());
四。原型式继承
这种继承借助原型并基于已有的对象创建新对象, 同时还不必因此创建自定义类型
function obj(o) { //传递一个字面量函数
function F() {} //创建一个构造函数
F.prototype = o; //把字面量函数赋值给构造函数的原型
return new F(); //最终返回出实例化的构造函数
}
var box = { //字面量对象
name : 'Lee',
arr : ['哥哥','妹妹','姐姐']
};
var box1 = obj(box); //传递
alert(box1.name);
box1.name = 'Jack';
alert(box1.name);
alert(box1.arr);
box1.arr.push('父母');
alert(box1.arr);
var box2 = obj(box); //传递
alert(box2.name);
alert(box2.arr); //引用类型共享了
五。寄生组合式继承
寄生组合式继承解决了两次调用的问题,组合式继承就会有两次调用的情况
基本模型如下:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
后面的寄生式继承和寄生组合模型式继承还搞不懂,哈哈哈,好尴尬
寄生组合继承,解决了两次调用的问题
Person.prototype.constructor == Person;
person1.__proto__ == Person.prototype;
person1.constructor == Person;
person1.__proto__ === Person.prototype
Person.__proto__ === Function.prototype
Person.prototype.__proto__ === Object.prototype
Object.__proto__
Object.prototype.__proto__ === null
var b = new Array();
b.constructor === Array;
b.__proto__ === Array.prototype;
var c = new Date();
c.constructor === Date;
c.__proto__ === Date.prototype;
var d = new Function();
d.constructor === Function;
d.__proto__ === Function.prototype;
// 所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function)
Number.__proto__ === Function.prototype // true
Number.constructor == Function //true
Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true
String.__proto__ === Function.prototype // true
String.constructor == Function //true
// 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Object.__proto__ === Function.prototype // true
Object.constructor == Function // true
// 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
Function.__proto__ === Function.prototype // true
Function.constructor == Function //true
Array.__proto__ === Function.prototype // true
Array.constructor == Function //true
RegExp.__proto__ === Function.prototype // true
RegExp.constructor == Function //true
Error.__proto__ === Function.prototype // true
Error.constructor == Function //true
Date.__proto__ === Function.prototype // true
Date.constructor == Function //true
console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype) // object
console.log(typeof Number.prototype) // object
console.log(typeof Boolean.prototype) // object
console.log(typeof String.prototype) // object
console.log(typeof Array.prototype) // object
console.log(typeof RegExp.prototype) // object
console.log(typeof Error.prototype) // object
console.log(typeof Date.prototype) // object
console.log(typeof Object.prototype) // object
function Person(){}
var person1 = new Person();
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype) //true
console.log(Object.prototype.__proto__) //null
Person.__proto__ == Function.prototype; //true
console.log(Function.prototype)// function(){} (空函数)
var num = new Array()
console.log(num.__proto__ == Array.prototype) // true
console.log( Array.prototype.__proto__ == Object.prototype) // true
console.log(Array.prototype) // [] (空数组)
console.log(Object.prototype.__proto__) //null
console.log(Array.__proto__ == Function.prototype)// true
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.prototype = animal;
var tidy = new dog();
console.log(dog.price) //undefined
console.log(tidy.price) // 2000
原型和原型链是JS实现继承的一种模型。 原型链的形成是真正是靠__proto__ 而非prototype
JavaScript继承实现
function Animal() {
}
Animal.prototype.speak = function () {
console.log('动物发声:');
}
function Dog(name) {
this.name = name;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function () {
//通过原型链找‘基本类’原型里的同名方法
this.__proto__.__proto__.speak.call(this);
console.log('汪汪, 我是', this.name);
}
function Cat(name) {
this.name = name;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.speak = function () {
//通过原型链找‘基本类’原型里的同名方法
this.__proto__.__proto__.speak.call(this);
console.log('喵喵, 我是', this.name);
}
//调用代码
function animalSpeak(animal) {
animal.speak();
}
animalSpeak(new Dog('大黄'))
console.log()
animalSpeak(new Cat('小喵'))
//动物发声:
//汪汪, 我是 大黄
//动物发声:
//喵喵, 我是 小喵
Q: javascript里面的继承怎么实现,如何避免原型链上面的对象共享
我在写的时候,用了两种,一个是 ES5和 ES6的方案
ES5:寄生组合式继承:通过借用构造函数来继承属性和原型链来实现子继承父。
function ParentClass(name) {
this.name = name;
}
ParentClass.prototype.sayHello = function () {
console.log("I'm parent!" + this.name);
}
function SubClass(name, age) {
//若是要多个参数可以用apply 结合 ...解构
ParentClass.call(this, name);
this.age = age;
}
SubClass.prototype = Object.create(ParentClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sayChildHello = function (name) {
console.log("I'm child " + this.name)
}
let testA = new SubClass('CRPER')
// Object.create()的polyfill
/*
function pureObject(o){
//定义了一个临时构造函数
function F() {}
//将这个临时构造函数的原型指向了传入进来的对象。
F.prototype = obj;
//返回这个构造函数的一个实例。该实例拥有obj的所有属性和方法。
//因为该实例的原型是obj对象。
return new F();
}
*/
// ES6: 其实就是ES5的语法糖,不过可读性很强..
class ParentClass {
constructor(name) {
this.name = name;
}
sayHello() {
console.log("I'm parent!" + this.name);
}
}
class SubClass extends ParentClass {
constructor(name) {
super(name);
}
sayChildHello() {
console.log("I'm child " + this.name)
}
// 重新声明父类同名方法会覆写,ES5的话就是直接操作自己的原型链上
sayHello(){
console.log("override parent method !,I'm sayHello Method")
}
}
let testA = new SubClass('CRPER')
到这里就结束了么...不,这只是笔试,
问的时候你用过静态方法,静态属性,私有变量么?
这个静态方法是ES6之后才有这么个玩意,有这么些特点
方法不能给 this引用,可以给类直接引用 静态不可以给实例调用,比如 let a = new ParentClass => a.sayHello() 会抛出异常 父类静态方法,子类非 static 方法没法覆盖父类 静态方法可以给子类继承 静态属性可以继承也可以被修改 看下面的代码..
class ParentClass {
constructor(name) {
this.name = name;
}
static sayHello() {
console.log("I'm parent!" + this.name);
}
static testFunc(){
console.log('emm...Parent test static Func')
}
}
class SubClass extends ParentClass {
constructor(name) {
super(name);
}
sayChildHello() {
console.log("I'm child " + this.name)
}
static sayHello() {
console.log("override parent method !,I'm sayHello Method")
}
static testFunc2() {
console.log(super.testFunc() + 'fsdafasdf');
}
}
ParentClass.sayHello(); // success print
let a = new ParentClass('test');
a.sayHello() // throw error
SubClass.sayHello(); // 同名 static 可以继承且覆盖
SubClass.testFunc2(); // 可以继承
let testA = new SubClass('CRPER');
私有变量这个我没答出来,只是说了下没有 private 这个关键字和基本用下划线的人为区分
所以回来只是找了下相关的资料,发现有一个比较好的模拟方案,就是 WeakMap ;
WeakMap 可以避免内存泄露,当没有被值引用的时候会自动给内存寄存器回收了.
const _ = new WeakMap(); // 实例化,value 必须为对象,有 delete,get,has,set四个方法,看名字都知道了
class TestWeakMap {
constructor(id, barcode) {
__.set(this, { id,barcode });
}
testFunc() {
let { id,barcode } = __.get(this); // 获取对应的值
return { id,barcode };
}
}