Javascript 继承篇

JS篇(010)-JavaScript 继承的方式和优缺点 答案:六种方式 * 一、原型链继承 + 缺点: + 1. 引用类型的属性被所有实例共享 + 2. 在创建 Child 的实例时,不能向 Parent 传参 * 二、借用构造函数(经典继承) + 优点: + 1. 避免了引用类型的属性被所有实例共享 + 2. 可以在 Child 中向 Parent 传参 + 缺点: + 1. 方法都在构造函数中定义,每次创建实例都会创建一遍方法。 * 三、组合继承 + 优点: + 1. 融合原型链继承和构造函数的优点,是 ... 阅读详情

1. Prototype 链(Prototype chaining)

Javascript 是一种动态语言,实现一个目标通常有多种方式,继承也不例外。首先我们介绍下实现继承最普遍的方式 :利用 Prototype 链。

这里假设你已经对 prototype 以及 __proto__ 有了一定的了解,否则请先参考 Javascript 之 Prototype

prototype 链的示意图:
这里写图片描述

接下来的例子我们都采用类似示意图中的3层继承结构:最顶层为一个 Sharp 类,它有一个 名为 TwoDSharp 的子类,最后还有一个名为 Triangle 的类继承自 TwoDSharp。

1.1 Prototype 链示例

首先定义这3个类:

function Shape(){
  this.name = 'Shape';
  this.toString = function () {
    return this.name;
  };
}

function TwoDShape(){
  this.name = '2D shape';
}

function Triangle(side, height){
  this.name = 'Triangle';
  this.side = side;
  this.height = height;
  this.getArea = function () {
    return this.side * this.height / 2;
  };
}

要实现继承关系,只需要添加下面的代码:

TwoDShape.prototype = new Shape();
Triangle.prototype = new TwoDShape();

// 修正 constructor 信息
TwoDShape.prototype.constructor = TwoDShape;
Triangle.prototype.constructor = Triangle;

这里需要指出: Javascript 操作的是对象而不是类,所以 prototype 属性需要一个实例化对象来实现继承,而不像其他 OO 语言直接声明继承自某一个类。
另外在你通过这种方法实现继承后,你再去修改甚至删除父类的函数,已经没有什么关系了,因为我们的继承关系是建立在实例对象上的。

var my = new Triangle(5, 10);

// 自属性
my.getArea();
// 25

// 父属性
my.toString();
// "Triangle"

// 修正 constructor 的语句让我们能获得正确的信息
my.constructor === Triangle;
// true

// 类型确认
my instanceof Shape;
// true
my instanceofTwoDShape;
// true
my instanceof Triangle;
// true
Shape.prototype.isPrototypeOf(my);
// true
TwoDShape.prototype.isPrototypeOf(my);
// true
Triangle.prototype.isPrototypeOf(my);
// true

1.2 把共有属性转到 prototype 上

当你用构造函数创建实例对象时,你可以通过 this 关键字来为其追加属性。当这些属性是只读时,这种做法值得商榷:

function Shape(){
  this.name = 'Shape';
}

这意味着你每一个 Shape 实例对象在内存中都保存着一份 name 属性的值,这显然是不必要的,可以尝试把属性转移到 prototype 上:

function Shape() { ... }
Shape.prototype.name = 'Shape';

利用这种方法,我们可以改进一下前面的函数定义:

// 构造函数
function Shape() {}
// 扩展 prototype
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.name;
};

// 构造函数
function TwoDShape() {}
// 继承实现
TwoDShape.prototype = new Shape();
TwoDShape.prototype.constructor = TwoDShape;
// 扩展 prototype
TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// 继承实现
Triangle.prototype = new TwoDShape();
Triangle.prototype.constructor = Triangle;
// 扩展 prototype
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

验证一下:

var my = new Triangle(5, 10);
my.getArea();
// 25

my.toString();
// "Triangle"

TwoDShape.prototype.isPrototypeOf(my);
// true
my instanceof Shape;
// true

输出结果都满足预期,这里要指出一个细节:my 上的 toString() 方法要比改进前多一步查找,因为原先这个函数就在 Shape 类上,而现在它在 Shape.prototype 上。

