JS继承和多态

JS继承和多态

  • 继承
    案例:创建一只狗
function Dog({name,type,age}){
   //this = new Object();
   //添加属性
   this.name = name;
   this.type = type;
   this.age = age;
}
/* 
   通过构造函数的原型添加方法
*/
Dog.prototype = {
    run: function(){
        alert(this.name + "会飞快的奔跑");
    },
    showSelf: function(){
        alert(`这是一个${this.type}的,${this.age}岁的,${this.name}叫的小狗`);
    }
}

/* 
   分类更加细分的构造函数。
*/
function Teddy({name,type,age,color}){
    //1.继承父一级构造函数所有的属性
    //构造函数的伪装
    Dog.call(this,{
        name: name,
        type: type,
        age: age
    })
    //添加自己的属性
    this.color = color;
}

// 2.原型链  继承父一级的方法
//<1>通过for...in遍历继承
for(var funcName in Dog.prototype){
    Teddy.prototype[funcName] = Dog.prototype[funcName];
}

//<2>Object.create()
Teddy.prototype = Object.create(Dog.prototype);

//<3>调用构造函数继承
Teddy.prototype = new Dog({});

var xiaohong = new Teddy({
    name: "小红",
    type: "泰迪",
    age: 10,
    color: "红色"
})
alert(xiaohong.name); // 小红
alert(xiaohong.age); // 10
alert(xiaohong.type); // 泰迪
alert(xiaohong.color); // 红色
xiaohong.showSelf(); // 这是一个泰迪的,10岁的,小红叫的小狗

拓展:对象拷贝

var obj1 = {
    a: 10,
    b: 20,
    c: 30
};

var obj2 = obj1;

obj2.c = 100;
console.log(obj1); // {a: 10,b: 20,c: 100}
console.log(obj2); // {a: 10,b: 20,c: 100}

var obj1 = {
    a: 10,
    b: 20,
    c: 30
};

var obj2 = {};
for(var attr in obj1){
    obj2[attr] = obj1[attr];
}

obj2.c = 100;
console.log(obj1); // {a: 10,b: 20,c: 30}
console.log(obj2); // {a: 10,b: 20,c: 100}
  • 多态
    案例:创建一只狗
function Dog({name,type,age}){
    //this = new Object();
    //添加属性
    this.name = name;
    this.type = type;
    this.age = age;
}
 /* 
    通过构造函数的原型添加方法
 */
 Dog.prototype = {
     run: function(){
         alert(this.name + "会飞快的奔跑");
     },
     showSelf: function(){
         alert(`这是一个${this.type}的,${this.age}岁的,叫${this.name}的小狗`);
     }
 }

 /* 
    分类更加细分的构造函数。
 */
 function Teddy({name,type,age,color}){
     //1.继承父一级构造函数所有的属性
     //构造函数的伪装
     Dog.call(this,{
         name: name,
         type: type,
         age: age
     })
     //添加自己的属性
     this.color = color;
 }

 //继承父类方法
 for(var funcName in Dog.prototype){
     Teddy.prototype[funcName] = Dog.prototype[funcName];
 }

 // 新增子方法
 Teddy.prototype.showColor = function(){
     alert(this.color);
 }

 //在子一级构造函数重写showSelf()方法
 Teddy.prototype.showSelf = function(){
    alert(`这是一个${this.type}的,${this.age}岁的,是${this.color}的,叫${this.name}叫的小狗`);

 }

 var xiaohong = new Teddy({
     name: "小红",
     type: "泰迪",
     age: 10,
     color: "红色"
 });
 xiaohong.showSelf(); // 这是一个泰迪的,10岁的,是红色的,叫小红叫的小狗

 var xiaohei= new Dog({
     name: "小黑",
     type: "柴犬",
     age: 5
 });
 xiaohei.showSelf(); // 这是一个柴犬的,5岁的,叫小黑的小狗

总结:
继承和多态同一件事情的两种完全不同的侧重:
继承:侧重的是从父一级构造函数,继承到的属性和方法
多态:侧重的是子一级,自己重写和新增的属性和方法

