宝哥软件园

对JavaScript中原型的深入研究

编辑:宝哥软件园 来源:互联网 时间:2021-09-08

Javascript是一种基于原型的编程语言,与我们通常的基于类的编程有很大不同。我列出一些要点如下:

1.函数是第一类对象,这意味着函数和对象具有相同的语言状态。2.没有类,只有对象。3.函数也是一个对象,所谓函数对象。4.对象通过引用传递。那么,这种基于原型的编程语言如何继承(OO的一个基本元素),这就是原型的起源。

请看下面的代码片段:

函数foo(a,b,c){返回a * b * c;} alert(foo . length);alert(foo . constructor的类型);alert(foo . call的类型);alert(foo . apply类型);alert(foo . prototype的类型);对于上面的代码,用浏览器运行后会发现:

1.length:提供函数的参数数量。2.prototype:是对象3。3.另外三个是函数。对于任何函数声明,它都将具有上述五个属性(方法或属性)。

下面我们主要看原型。

//prototypefunction Person(姓名、性别){ this.name=namethis.gender=性别;This . whoi you=function(){//这也叫闭包。内部函数可以访问变量var res='我'这个。名字'而我是'这个。性别。外部函数的。返回res};}//那么Person创建的对象具有以下属性:Person . prototype . age=24;person . prototype . GetAge=function(){ return this . age;};flag=trueif(flag){ var fun=new Person(' Tower ','雄');alert(fun . name);alert(fun . gender);警惕(有趣。你是谁());alert(fun . GetAge());} person . prototype . salary=10000;person . prototype . getsalary=function(){ return this . name '每个月能赚大概' this.salary '人民币。};//以下是最神奇的地方。我们改变了Person的原型,这个改变是在创造了乐趣之后。//而这个变化让好玩有了相同的属性和方法。//继承的意义就是这个if(flag){ alert(fun . getsalary());alert(fun . constructor . prototype . age);//而这相当于直接调用person . prototype . age alert(person . prototype . age);}从上面的例子可以发现,我们可以动态添加prototype的方法或属性,prototype创建的对象会自动继承相关的方法和属性。

此外,每个对象都有一个构造函数属性,用于指向创建它的函数对象。在上面的例子中,fun.constructor指向Person。

那么一个问题自然就产生了。函数对象声明的方法和属性与原型声明的对象有什么区别?

有以下区别:

1.自声明的方法和属性是静态的,也就是说在声明之后,尝试添加新的方法或者修改现有的方法,不会影响它们创建的对象,也就是继承失败。2.prototype可以动态添加新方法或修改现有方法,这是动态的。一旦父函数对象声明了相关的原型属性,它创建的对象将自动继承这些原型属性。继续上面的例子33366。

flag=true//函数内部声明的方法是静态的,不能传递。Person.school=' ISCASperson . whole you=function(){返回“祝焘”;};//动态改变申报周期的方法不会影响其创建对象的方法,即所谓的静态if(flag){ alert(person . school);alert(fun . school);//输出是“未定义”警报(person。你是谁());//输出Zhu Tao alert(fun . whoiyou());//我是塔,我是男的。} person . prototype . getsalary=function(){ return '我能赚1000000 USD ';};if(flag){ alert(fun . getsalary());//变化是继承的,也就是所谓的动态。}既然函数对象本身和原型都有属性,那么它创建的对象如何搜索对应的属性呢?

基本上是按照以下的流程和顺序进行的。

1.首先搜索函数Object本身的属性,如果找到就立即执行。2.如果找不到1,它将搜索原型属性。如果找到,直接执行。否则,继续搜索父对象的父对象的原型,直到找到,或者到达原型链的末端(末端将是对象)。如果函数对象本身的属性与原型属性(同名)、函数本身相同,上面也给出了解决方案

原型的典型示例

使用过jQuery或Prototype库的朋友可能知道,这些库通常都有trim方法。