2. 仅继承 prototype

前面的例子可以看到在 prototype 上扩展可重用的属性和方法的优势,那么直接从 prototype 继承显然是个不错的方法,至少它带来两个好处:

  • 不用再实例化对象来实现继承
  • 运行时定位属性/方法的效率高了
function Shape() {}
// 扩展 prototype
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.name;
};

function TwoDShape() {}
// 实现继承
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
// 扩展 prototype
TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// 实现继承
Triangle.prototype = TwoDShape.prototype;
Triangle.prototype.constructor = Triangle;
// 扩展 prototype
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

// 测试
var my = new Triangle(5, 10);
my.getArea();
// 25
my.toString();
// "Triangle"

如果你细究一下,你会发现现在 my 的 toString() 函数定位高效了不少。
这里要提一下这个方法的缺点:由于父子的 prototype 都指向同一个对象,当其中一方修改时就会影响到另一方:

Triangle.prototype.name = 'Triangle';
var s = new Shape();
s.name;
// "Triangle"

这显然不可接受啊!

3. 临时构造函数 – new F()

前面介绍的继承方法非常高效,却有个致命的缺点。我们引入一个临时的构造函数来解决:

function Shape() {}
// 扩展 prototype
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.name;
};

function TwoDShape() {}
// 继承实现
var F = function () {};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
// 扩展 prototype
TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// 继承实现
var F = function () {};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
// 扩展 prototype
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

// 测试
var s = new Shape();
s.name;
// "Shape"
"I am a " + new TwoDShape(); // 调用 toString()
// "I am a 2D shape"

3.1 子类中访问父类

传统的 OO 语言通常都有一个关键字(super/base等)来代表父类,这种方式下子类能非常方便的访问父类成员。
在 Javascript 中没有类似的语法,但我们依然能巧妙的实现类似的功能,下例中我们建立了一个 uber 属性来指向父的 prototype 对象。

function Shape() {}
// 扩展 prototype
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  var const = this.constructor;
  return const.uber ? this.const.uber.toString() + ', ' + this.name : this.name;
};

function TwoDShape() {}
// 继承实现
var F = function () {};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.uber = Shape.prototype;
// 扩展 prototype
TwoDShape.prototype.name = '2D shape';
function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// 继承实现
var F = function () {};
F.prototype = TwoDShape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.uber = TwoDShape.prototype;
// 扩展 prototype
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

这里修改了两个内容:

  • 建立了一个 uber 属性来指向父类的 prototype 对象
  • 一个新的 toString() 函数,用来帮助我们验证这套运行机制
var my = new Triangle(5, 10);
my.toString();
// "Shape, 2D shape, Triangle"

这里的属性名 uber 可以任意命名,但并不建议采用以下的常用名称。
“superclass”:这暗示了 Javascript 中有类的概念,而实际却不是这样
“super”:这是 Java 中的父对象关键字,在 Javascript 是保留字(虽然没作用)

3.2 把继承逻辑合到一个 function 中

现在我们把继承的实现逻辑提取出来做成一个 fucntion,方便调用:

function extend(Child, Parent) {
  var F = function () {};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

现在要定义继承关系就相当简洁明了:

// 类定义
function Shape() {}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.constructor.uber ? this.constructor.uber.toString() + ', ' + this.name : this.name;
};

// 类定义 + 继承
function TwoDShape() {}
extend(TwoDShape, Shape);
TwoDShape.prototype.name = '2D shape';

// 类定义
function Triangle(side, height) {
  this.side = side;
  this.height = height;
}
// 继承
extend(Triangle, TwoDShape);
// 扩展
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function () {
  return this.side * this.height / 2;
};

// 测试
new Triangle().toString();
// "Shape, 2D shape, Triangle"

4. 复制属性

现在换一下思路,既然我们继承的目的是重用代码,那么把一个对象的成员简单地复制到另一个对象不也可以吗?我们这就新建一个 extend2() 函数来实验一下这个方法:

