用Javascript深入研究原型原型
1。函数是一个类对象,这意味着函数与对象具有相同的语言状态。
2。没有类,只有对象
3。函数也是一个对象,所谓函数对象。
4。对象是通过引用传递的。
那么基于原型的编程语言是如何继承继承的(这是OO的一大基础元素),这就是原型的起源。
请看下面的代码片段:
函数(a,b,c)
{
返回;
}
警报(长度);
警报(typeof foo。构造函数);
警报(typeof foo调用);
警报(typeof foo。适用);
警报(typeof foo。原型);
对于上面的代码,当你运行浏览器时,你会发现:
1.length:提供对函数参数的个数
2.prototype:是一个对象
三.其他三个功能
对于任何函数的声明,它将有上面描述的5个属性(方法或属性)。
下面我们来看看原型。
原型
功能人(姓名,性别)
{
this.name =名称;
this.gender =性别;
this.whoareyou =功能({ / /)这就是所谓的封闭,内部函数可以访问外部函数的变量
VaR既=我+ this.name + 我+ this.gender + 。;
返回水库;
};
}
因此,在人创建的对象中有以下属性
person.prototype.age = 24;
person.prototype.getage =函数(){
返回this.age;
};
标志=真;
如果(国旗)
{
新的人(塔
警惕(有趣,名字);
警惕(有趣,性别);
警报(fun.whoareyou());
警报(fun.getage());
}
person.prototype.salary = 10000;
person.prototype.getsalary =函数(){
返回this.name +能挣+ this.salary +人民币每个月。;
};
下面是最令人惊奇的地方,/我们改变了人原型,在创造乐趣之后改变了这个原型。
尽管这个更改使乐趣具有相同的属性和方法。
这意味着继承
如果(国旗)
{
警报(fun.getsalary());
警报(乐趣。构造函数。原型。年龄); / /这就相当于你直接打电话给person.prototype.age
警戒(人,原型,年龄);
}
从上面的例子中,我们可以发现,对于原型的方法或属性,我们可以动态地增加,并且由它创建的对象将自动继承相关的方法和属性。
此外,每个对象都有一个构造函数创建的函数对象的属性,如在fun.constructor点的例子是人。
然后自然会出现一个问题,函数对象声明的方法和属性和原型声明的属性有什么区别
有以下差异:
1、自我声明的方法和属性是静态的。也就是说,在声明之后,您尝试添加新的方法或修改现有的方法,而不会影响它们创建的对象,也就是说,继承失败。
2、原型可以动态地添加新的方法或修改现有的方法,但它是动态的。一旦父函数对象声明相关的原型属性,由它创建的对象将自动继承这些原型的属性。
继续上述示例:
标志=真;
方法语句内部函数是静态的,无法传递。
person.school = 与;
person.whoareyou =函数(){
返回zhutao ;
}动态更改声明期,不受对象创建方法的影响,所谓静态
如果(国旗)
{
警戒(人、学校);
警报(有趣的学校);输出未定义
警报(人。whoareyou)(zhutao); / /输出
警报((乐趣。whoareyou)); / /我是Tower,我是一个男。
}
person.prototype.getsalary =函数(){
返回我可以赚1000000美元;
};
如果(国旗)
{
警报((乐趣。getsalary)); / /继承了所谓的动态变化。
}
由于函数对象本身的性质和原型的性质,那么由它创建的对象如何搜索相应的属性呢
基本上,它是在以下过程和顺序中进行的。
1。首先搜索函数对象本身的属性,如果它立即被找到
2、如果找不到1,它将搜索原型属性。有2个结果。如果找到它,它将直接执行,否则它将继续搜索父对象的父对象的原型,直到找到或到达原型链的结尾(结束将是对象对象)。
上述答案如果属性函数对象本身与解决方案的原型属性(name)相同,则对象函数本身是首选的。
原型的典型例子
使用jQuery或原型库的朋友可能知道所有这些库通常都有修剪方法。
实例:
string.prototype.trim =函数(){
返回this.replace( / ^ + | + $ /克,);
};
装饰使用:
foo bar。修剪('foo); / /酒吧
但这样做有一个缺点,因为新版本的浏览器中的Javascript引擎在String对象本身中提供了修剪方法。然后,我们自己定义的修剪将覆盖修剪本身。事实上,在我们定义修剪方法之前,我们可以做一个简单的测试,看看我们是否需要自己添加这个方法:
如果(!字符串.原型.修剪){
string.prototype.trim =函数(){
返回this.replace( / ^ + | + $ /克,);
};
}
原型链
当Javascript定义或实例化任何对象,它将添加一个隐藏属性命名__proto__。原型链是由这个属性形成,但不直接进入__proto__属性,因为有些浏览器不支持直接访问。此外,该__proto__对象和原型的属性是不一样的东西;他们每个人都有各自的用途。
你是怎么理解的事实上,当我们创建一个MyObject的功能,我们实际上创建函数对象类型:
console.log(typeof MyObject); / /功能
这里是解释功能是Javascript中的一个预定义的对象,所以它也有自己的预定义属性(如长度和参数)和方法(如电话申请),并__proto__,当然,从而实现原型链,有可能是一个代码片段像Javascript发动机下面:
function.prototype = { {
参数:null,
长度:0,
调用:函数(){
机密代码
},
应用:函数(){
机密代码
},
…
};
事实上,Javascript引擎代码不能这么简单。下面是对原型链如何工作的描述。
我们定义一个函数MyObject,具有另一个参数的名称,但它不会给任何其他属性,如长度或其他方法,如呼叫。所以为什么下面的代码被执行,正常吗
console.log(MyObject。长度); / /结果:1、多参数
这是因为我们定义的MyObject,又定义了一个__proto__属性,和Function.prototype的价值(指前面的代码片段),所以我们可以访问其他属性的访问myobject.length,即使我们不定义该属性,因为它会跟随__proto__原型链上长度,最后发现在功能。
那么为什么长度属性的值是1,而不是0,什么时候赋值给它呢由于MyObject是函数的一个例子:
console.log(MyObject instanceof功能); / /真的
console.log(MyObject =功能); / /假
当实例化一个对象,该对象的__proto__属性分配给它的构造函数的原型对象。在这种情况下,函数被使用。此时,构造函数返回计算参数的数量并更改长度的值。
console.log(MyObject。__proto__ =函数原型); / /真的
当我们创建一个新的实例与新的关键词,新对象的__proto__将分配到myobject.prototype,因为构造函数是MyObject代替功能。
无功myinstance =新的MyObject('foo);
console.log(myinstance。__proto__ = MyObject。原型); / /真的
除了访问调用,适用于从function.prototype继承,新的对象也可以访问从MyObject继承getName方法:
Console.log((myinstance。getName)); / / Foo
无功mysecondinstance =新的MyObject('bar);
Console.log((mysecondinstance。getName)); / /酒吧
Console.log((myinstance。getName)); / / Foo
事实上,这相当于使用原型对象作为蓝图,然后您可以基于这个蓝图创建N个新对象。
看一个多原型链的例子。
多个原型链实例
职能雇员(姓名)
{
this.name = ;
this.dept =一般;
this.gender =未知;
}
workerbee()函数
{
this.projects = { };
this.hascar = false;
}
workerbee.prototype =新员工; / /原型第一层链
功能工程师()
{
this.dept =工程师; / / 覆盖的父对象
this.language =Javascript;
}
engineer.prototype =新workerbee; / /第二层原型链
Var Jay =新工程师();
如果(国旗)
{
警报(周杰伦);工程师,找到它自己的属性
警报(Jay。hascar); / /假,搜索是一层性能
警报(周杰伦性别);未知,搜索其两层属性
}
上面例子的对象关系如下: