JavaScript 中实现继承的方式(列举3种在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。)
第一种:对象冒充
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function ClassA(sColor) { this .color = sColor; this .sayColor = function () { alert( this .color); }; } function ClassB(sColor, sName) { this .newMethod = ClassA; this .newMethod(sColor); delete this .newMethod; this .name = sName; this .sayName = function () { alert( this .name); }; } var objA = new ClassA( "blue" ); var objB = new ClassB( "red" , "John" ); objA.sayColor(); objB.sayColor(); objB.sayName(); |
注意: 所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法:
第二种: 通过Function 对象上面的call, apply方法来实现继承。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function ClassA(sColor) { this .color = sColor; this .sayColor = function () { alert( this .color); }; } function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply( this , arguments); this .name = sName; this .sayName = function () { alert( this .name); }; } var objA = new ClassA( "blue" ); var objB = new ClassB( "red" , "John" ); objA.sayColor(); objB.sayColor(); objB.sayName(); |
第三种:原型链 prototype 属性对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function ClassA() { } ClassA.prototype.color = "red" ; ClassA.prototype.sayColor = function () { alert( this .color); }; function ClassB() { } ClassB.prototype = new ClassA(); ClassB.prototype.name = "" ; ClassB.prototype.sayName = function () { alert( this .name); }; var objA = new ClassA(); var objB = new ClassB(); objA.color = "blue" ; objB.color = "red" ; objB.name = "John" ; objA.sayColor(); objB.sayColor(); objB.sayName(); |
注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
实际应用中,可能混合方式:
(象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了)
在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。用这两种方式重写前面的例子,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function ClassA(sColor) { this .color = sColor; } ClassA.prototype.sayColor = function () { alert( this .color); }; function ClassB(sColor, sName) { ClassA.call( this , sColor); this .name = sName; } ClassB.prototype = new ClassA(); ClassB.prototype.sayName = function () { alert( this .name); }; var objA = new ClassA( "blue" ); var objB = new ClassB( "red" , "John" ); objA.sayColor(); objB.sayColor(); objB.sayName(); |
注意:在第一行突出显示的代码中,在 ClassB 构造函数中,用对象冒充继承 ClassA 类的 sColor 属性。在第二行突出显示的代码中,用原型链继承 ClassA 类的方法。由于这种混合方式使用了原型链,所以 instanceof 运算符仍能正确运行。
作者:杨志
链接:https://www.zhihu.com/question/20289071/answer/14644278
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:itlr
链接:https://www.zhihu.com/question/20289071/answer/48779872
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:杨佰
链接:https://www.zhihu.com/question/20289071/answer/62582198
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://www.zhihu.com/question/20289071/answer/14644278
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LZ要先明白存在call和apply的原因,才能记得牢一点:
在javascript OOP中,我们经常会这样定义:
所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。
用的比较多的,通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。我们可以通过:
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
这样domNodes就可以应用Array下的所有方法了。
其他的就不提了,讲多了反而迷惑。
在javascript OOP中,我们经常会这样定义:
function cat(){但是如果我们有一个对象whiteDog = {food:"bone"},我们不想对它重新定义say方法,那么我们可以通过call或apply用blackCat的say方法:blackCat.say.call(whiteDog);
}
cat.prototype={
food:"fish",
say: function(){
alert("I love "+this.food);
}
}
var blackCat = new cat;
blackCat.say();
所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。
用的比较多的,通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。我们可以通过:
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
这样domNodes就可以应用Array下的所有方法了。
其他的就不提了,讲多了反而迷惑。
另外:
- JS functions are objects JS函数是对象,没什么特别的
- ... that have .call and .apply methods 这些对象只不过有call和apply两个特别的方法而已
- ... both take an object as the first argument call和apply的第一个参数是任一个对象
- ... which specifies the target where the function runs against 既函数的执行(作用)目标
function fn (a) { ... }
var obj = { ... }
// 在obj上执行fn
fn.call(obj, ...)
fn.apply(obj, ....)
作者:itlr
链接:https://www.zhihu.com/question/20289071/answer/48779872
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
a)另外:
1 2 3 4 5 6 7 8 9 10 | function add(a, b){console.dir( this );} function sub(a, b){console.dir( this );} add(1,2); "Window" sub(1,2); "Window" add.call(sub, 1, 2); "sub(a, b)" sub.apply(add, [1, 2]); "add(a, b)" |
this和arguments理解了。这2函数apply, call就不攻自破了。
作者:杨佰
链接:https://www.zhihu.com/question/20289071/answer/62582198
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现