function extend2(Child, Parent) {
  var p = Parent.prototype;
  var c = Child.prototype;
  for (vari in p) {
    c[i] = p[i];
  }
  c.uber = p;
}

这里没有设置 Child.prototype.constructor 的原因是:我们没有整个替换掉 Child.prototype 对象,而是在其本身上进行了扩展。

这个方法比起前面的 extend() 来说有一个缺点:每个子类成员都被做了一个副本,而前者是通过 prototype 链。另外需要注意的是这个复制操作仅仅对原始(primitive)类型有效,对于 object 类型(包括 function 及 array)来说因为它们是基于引用传递的,你复制的仅仅是它们的地址!

var Shape = function () {};
varTwoDShape = function () {};
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.uber ? this.uber.toString() + ', ' + this.name : this.name;
};

// extend()
extend(TwoDShape, Shape);
var td = new TwoDShape();
td.name;
// "Shape"
TwoDShape.prototype.name;
// "Shape"
td.__proto__.name;
// "Shape"
td.hasOwnProperty('name');
// false
td.__proto__.hasOwnProperty('name');
// false

// extend2()
extend2(TwoDShape, Shape);
var td = new TwoDShape();
td.__proto__.hasOwnProperty('name');
// true
td.__proto__.hasOwnProperty('toString');
// true
td.__proto__.toString === Shape.prototype.toString;
// true

子成员都需要做一个副本的话 extend2() 似乎并不高效,但这没有想象的那么糟糕因为实际上我们仅仅对原始(primitive)类型做了复制;另外当 Javascript 引擎在 prototype 链上查找成员时查找的路径变短了。

4.1 注意引用拷贝

有时候引用拷贝的结果并不是你期待的,比如下面的例子:

function Papa() {}
function Wee() {}
Papa.prototype.name = 'Bear';
Papa.prototype.owns = ["porridge", "chair", "bed"];

extend2(Wee, Papa);

Wee.prototype.hasOwnProperty('name');
// true
Wee.prototype.hasOwnProperty('owns');
// true

Wee.prototype.owns;
// ["porridge", "chair", "bed"]
Wee.prototype.owns=== Papa.prototype.owns;
// true

Wee.prototype.name += ', Little Bear';
// "Bear, Little Bear"
Papa.prototype.name;
// "Bear"

// 对 Wee 的 owns 属性的修改会作用到 Papa 上
Wee.prototype.owns.pop();
// "bed"
Papa.prototype.owns;
// ["porridge", "chair"]

但是当你整个替换 Wee 的 owns 属性时,又是另外一番情形了:

Wee.prototype.owns= ["empty bowl", "broken chair"];
Papa.prototype.owns.push('bed');
Papa.prototype.owns;
// ["porridge", "chair", "bed"]

这里用一张示意图来分析一下这个过程:
这里写图片描述

  1. 生成一个新 object对象,A 中存放指向它的地址
  2. 声明一个新变量 B,把 A 中的地址复制一份给 B
  3. 修改 B.code 意味着修改 B 的地址指向内容的 code,由于 A 的指向和 B 的一致,所以修改也会作用到 A 上。
  4. 一个新对象被创建,B 的地址被改为指向这个新的对象。A 和 B 指向了不同的内容,不再互相影响了。

5. 从实例对象继承

前面的篇章我们都在构造函数上做文章,通过设置这些函数的 prototype 来实现继承。之前提到过 Javascript 中并没有类的概念,所以它的继承实际上就是代码的重用,前面的 extend2() 就是个比较直接的方式,但它只是在构造函数本身上动手脚。让我们更简单粗暴一点,跳过构造函数直接生成子类的实例对象岂不更好?

function extendCopy(p) {
  var c = {};
  for (vari in p) {
    c[i] = p[i];
  }
  c.uber = p;
  return c;
}

利用新的 extendCopy() 来实现一下前面的继承结构:

var shape = {
  name: 'Shape',
  toString: function () {
    return this.name;
  }
};

var twoDee = extendCopy(shape);
twoDee.name = '2D shape';
twoDee.toString = function () {
  return this.uber.toString() + ', ' + this.name;
};