示例:

string . prototype . trim=function(){ return this.replace(/^s | s $/g ' ');};修剪用法:

foo bar。trim();//‘foo bar’,但这有另一个缺点,因为新版浏览器中的JavaScript引擎本身在String对象中提供了trim方法,所以我们自己定义的trim会覆盖它自己的trim。实际上,在定义trim方法之前,我们可以做一个简单的测试,看看是否需要自己添加这个方法:

if(!string . prototype . trim){ string . prototype . trim=function(){ return this.replace(/^s | s $/g ' ');};}原型链

在JavaScript中定义或实例化任何对象时,都会附加一个名为__proto__的隐藏属性,原型链就是由这个属性形成的。但是不要直接访问__proto__属性,因为有些浏览器不支持直接访问它。此外,__proto__与对象的原型属性不一样,它们有各自的用途。

怎么理解?实际上,当我们创建myObject函数时,我们实际上创建了一个函数类型的对象:

console . log(my object的类型);//函数

这里需要说明的是,Function是JavaScript中的预定义对象,所以它也有自己的预定义属性(比如长度和参数)和方法(比如call和apply),当然也有__proto__,从而实现原型链。也就是说,在JavaScript引擎中可能有类似于以下内容的代码片段:

function . prototype={ arguments 3360 null,length: 0,call : function(){//secret code },apply : function(){//secret code },};事实上,JavaScript引擎代码不可能那么简单,所以这里只是描述一下原型链是如何工作的。

我们定义了一个函数myObject,它也有一个参数名,但是没有给它任何其他属性,比如长度或者其他方法,比如call。那么为什么下面的代码可以正常执行呢?

console . log(myobject . length);//结果:1是参数的个数。这是因为我们在定义myObject的时候,也为它定义了一个__proto__属性,并将其赋值为Function.prototype(参考前面的代码片段),这样我们就可以像访问其他属性一样访问myObject.length,即使我们没有定义这个属性,因为它会遵循__proto__ prototype链来查找长度。

那么为什么长度属性的值是1而不是0,是什么时候赋值的呢?因为我的对象是函数的一个实例:

console.log(函数的myObject实例);//true console . log(myObject===Function);//false实例化对象时,对象的__proto__属性将被分配为其构造函数的原型对象,在本例中为Function。此时,构造函数返回来计算参数的数量,并更改长度的值。

console.log(myObject。_ _ proto _ _===function . prototype);//真。当我们用new关键字创建一个新实例时,新对象的__proto__将被分配为myObject.prototype,因为当前的构造函数是myObject,而不是Function。

var myInstance=new myObject(' foo ');console.log(我的实例。_ _ proto _ _===myobject . prototype);//true新对象不仅可以访问从Function.prototype继承的调用和应用,还可以访问从myObject继承的getName方法:

控制台。日志(我的实例。GetName());//foo var my second instance=new myObject(' bar ');控制台。日志(我的第二个实例。getname());//吧台控制台。日志(我的实例。GetName());//foo其实这相当于把原型对象当做一个蓝本,然后可以根据这个蓝本创建普通个新的对象。

再看一个多重原型链的例子:

//多重原型链的例子函数员工(姓名){这个。名称=' ';this.dept=' generalthis.gender='未知;} function WorkerBee(){ this。项目=[];this . hascar=false } worker bee . prototype=新员工;//第一层原型链函数工程师(){ this.dept=' engineer//覆盖了'父对象this.language=' javascript}工程师。原型=new WorkerBee//第二层原型链var jay=新工程师(‘杰’);if(flag){ alert(Jay。部门);//工程师,找到的是自己的属性警惕(杰。HasCar);//false,搜索到的是自己上一层的属性警惕(杰。性别);//未知,搜索到的是自己上二层的属性}上面这个示例的对象关系如下:

201581395745486.jpg  (222362)

更多资讯
游戏推荐
更多+