和我一起学习Javascript的原型

和我一起学习Javascript的原型
1。在原型上保存方法

例如,不使用原型进行Javascript编码是完全可行的:
功能用户(姓名、passwordhash){
this.name =名称;
this.passwordhash = passwordhash;
this.tostring =函数(){
返回{用户+ this.name +};
};
this.checkpassword =功能(密码){
返回哈希(密码)= this.passwordhash;
};
}

VaR U1 =新(用户 / *…**;
var =新的(用户…**;
VaR U3 =新(用户 / *…**;

创建多种用户类型的实例时,有一个问题:不仅名字和passwordhash属性存在于每一个实例,但ToString和checkPassword方法有复制在每一个实例,如下面的图所示:
但当ToString和checkPassword定义原型,上面的图像就变成下面:
toString方法,现在user.prototype checkPassword定义的对象,这意味着只有一个拷贝,这两种方法的存在,它是由所有用户共享实例。

也许您会认为将每个实例作为副本保存一个副本可以节省方法查询的时间(当该方法在原型上定义时,该方法首先在实例本身上找到,如果没有找到,它将在原型上继续)。

但在现代Javascript执行引擎中,该方法的查询已经进行了大量优化。因此查询时间几乎不需要考虑。因此,在原型对象上保存方法可以节省大量内存

两。使用闭包保存私有数据

Javascript的对象系统不鼓励使用信息隐藏(隐藏)从其语法。因为使用this.name,this.passwordhash时,这些属性的默认访问级别是公开的,可以通过obj.name和obj.passwordhash在任何位置

在ES5的环境,提供更方便的访问一个对象的所有属性,也有一些方法,如Object.keys()、Object.getOwnPropertyNames(),因此,一些开发商利用某些协议的定义例如Javascript对象的私有属性,最典型的是使用下划线属性告诉其他开发者和用户,这个属性不应直接访问前缀。

但这并不能从根本上解决问题,其他开发人员和用户仍然可以直接使用带有下划线的属性访问。

从某种意义上说,在Javascript中,对变量的访问策略和对象的访问策略的关闭是两个极端。闭包中的任何变量都是私有的,只有在函数中才能访问变量:
功能的用户(姓名、passwordhash){
this.tostring =函数(){
返回{用户+名称;
};
this.checkpassword =功能(密码){
返回哈希(密码)= passwordhash;
};
}
在这一点上,名称和passwordhash都没有保存的实例的属性,而是由局部变量保存。然后,根据关闭的访问规则,在实例中的方法可以访问,但不能在其他地方。

采用这种模式的一个缺点是,使用局部变量的方法需要对实例本身的定义,而这些方法不能对原型对象的定义,讨论item34,这样做的问题是增加内存消耗。但在一些特殊的情况下,在一个实例定义的方法可行是也。

三。实例状态仅保存在实例对象上。

一种原型是一对与这种类型的实例多关系。因此,需要确保数据相关的例子将不被保存在原型的错误。例如,一个树型结构,保存它的子节点上的原型是不正确的。
函数树(x){
this.value = x;
}
tree.prototype = { {
子:{,应该是实例状态!
给:函数(x){
This.children.push(X);
}
};

var =新树(2);
(1)left.addchild;
(3)left.addchild;

var =新树(6);
(5)right.addchild;
(7)right.addchild;

新树(4);
top.addchild(左);
top.addchild(右);

top.children; / / { 1, 3, 5,7 },左,右

当状态被保存到原型时,所有实例的状态将被集中保存,这在上面的场景中显然是不正确的:属于每个实例的状态被错误地共享:
正确的实现应该是:
函数树(x){
this.value = x;
this.children = {}; / /实例的状态
}
tree.prototype = { {
给:函数(x){
This.children.push(X);
}
};
此时,实例状态的存储如下所示:
可以看出,当实例的状态在原型上共享时,这可能是一个问题。在您需要在原型上保存状态属性之前,必须确保属性可以共享。

一般来说,当一个属性是不可变的(状态)的属性,它可以保存在原型对象(例如,该方法可以保存在原型对象)。当然,状态属性也可以放在原型对象,这取决于特定的应用场景,如用来记录的类型实例变量数。使用java语言作为一个比喻,这类变量可以存储在原型对象在java类变量(用static关键字修饰)。

四。避免标准继承类型

ECMAscript标准库不是很大,但它提供了一些重要的类型如数组、函数和日期。在某些情况下,你可以考虑继承的类型之一,以实现特定的功能,但这并不是鼓励。

例如,为了操作目录,可以让目录类型继承数组类型如下所示:
函数Dir(路径,条目){
this.path =路径;
对于(var i = 0,n = entries.length;i < n;i++){
此{ = } =条目{ };
}
}
dir.prototype = object.create(阵列。原型);
扩展数组

var目录=新目录( / / TMP的首页
dir.length / / 0;

但可以发现,dir.length值是0,不是3的期望。

这样做的原因是,当对象是真正的数组类型时,长度属性才会起作用

在ECMAscript标准,一个看不见的内部属性定义为{ {类} }。这个属性的值是一个字符串,所以不要被误导认为Javascript也实现了它自己的类型系统,为数组类型,此属性的值是数组的函数式;此属性的值的函数。下表是所有{ {类} }值定义的ECMAscript:

当对象的类型是数组的长度属性是特殊的:长度的值将在对象索引属性的数量一致。例如,一个对象数组arr数组{ 0 }和{ 1 }表明数组的对象有两个索引属性,那么长值是2。当ARR { 2 }增加长度的值会自动同步到3。同样,当长度的值设置为2,ARR { 2 }自动设置为未定义。

但是,当数组类型被继承并创建一个实例时,实例的{ } }属性不是数组,而是对象,所以长度属性不能正常工作

在Javascript中,一种方法查询{ {类} }特性还提供,即使用object.prototype.tostring方法:
新目录()
object.prototype.tostring.call(DIR); / / {物}
object.prototype.tostring.call({ }); / / } {对象数组
因此,更好的实现方法是使用组合而不是继承:
函数Dir(路径,条目){
this.path =路径;
this.entries =条目; / /数组属性
}
dir.prototype.foreach =函数(F,thisarg){
如果(typeof thisarg =未定义){
这thisarg =;
}
this.entries.foreach(F,thisarg);
};
上面的代码将不再使用继承,而是将函数代理的一部分给内部条目属性,这是一个数组类型对象。

在ECMAscript标准库,大多数的建设者依靠内部的属性值,如{ {类} },达到正确的行为。对于亚型,继承这些标准类型,也不可能保证自己的行为是正确的。因此,不继承类型在ECMAscript标准库,这样作为:

阵列、布尔值、日期、数量、功能、正则表达式、字符串

以上就是使用原型来总结几点注意事项,希望能帮助您正确使用原型。
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部