var triangle = extendCopy(twoDee);
triangle.name = 'Triangle';
triangle.getArea = function () {
  return this.side * this.height / 2;
};

// 测试
triangle.side = 5;
triangle.height = 10;
triangle.getArea();
// 25
triangle.toString();
// "Shape, 2D shape, Triangle"

新的实现让我们不再需要定义子类的构造函数,但某些情形下你可能需要通过构造函数传入一些参数(譬如:创建 triangle 实例的同时传入 side,height),这要解决起来也是很简单的:

  • 增加一个 init() 来传参数
  • 在 extendCopy() 上添加第二个参数,用来传递这些信息

6. 深拷贝

你已经理解 Javascript 中的引用拷贝的内部原理:它们只是指针的拷贝,这被称之为浅拷贝。那么复制指针指向的内容就称之为深拷贝,它们的实现代码非常相似,深拷贝只是浅拷贝的一个“递归”版本:

function deepCopy(p, c) {
  c = c || {};
  for (vari in p) {
    if (p.hasOwnProperty(i)) {
      if (typeof p[i] === 'object') {
        c[i] = Array.isArray(p[i]) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
        c[i] = p[i];
      }
    }
  }
  return c;
}

测试一下:

var parent = {
  numbers: [1, 2, 3],
  letters: ['a', 'b', 'c'],
  obj: {
    prop: 1
  },
  bool: true
};

var mydeep = deepCopy(parent);
var myshallow = extendCopy(parent);
mydeep.numbers.push(4,5,6);
// 6
mydeep.numbers;
// [1, 2, 3, 4, 5, 6]
parent.numbers;
// [1, 2, 3]
myshallow.numbers.push(10);
// 4
myshallow.numbers;
// [1, 2, 3, 10]
parent.numbers;
// [1, 2, 3, 10]
mydeep.numbers;
// [1, 2, 3, 4, 5, 6]

最后补充两点:

  • 使用 hasOwnProperty() 来排除非自有属性,以此保证不会附加多余的属性
  • Array.isArray() 是 ES5 的规范,如果你的 Javascript 环境中没有别惊慌,使用下面的 Polyfill:
if (Array.isArray !== "function") {
  Array.isArray = function (candidate) {
    return Object.prototype.toString.call(candidate) === '[object Array]';
  };
}

7. object()

基于从对象继承的模式,有人提出使用一个 object() 函数来实现:

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

如果需要对父操作,可以改为:

// 虽然是从实例对象继承,但这种模式内部使用 prototype 继承的方式
function object(o) {
  var n;
  function F() {}
  F.prototype = o;
  n = new F();
  n.uber = o;
  return n;
}

使用起来与 extendCopy() 一样,也是传入一个实例对象:

var triangle = object(twoDee);
triangle.name = 'Triangle';
triangle.getArea = function () {
  return this.side * this.height / 2;
};

triangle.toString();
// "Shape, 2D shape, Triangle"

// 在 ES5 中内置了类似的函数 Object.create()
var square = Object.create(triangle);

8. prototype 继承 与 成员拷贝的混合使用

继承的时候,你总是想能够利用既有的功能,以此为基础进行扩展,同时利用前面的两种继承方式可以让我们很容易达成该目的。

  • 使用 prototype 继承来获取既有对象的功能
  • 使用成员拷贝来扩展新的实例对象
function objectPlus(o, stuff) {
  var n;
  function F() {}
  F.prototype = o;
  n = new F();
  n.uber = o;
  for (vari in stuff) {
    n[i] = stuff[i];
  }
  return n;
}

objectPlus() 函数的第一个参数用来 prototype 继承,第二个参数用来扩展,来看看具体的使用:

var shape = {
  name: 'Shape',
  toString: function () {
    return this.name;
  }
};

var twoDee = objectPlus(shape, {
  name: '2D shape',
  toString: function () {
    return this.uber.toString() + ', ' + this.name;
  }
});

var triangle = objectPlus(twoDee, {
  name: 'Triangle',
  getArea: function () {
    return this.side * this.height / 2;
  },
  side: 0,
  height: 0
});

