Nodejs环境下javascript原型继承的学习研究
Nodejs环境下javascript原型继承的学习研究
###几句废话先
本人由.NET平台转向JS,但是对JS深层次的东西理解的不是很透彻,自己也花了些时间研究JS相关技术,今天这就当是自己学习研究的一个记录吧 :)
###js的原型链prototype chain
我一直很难理解js中德继承机制,他不像C#或者java中的那样去实现,而且在js中也没有instance这个概念,也就是说在js中没有子类
和父类
的概念,他全靠prototype的模式实现继承机制。关于js的原型继承呢,你也会经常看到这样一句话:
当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止;
他的基本查找就是如同下面这段代码所演示的,但是他的内部机制不是这么的简单:
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop))
return obj[prop]
else if (obj.__proto__ !== null)
return getProperty(obj.__proto__, prop)
else
return undefined
}
说到这,就不得不说一下proto
,在js中是靠他表示一个对象的原型链,但是使用他是不符合规范的,你将在下面的文章中看到,为什么不能使用他。我们先来举一个例子:
var say = {
you:'',
me:'',
print:function(){console.log(this.you,this.me)}
}
var p = {you:'jeff',me:'David','__proto__':say}
p.print();
在这里他的__proto__属性指向了say。(在这里我们可以吧这个属性当做一个指针,尽管不是:))
###javascript中让人摸不着头脑的原型继承
- 首先咱来谈谈
new
关键字:
造物者:Brendan Eich在设计javascript之初一定受到了c++和java的影响,c++和java还有c#之类的语言在调用new时一定会调用它们的构造函数
constructor
,但是呢,在javascript中new后面跟的不是类,而是构造函数constructor
但是呢,这里有一个问题,使用构造函数生成的对象,无法共享其属性和方法,换句话说就是,你是你的,我是我的。 举一个例子吧:
function say(word){
this.word = word;
this.host = 'David zhang';
}
var sayer1 = new say('今儿北京雾霾太严重了');
var sayer2 = new say('下午6点回家');
//在这里这两个对象的host属性是独立的,
sayer2.host = 'jeff';
alert(sayer1.host); //David Zhang;
从上面我们可以看出,每个实例对象有自己的属性和方法,实例与实例之间无法共享。这也就导致了资源的浪费
####new的机制:
new 运算符接受一个函数 F 及其参数:new F(arguments…)。这一过程分为三步: + 创建类的实例。这步是把一个空的对象的 proto 属性设置为 F.prototype 。 + 初始化实例。函数 F 被传入参数并调用,关键字 this 被设定为该实例。 + 返回实例。
- javascript中真正的原型继承
说到这咱又要说到咱的大宗师:
道格拉斯
了是他发现了一种可以利用 new 来实现真正的原型继承的方式:
Object.create = function (parent) {
function F() {}
F.prototype = parent;
return new F();
};
上面那个say对象现在可以写成:
var say = {
you:'',
me:'',
print:function(){console.log(this.you,this.me)}
};
var s = Object.create(say);
s.you = 'noder';
s.me = 'David Zhang';
s.print(); //noder David Zhang
但是呢,Object.create()的性能比new差的很多!
现在说说为什么不要用__proto__
:因为这样会对父类的所有子类开放整个原型链的操作权限(太可怕了!)
var P = new function(){}
P.prototype.name = 'David'
var a = new P()
a.name // 'David'
a.__proto__ === P.prototype //true
a.__proto__.name = 'Zhang'
P.prototype.name // 被修改为'Zhang'
###重点回顾
- javascript中德原型链继承了啥:
说到底就是继承了构造函数和原型链两个东西,构造函数继承就是意味着,把父类的属性方法给copy一遍,对其进行修改也不会影响到其他的实例。 而对于原型链的继承就表示子类和超类公用原型链上的东西,修改的话,只能从超类修改
###构造函数继承(觉得有些地方没有说清楚)
function a(){
this.nameA = '我是基类a';
}
构造函数的继承在这我就先说两种方法: 1:构造函数绑定
function b(){
a.apply(this,arguments);
this.nameB = '我是子类b';
}
var p = new b();
b.nameA; //我是基类a
2: 使用prototype 这里还是使用上面的a 和 b
b.prototype = new a();
b.prototype.constructor = b;
var p = new b();
b.nameA;//我是基类a
其实任何一个prototype对象都有一个constructor属性,指向它的构造函数 在这里b.prototype = new a();后b.prototype.constructor就指向a了 所以我们要加上b.prototype = b; (这是必须的,务必遵守!) ###几点要说:
- 本人也在学习之中,上述述说中如有错的地方,请雅正。
- 自己还要进一步的深入学习JS
- 深度参考:Vjeux
- 同时欢迎各位大神补充
- 本博文允许转载,但请标明来源: nodejs中文社区:http://cnodejs.org/topic/53b8e1f41b009b31531f37bd 博客园:http://www.cnblogs.com/struCoder/p/3827027.html
Nodejs环境下JavaScript原型继承的学习研究
几句废话先
本人由.NET平台转向JS,但是对JS深层次的东西理解得不是很透彻,自己也花了些时间研究JS相关技术。今天这篇文章算是对自己学习研究的一个记录吧。
JavaScript的原型链
我一直很难理解JS中的继承机制,它不像C#或Java那样有明确的子类
和父类
的概念。在JS中,所有的继承都是通过prototype
实现的。JS中有一个常见的说法:
当查找一个对象的属性时,JavaScript会向上遍历原型链,直到找到给定名称的属性为止。
这可以通过以下代码进行演示:
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop)) {
return obj[prop];
} else if (obj.__proto__ !== null) {
return getProperty(obj.__proto__, prop);
} else {
return undefined;
}
}
var obj = {
name: 'David',
};
var newObj = Object.create(obj);
console.log(newObj.name); // 输出 "David"
JavaScript中让人摸不着头脑的原型继承
new
关键字
Brendan Eich在设计JavaScript之初确实受到了C++和Java的影响,但在JavaScript中new
后面跟的是构造函数,而不是类。使用构造函数生成的对象无法共享其属性和方法,因此资源会被浪费。
function Say(word) {
this.word = word;
this.host = 'David Zhang';
}
var sayer1 = new Say('今儿北京雾霾太严重了');
var sayer2 = new Say('下午6点回家');
// 在这里这两个对象的host属性是独立的
sayer2.host = 'jeff';
console.log(sayer1.host); // 输出 "David Zhang"
new
的机制
new
运算符的工作步骤如下:
- 创建一个新的空对象,并将该对象的
__proto__
属性设置为构造函数的prototype
。 - 将构造函数的
this
绑定到新创建的对象上,并执行构造函数。 - 返回新创建的对象。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
var person1 = new Person('David');
person1.greet(); // 输出 "Hello, I'm David"
JavaScript中真正的原型继承
Douglas Crockford 发现了一种利用new
来实现真正的原型继承的方式:
Object.create = function(parent) {
function F() {}
F.prototype = parent;
return new F();
};
var say = {
you: '',
me: '',
print: function() {
console.log(this.you, this.me);
}
};
var s = Object.create(say);
s.you = 'noder';
s.me = 'David Zhang';
s.print(); // 输出 "noder David Zhang"
但是,Object.create()
的性能通常不如直接使用new
操作符。
为什么不要用__proto__
使用__proto__
会对父类的所有子类开放整个原型链的操作权限,这可能会导致不可预测的行为。
var P = function() {};
P.prototype.name = 'David';
var a = new P();
a.name; // 输出 "David"
a.__proto__.name = 'Zhang';
P.prototype.name; // 修改为 "Zhang"
重点回顾
JavaScript中的原型链继承了构造函数和原型链两个东西。构造函数继承意味着将父类的属性方法复制一遍,修改不会影响其他实例。而原型链继承则表示子类和超类共用原型链上的东西,修改只能从超类开始。
构造函数继承
构造函数的继承可以通过两种方法实现:
- 构造函数绑定:
function A() {
this.nameA = '我是基类A';
}
function B() {
A.apply(this, arguments);
this.nameB = '我是子类B';
}
var p = new B();
console.log(p.nameA); // 输出 "我是基类A"
- 使用
prototype
:
function A() {
this.nameA = '我是基类A';
}
function B() {
A.call(this);
this.nameB = '我是子类B';
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
var p = new B();
console.log(p.nameA); // 输出 "我是基类A"
总结
本文介绍了Node.js环境下JavaScript原型继承的基本概念、实现方式及注意事项。希望这些内容对你理解JavaScript的继承机制有所帮助。如果你有任何疑问或需要进一步探讨的地方,请随时留言交流。
加油!
支持一下。看来大家都喜欢原型继承,不过我也推荐使用模块模式来实现继承,不需要涉及原型以及相关概念,比较直观。
学习了很多遍,还是忘记了:( 咋办?
var P = new function () {} P.prototype.name = ‘David’
is this correct? maybe not
Node.js 环境下 JavaScript 原型继承的学习研究
大家好,我之前主要做 .NET 平台开发,现在转到了 JavaScript。虽然我对 JavaScript 的基础知识有一定了解,但对于一些深层次的概念如原型继承还存在不少疑惑。今天,我将分享一些关于 JavaScript 原型继承的研究成果。
JavaScript 的原型链
在 JavaScript 中,继承机制不同于 C# 或 Java,它完全依赖于原型(prototype)。在 JavaScript 中没有像 “子类” 或 “父类” 这样的概念,所有的继承都是通过原型链来实现的。
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop)) {
return obj[prop];
} else if (obj.__proto__) {
return getProperty(obj.__proto__, prop);
} else {
return undefined;
}
}
这里的 __proto__
表示对象的原型链,但它并不是标准的属性名。建议使用 Object.getPrototypeOf()
和 Object.setPrototypeOf()
来操作原型链。
new
关键字的作用
new
关键字用于创建一个新对象,并调用构造函数。例如:
function Say(word) {
this.word = word;
this.host = 'David Zhang';
}
var sayer1 = new Say('今天北京雾霾太严重了');
var sayer2 = new Say('下午6点回家');
sayer2.host = 'Jeff';
console.log(sayer1.host); // 输出: David Zhang
可以看到,每个实例对象有自己的属性和方法,这会导致资源的浪费。为了更好地理解 new
的机制,可以看以下三个步骤:
- 创建一个新对象,并将其
__proto__
属性设置为构造函数的prototype
。 - 调用构造函数,
this
指向新创建的对象。 - 返回新创建的对象。
实现原型继承
我们可以使用 Object.create
方法来实现真正的原型继承:
Object.create = function (parent) {
function F() {}
F.prototype = parent;
return new F();
};
var say = {
you: '',
me: '',
print: function () { console.log(this.you, this.me); }
};
var s = Object.create(say);
s.you = 'Noder';
s.me = 'David Zhang';
s.print(); // 输出: Noder David Zhang
构造函数继承
构造函数的继承可以通过两种方式实现:
- 构造函数绑定:
function A() {
this.nameA = '我是基类A';
}
function B() {
A.apply(this, arguments);
this.nameB = '我是子类B';
}
var p = new B();
console.log(p.nameA); // 输出: 我是基类A
- 使用 prototype:
function A() {
this.nameA = '我是基类A';
}
function B() {
this.nameB = '我是子类B';
}
B.prototype = new A();
B.prototype.constructor = B;
var p = new B();
console.log(p.nameA); // 输出: 我是基类A
需要注意的是,B.prototype = new A();
后 B.prototype.constructor
会指向 A
,所以我们需要手动将其设置回 B
。
总结
JavaScript 的原型链继承主要包括构造函数继承和原型链继承。构造函数继承通过拷贝父类的方法和属性实现,而原型链继承则通过共享原型链上的方法和属性实现。希望这些示例能帮助你更好地理解和应用 JavaScript 的原型继承机制。