### JavaScript 中的继承机制 在 JavaScript 中,继承主要通过原型链(Prototype Chain)来实现。每个对象都有一个内部链接指向其构造函数的 `prototype` 属性所指定的对象。当尝试访问一个对象的属性时,如果该对象本身不存在此属性,则会沿着这条链向上查找直到找到为止。 #### 使用构造函数与 prototype 实现简单继承 ```javascript function Animal(name) { this.name = name; } Animal.prototype.sayName = function() { console.log('My name is ' + this.name); }; function Dog(breed, name) { Animal.call(this, name); // 调用父类构造器 this.breed = breed; // 添加子类特有属性 } Dog.prototype = Object.create(Animal.prototype); // 创建新的原型对象并设置 [[Prototype]] Dog.prototype.constructor = Dog; // 修正 constructor 指针 Dog.prototype.bark = function() { // 定义新方法 console.log(`${this.name} barks!`); }; ``` 上述代码展示了如何利用构造函数 `prototype` 来创建父子关系,并实现了基本的功能扩展[^1]。 ### JavaScript 中的多态JavaScript 是一种弱类型语言,在定义变量时不需声明具体的数据类型;因此,同一个函数可以接受不同类型或不同数量的参数而表现出不同的行为——这就是所谓的“鸭子类型”。这种灵活性使得 JavaScript 自然地支持了多态性的概念。 #### 方法重载模拟 虽然 ECMAScript 不直接提供像 Java 或 C++那样的静态方法签名检查功能来进行真正的编译期多态,但是可以通过其他手段达到类似的效果: ##### 基于参数类型的分支逻辑 ```javascript class Shape { draw(context) { throw new Error("This method should be overridden by subclasses."); } } class Circle extends Shape { draw(canvasContext) { canvasContext.beginPath(); canvasContext.arc(70, 80, 50, 0, Math.PI * 2, true); canvasContext.stroke(); } draw(svgElement) { const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); svgElement.appendChild(circle); circle.setAttribute("cx", "70"); circle.setAttribute("cy", "80"); circle.setAttribute("r", "50"); circle.style.fill = "#f00"; } } ``` 注意这里我们实际上违反了一些最佳实践原则,因为在一个类里为同名的方法提供了两个版本。这通常不是推荐的做法,但在某些情况下确实能用来展示多态的思想[^2]。 更常见的是使用运行时期间的信息来做决策: ```javascript // 利用 instanceof 关键字区分调用者身份 if (shape instanceof Circle && context instanceof CanvasRenderingContext2D) { shape.drawCanvas(context); } else if (shape instanceof Rectangle && context instanceof SVGSVGElement) { shape.drawSVG(context); } ``` 这种方法允许程序根据不同条件选择适当的操作路径,从而体现出多态的特点。 ### 结合实际应用场景的例子 考虑构建一个简单的图形渲染库,其中包含多种形状(圆形、矩形等),每种形状都可以被绘制到 HTML5 `<canvas>` 上或者 SVG 元素内。为了使这个过程尽可能灵活通用,我们可以设计如下接口: ```javascript abstract class DrawableShape { abstract render(target); static create(type, ...args) { switch (type.toLowerCase()) { case 'circle': return new Circle(...args); case 'rectangle': return new Rectangle(...args); default: throw new TypeError(`Unsupported shape type: ${type}`); } } } class Circle extends DrawableShape { constructor(radius) { super(); this.radius = radius; } render(target) { if (target instanceof CanvasRenderingContext2D) { target.beginPath(); target.arc(0, 0, this.radius, 0, Math.PI * 2); target.stroke(); } else if (target instanceof SVGCircleElement) { target.setAttribute('r', String(this.radius)); } } } const myCircle = DrawableShape.create('circle', 50); myCircle.render(someCanvasContextOrSvgElement); ``` 在这个例子中,无论目标是何种形式的目标环境 (`<canvas>`, `<svg>`),只要传入合适的上下文对象作为参数给定,就能正确处理相应的绘图命令。这样的设计既体现了良好的封装性可维护性,同时也很好地展现了面向对象编程中的多态特征[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东方求败、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值