// 测试
var my = objectPlus(triangle, {
  side: 4, height: 4
});
my.getArea();
// 8
my.toString();
// "Shape, 2D shape, Triangle, Triangle"

最后的输出出现了两个 Triangle,这是因为实例对象 my 继承自 Triangle,导致继承层数多了一层,如果创建时给 name 赋个值就能分辨出这个原由了:

objectPlus(triangle, {
  side: 4,
  height: 4,
  name: 'My 4x4'
}).toString();
// "Shape, 2D shape, Triangle, My 4x4"

objectPlus() 与 ES5 中的 Object.create() 非常相似,唯一不同的是第二个参数。详细可参考相关的文档。

9. 多重继承

多重继承就是子类有多个父类,在 OO 语言中许多都不支持,当你遇到是否引入多重继承时需要考虑再三,因为它可能给你带来便利的同时增加程序的复杂度,同时打断直观的继承链。
采用成员拷贝的做法能够很容易地实现多重继承,你甚至可以继承自无限多个父对象。下面的 multi() 函数接受一个父对象数组,内部使用 arguments 关键字来遍历这个数组,并逐一复制:

function multi() {
  var n = {}, stuff, j = 0, len = arguments.length;
  for (j = 0; j <len; j++) {
    stuff = arguments[j];
    for (vari in stuff) {
      if (stuff.hasOwnProperty(i)) {
        n[i] = stuff[i];
      }
    }
  }
  return n;
}

// 使用
var shape = {
  name: 'Shape',
  toString: function () {
    return this.name;
  }
};
vartwoDee = {
  name: '2D shape',
  dimensions: 2
};
var triangle = multi(shape, twoDee, {
  name: 'Triangle',
  getArea: function () {
    return this.side * this.height / 2;
},
  side: 5,
  height: 10
});

// 测试
triangle.getArea();
// 25
triangle.dimensions;
// 2
triangle.toString();
// "Triangle"

multi() 采用顺序遍历的方式复制类成员,所以如果父对象的成员有相同的名字,最后出现的作用在子对象上

混合体(Mixins)

混合体是一种多个对象的合体,它通常具有所有这些合体对象的功能(成员),但本质上并不是这些对象的子对象。(前文的 multi() 生成的结果就是一个混合体)

10. 寄生式继承(Parasitic inheritance)

寄生式继承:把一个对象上的所有功能移到新的实例对象上,并对新的实例对象进行扩展。

var twoD = {
  name: '2D shape',
  dimensions: 2
};

// 寄生式继承
function triangle(s, h) {
  // 使用 object() 来拷贝对象上的所有成员
  var that = object(twoD);
  // 修改/扩展
  that.name ='Triangle';
  that.getArea = function () {
    return this.side * this.height / 2;
  };
  that.side = s;
  that.height = h;
  // 返回新实体
  return that;
}

使用时注意不用 new 关键字:

var t = triangle(5, 10);
t.dimensions;
// 2
vart2 = new triangle(5,5);
t2.getArea();
// 12.5

11. 构造函数的借用

这是本文介绍的最后一种实现继承的方式:子对象使用 call() 或 apply() 来调用父对象的构造函数。

如果你对 call() 或 apply() 不是非常了解,这里简短的介绍一下:
这两个方法让你调用函数的时候传入一个对象,并把该函数中的 this 与传入的这个对象进行绑定。

// 父
function Shape(id) {
  this.id = id;
}
Shape.prototype.name = 'Shape';
Shape.prototype.toString = function () {
  return this.name;
};

// 子
function Triangle() {
  Shape.apply(this, arguments);
}
Triangle.prototype.name = 'Triangle';

// 测试
var t = new Triangle(101);
t.name;
// "Triangle"
t.id;
// 101
t.toString();
// "[object Object]"

实例 Triangle 对象从 Shape 上继承了 id 属性,但是并没有得到父的 prototype 上的内容。根据前文的介绍,我们知道可以这样修改来解决这个问题:

// 子
function Triangle() {
  Shape.apply(this, arguments);
}
Triangle.prototype = new Shape();
Triangle.prototype.name = 'Triangle';

这里有个小问题问题:父的构造函数被调用了两次,一次是 apply() 发起的,一次是设置 prototype 的时候。

骚戴笔记公告 阅读详情

相关推荐

小鹏P7车载以太网诊断实战:从OBD口定义到DoIP协议验证

本文详细解析了小鹏P7车载以太网诊断的实战过程。从OBD接口的针脚定义入手,依据ISO13400标准,确认了以太网线对位置,并指导制作专用的RJ45转OBD线束。通过搭建测试环境,使用Ping、端口扫描及Wireshark抓包,最终成功验证了车辆对DoIP协议的支持,为基于以太网的高速诊断与刷写提供了完整的技术路径。

CAT789的专栏 520

JavaScript继承篇

作为一门面向对象的语言,JavaScript并没有“父类”与“子类”的概念,也没有像java提供extends关键字,c++中直接提供继承方法等那样直接进行继承。然而继承在面向对象的语言中的重要性不言而喻,所以,下述将简要探讨一下,JavaScript中的几种常用的继承方法。 首先,我们需要定义一个父类: function Parent(username) { this.username

慕云白博客 297

自动驾驶中的多传感器融合实战:用卡尔曼滤波搞定毫米波雷达与摄像头航迹对齐

本文深入探讨了自动驾驶中多传感器融合的实战技术,重点介绍了如何使用卡尔曼滤波实现毫米波雷达与摄像头的航迹对齐。通过分析传感器特性差异、时空同步挑战及工程化实现步骤,提供了包括状态向量定义、观测矩阵设计和故障检测机制在内的完整解决方案,最终实现0.15米以内的高精度航迹对齐。

weixin_28728495的博客 410

JavaScript 对象的创建与继承——继承篇

文章目录继承篇原型链继承借用构造函数继承 继承篇 原型链继承 当我访问一个对象实例的属性时候,这个就会在实例的本身找是否存在这个属性,如果没有则访问[__proto__]或者prototype 所以,如果我们需要实现继承,可以通过修改构造函数的原型来实现,这样每一个实例都可以得到父类的属性和方法。 我们直接代码来看下如何实现吧! var Father = function(age) { thi...

gdutRex的博客 252

ADS1231驱动开发:24位高精度ADC嵌入式实现指南

24位Δ-Σ型ADC是高精度传感器信号采集的核心器件,其原理基于过采样与数字滤波实现远超奈奎斯特极限的分辨率。技术价值在于以低成本硬件达成微伏级信号分辨能力,显著提升称重、压力、力等桥式传感器系统的动态范围与温漂稳定性。典型应用场景涵盖电子秤、工业变送器及材料测试设备等对线性度、零点漂移和抗工频干扰(50/60Hz)有严苛要求的领域。本文围绕ADS1231这一面向惠斯通电桥优化的专用ADC,深入解析其串行同步时序驱动、PGA增益配置、参考电压匹配及FreeRTOS多任务安全集成等关键工程实践。

weixin_34268462的博客 624

深度学习实战35-图卷积神经网络GCN模型的搭建与应用

大家好,我是微学AI,今天给大家介绍一下深度学习实战35-图卷积神经网络GCN模型的搭建与应用,GCN是一种用于处理图结构数据的深度学习模型,它可以捕捉节点之间的拓扑关系和局部特征,并进行图级别的预测和分类任务。下面将介绍如何搭建并应用GCN模型。

微学AI的博客 2224

javascript继承篇

theme: cyanosis 继承的7种方式 原型链继承 构造函数继承 组合继承 原型式继承 寄生式继承 寄生组合式继承 Es6 class extends 继承 原型链继承: 将父亲的实例作为孩子的原型. 优点: 父亲的方法可以被子类复用 缺点: 父类的所有属性都会被子类进行共享, 更改了一个子类的属性, 其他的子类的属性也一起变了. 子类的实例不能给父类进行参数的传递. function father (){} function son (){} // 原型指向被继承的实例化上 s.

weixin_40944062的博客 158

Vue+Echarts监控大屏实例四:智慧农业监控模板实例

本实例通过Vue-Echarts实现了智慧农业监控模板实例界面,学习并使用了vue-echarts的使用,接入高德地图并展示,添加了全屏切换、加载动画小鼓、站点切换及退出等相关功能,提供源码下载。

Java、前端、小程序学习笔记、问题汇总、项目实例分享,有需要请联系。 7667

第36篇:JavaScript 原型与原型链终极吃透——JS万物皆对象、继承核心原理

如果说闭包是「函数底层」,那原型链就是 JS 对象底层的天花板。90%零基础求职者卡在这一关:不知道为什么数组能用 map/forEach不知道为什么对象能调用 toString不知道什么是继承、什么是原型面试一问原型链直接空白本篇用最通俗、最系统、最应试的方式,带你彻底吃透原型、原型对象、原型链、继承。闭包 + 原型链是 JavaScript 原生最难、最核心的两大底层原理。JS 基础 → JS 高阶 → JS 底层原理 → 工程实战 → 面试手撕全部闭环。你的前端基础,已经。

2603_95923710的博客 228

时间序列分析(Time Series Analysis) 原理与代码实例讲解

时间序列分析(Time Series Analysis) - 原理与代码实例讲解 作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming 关键词:时间序列预测,ARIMA模型,状态空间模型,SARIMA模型,机器学习

AI天才研究院 1246

【AIGC】大模型面试高频考点09-大模型Agent框架

聚焦AIGC专业技术分享

一个内容严谨、方向前沿、极具实践价值的AI大模型技术分享站 1964

JavaScript继承模式篇

JavaScript继承模式篇继承发展史(1)传统方式——原型链(2)借用构造函数(3)共享原型(4)圣杯模式 继承发展史 (1)传统方式——原型链 A.prototype.lastName = "yang"; function A(){ } var a = new A(); B.prototype = a; function B(){ this.name = "haha"; } var b = new B(); C.prototype = b; function C(){ } var c = n

山大王杨 429

基于四旋翼模型的火箭型无人机视线角保持控制仿真设计

本文针对火箭型无人机的视线角保持控制问题展开研究。基于四旋翼动力学模型,通过改造设计了一种摄像头朝上安装的特殊无人机系统,用于追踪空中目标。文章详细推导了坐标系定义、运动学和动力学方程,重点分析了摄像头安装与视线几何关系,建立了目标运动模型和视线向量计算方法。通过解算期望姿态角,实现了使机体Z轴始终对准目标的控制目标。仿真结果表明,该系统能有效完成视线角保持任务,为空对空监视等应用场景提供了可行方案。~~~~~

huanghm88的专栏 140

前端JavaScript篇之对象继承的方式有哪些?

原型链继承:当使用原型链继承时,子类型的原型对象被设置为父类型的一个实例。这意味着子类型通过其原型可以访问父类型的属性和方法。

星辰迷上大海的博客 2256

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

JS篇-继承的方式

什么是继承 对于继承这个概念来说大家都不陌生,在现实中有儿子继承父业,孙子继承了爷爷的财产等等。那么在编程中,我们熟知的继承其实主要来自于面向对象编程。而很多的面向对象语言都支持两种继承:接口继承和实现继承。前者是只继承方法签名,后者继承实际的方法。 继承的主要作用是将一些抽象的模块抽离出来,作为一个父类使用,这样便于实际编程中代码的可复用性和可维护性,也从一定程度上减少代码冗余,使得代码更加的简洁整齐。 在 JavaScript 中接口继承是不可能实现的,因为函数没有签名。所以实现继承成了 JavaScr

qq_42345237的博客 497

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【前端】Javascript高级篇-类的继承

继承普通方法 // 父类 class Father { constructor() { } say() { console.log('hello world') } } // 子类 class Son extends Father{ } // 通过子类调用父类方法 var son = new Son() son.say() C:\Users\lenovo\Downloads\HBuilderX\readme>cd C:\Users\lenovo\Downloads\HB

瑞新の博客:bennyrhys 2338

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

js 继承模式篇

JS 继承模式 继承发展史 传统形式 ---- 原型链 缺点: ​ 过多的继承了没用的东西。不太实用。 借用构造函数 例如使用 call ( ) / apply ( ) 设置this的指向,来达到借用其他构造函数中的方法的目的。形似继承,实则不是 缺点: ​ 不能继承借用的构造函数的原型 ​ 每次构造函数都要多执行函数,因为使用call/apply时,被借用的构造函数也会执行。 共有原型 Father.prototype.lastName = "deng"; function Fa

い南秋乱港 205

JS 基础篇(原型和继承)

原型主要是用来存公共属性和方法 function Animal(){ } var a=new Animal() a._prop_=Animal.prototype//对象的_prop_指向函数对象的原型 a.constructor=Animal//对象的构造函数指向函数对象 //a即为Animal的实例也为Animal.prototype的实例 在这里插入代码片 原型继承 function...

一点一滴 1万+

JavaScript编程精粹——继承篇

伪类 一个函数对象被创建时,产生的函数对象会运行一个类似这样的代码this.prototype = { constructor: this }; 在我看来,这是原型的继承,类似于面向对象语言中类的继承 这是基于构造器调用模式实现的继承,即使用new,但是书中并不推荐使用new 一个原型继承的例子 Function.prototype.method = function (name, func) {

薛定谔的猫窝 480

JavaScript 基础篇:类与继承

JavaScript 类与继承 本文引自 JavaScript 学习 0402 课程 类与继承JavaScript 类与继承一. JavaScript 中类的写法二. 类的继承本文到此结束,如果对你有帮助,记得留下你的点赞! 一. JavaScript 中类的写法 1. 构造方法:初始化对象 class User1 { // 构造方法其实就是类可以传入的参数 constructor(name, email) { this.name = name; this.email = ema

RQ桑的博客 1429

JS对象继承篇

JS对象继承篇 ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的 原型链 其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法 function Person(){ this.name = "Person"; } Person.prototype.getName = function(){ return this...

weixin_30807779的博客 76

JavaScript学习篇-5、JavaScript中的继承

一、借用构造函数继承父类型属性 // 1、父构造函数 function Father(uname, age) { this.uname = uname; this.age = age; } // 2、子构造函数 function Son(uname, age) { // 通过call()将this指向子构造函数 Father.call(this, uname, age) } var son = new Son('小明', 18); console.log(son); //S

Code P的博客 126

JS笔记 继承篇1

组合继承 在ES6之前并没有提供extends继承。我们使用构造函数+原型对象的方式实现继承 // 构造函数继承 function Father(name,age) { this.name = name; this.age = age; } //共有的方法写到Father的原型对象上, //这里有人会问为什么不直接写到father的构造器中呢,同样可以继承到father的方法 //确实可以,但是当你有new了很多个儿子的时候,而father中有很多个方法, //这时候,js就会重新编译多次相同的方法

big_gg的博客 157

javascript内部原理篇[javascript实现继承]

javascript的面向对象并非新鲜事务,现在简单模拟OOP实现继承

低调的草原狼 1403

JS中的继承—原型篇

原型对象 一个对象的基本描述, 它本身是一个普通对象 当我们在创建一个对象时,这个对象往往会附加一些基本属性,这些基本属性则被称之为原型对象 const person = {} console.log( person.__proto__ ) // 每一个普通对象都有 __proto__ 属性 function person (){} console.log( person.prototype ) // 每个函数对象都有prototype属性 // prototype 和 __proto__ 包含了对象

Huhuf5的博客 231

JavaScript 对象的创建与继承——创建篇

对象 每一个语言最重要与最基础的数据结构非对象莫属,因为可以通过它实现其他任何数据结构。 什么是对象 在JS语言中,对象的定义未:无序属性的集合,其属性可以包含基本值、对象或者函数,换句话说,就是对象里包含许多属性,这些属性通过映射可以指向任何类型的值。 创建一个对象 通过实例Object来创建一个对象 var o = new Object() o.name = 'Rex' o.age =...

gdutRex的博客 307
上一篇: Javascript 之 Prototype
下一篇: Javascript 基础点
sqlchen
博客等级 码龄24年 10粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值