手机版

javascript学习笔记(5)原型和原型链的详细说明

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

私有变量和函数

除非向外部提供接口,即函数的私有变量和函数,否则不能从外部访问函数内部定义的变量和函数。

复制的代码如下:脚本类型=' text/JavaScript '函数test(){ var color=' blue ';//私有变量var fn=function() //私有函数{

} }/脚本

这样,变量color和fn就不能在函数对象Test之外访问,它们变成私有的:

复制代码如下: var obj=new Test();alert(obj . color);//弹出未定义的预警(obj . fn);//同上

静态变量和函数

当定义一个函数时,属性和函数用点“.”来表示仍然可以通过对象本身进行访问,但是不能访问它的实例。这样的变量和函数分别称为静态变量和静态函数。

复制的代码如下:脚本类型=' text/JavaScript '函数obj(){ 0

} Obj.num=72//静态变量Obj.fn=function() //静态函数{

}

alert(Obj . num);//72警报(Obj.fn的类型)//功能

var t=new Obj();alert(t . name);//未定义的警报(t.fn类型);//未定义/脚本

实例变量和函数

在面向对象编程中,除了一些库函数之外,我们在定义对象的时候还是要同时定义一些属性和方法,实例化之后可以访问,JavaScript也可以

复制的代码如下:脚本类型=' text/JavaScript '函数obj () {this。a=[];//实例变量this.fn=function(){ //实例方法

} }

console . log(type of Obj . a);//undefined console . log(type of Obj . fn);//未定义

var o=new Obj();console . log(o . a的类型);//对象console.log(类型为o . fn);//函数/脚本

为实例变量和方法添加新的方法和属性

复制的代码如下:脚本类型=' text/JavaScript '函数obj () {this。a=[];//实例变量this.fn=function(){ //实例方法

} }

var O1=new Obj();O1 . a . push(1);O1 . fn={ };console . log(O1 . a);//[1] console.log(类型为O1 . fn);//对象

var O2=new Obj();console . log(O2 . a);//[]console . log(O2 . fn的类型);//函数/脚本

a和fn在o1中被修饰,但在o2中没有。因为数组和函数既是Objects,也是reference类型,所以它表明,虽然o1中的属性和方法与o2中的属性和方法同名,但它们不是reference,而是obj对象定义的属性和方法的副本。

属性没有问题,但是方法有一个很大的问题,因为方法都在执行完全相同的功能,但是它们被复制成两个副本。如果一个函数对象有几千个实例方法,那么它的每个实例都必须保留几千个方法的副本,这显然是不科学的,这是一个很大的问题。原型应运而生。

基本概念

我们创建的每个函数都有一个原型属性,它是一个指向对象的指针,这个对象的目的是包含特定类型的所有实例都可以共享的属性和方法。然后,prototype是通过调用构造函数创建的对象实例的原型对象。

使用prototype的优点是它允许对象实例共享它包含的属性和方法。也就是说,不需要在构造函数中添加定义对象的信息,但是可以直接添加到原型中。使用构造函数的主要问题是每个方法必须在每个实例中创建一次。

在JavaScript中,有两种类型的值,原始值和对象值。每个对象都有一个内部属性原型,我们通常称之为prototype。原型的值可以是对象或空值。如果它的值是一个对象,那么这个对象也必须有自己的原型。这样就形成了一个线性链,我们称之为原型链。

意义

函数可以用作构造函数。此外,只有函数具有prototype属性并且可以访问它,但是对象实例没有该属性,只有内部不可访问的_ _ prototype _ _属性。__proto__是对象与相关原型之间的神秘链接。按照标准,__proto__是不对外开放的,也就是说是私有财产,但是火狐引擎将其公开为公共财产,我们可以对外访问和设置。

复制的代码如下: Script Type=' text/JavaScript ' var Browser=function(){ };browser . prototype . run=function(){ alert('我是Gecko,firefox'的一个内核);}

var Bro=新浏览器();bro . run();/script

当我们调用Bro.run()方法时,因为Bro中没有这样的方法,所以他会查看自己的__proto_,也就是Browser.prototype,最后执行run()方法。(这里,函数的大写字母都代表构造函数来区分普通函数。)

当调用构造函数创建实例时,实例中将包含一个内部指针(_proto__)来指向构造函数的原型。这种连接存在于实例和构造函数原型之间,但不存在于实例和构造函数之间。

复制的代码如下:脚本类型=' text/JavaScript '函数person (name) {this。name=name}

person . prototype . print name=function(){ alert(this . name);}

var person1=新人(“拜伦”);var person2=新人(' Frank ');/script

Person的Person1实例中包含name属性,自动生成一个__proto__属性,指向Person的原型,可以访问原型中定义的printName方法,大概是这样的:

再举一个栗子:

复制的代码如下:脚本类型=' text/JavaScript '函数animal(name)//累积构造函数{ this.name=name//设置对象属性}

animal . prototype . behavior=function()//向基类构造函数的原型添加一个行为方法{alert('这是一个' this . name ');}

var Dog=新动物(“狗”);//创建狗对象var Cat=新动物('猫');//创建Cat对象

dog . behavior();//通过Dog对象直接调用行为方法cat . behavior();//输出‘这是一只猫’

警惕(狗.行为==猫.行为);//输出为真;/script

从程序的运行结果可以看出,构造函数原型上定义的方法可以直接通过对象调用,代码是共享的。(您可以尝试删除Animal.prototype.behavior中的prototype属性,看看它是否仍然有效。)在这里,原型属性指向Animal对象。

数组对象实例

让我们看一个数组对象的例子。当我们创建对象数组1时,Javascript引擎中数组1的实际对象模型如下:

复制代码如下:var array1=[1,2,3];

array1对象的长度属性值为3,但是我们可以通过以下方式向array1添加元素:

array 1 . push(4);push方法来自array1的__proto__成员指向对象的方法(array . prototey . push())。正是因为所有的数组对象(由[])都包含一个__proto__成员,指向同一个Array.prototype带有push、reverse等方法,这些数组对象才能使用push、reverse等方法。

函数对象示例

复制代码如下:function base () {this。id=' base'}

复制代码如下: var obj=new Base();

这段代码的结果是什么?我们在Javascript引擎中看到的对象模型是:

新接线员到底做了什么?其实很简单。我做了三件事。

复制代码如下: var obj={ };物体。__原型_ _ _=基础.原型;base . call(obj);

原型链

原型链:当从一个对象调用属性或方法时,如果对象没有这样的属性或方法,它将寻找其关联的原型对象,如果原型没有,它将寻找其前身原型,如果没有,它将继续寻找原型引用的对象。原型等等。直到原型。….原型未定义(对象的原型未定义),从而形成所谓的“原型链”。

复制的代码如下:脚本类型=' text/JavaScript '函数shape () {this。名称=' shapethis . ToString=function(){ return this . name;} }函数two shape(){ this . name=' 2 shape ';}函数三角形(边,高){ this.name=' Trianglethis.side=sidethis.height=高度;this . GetArea=function(){ return this . side * this . height/2;} }

two Shape . prototype=new Shape();triangle . prototype=new two shape();/script

这里,使用构造函数Shape()创建了一个新的实体,然后使用它来覆盖对象的原型。

复制的代码如下:脚本类型=' text/JavaScript '函数shape () {this。名称=' shapethis . ToString=function(){ return this . name;} }函数two shape(){ this . name=' 2 shape ';}函数三角形(边,高){ this.name=' Trianglethis.side=sidethis.height=高度;this . GetArea=function(){ return this . side * this . height/2;} }

two Shape . prototype=new Shape();triangle . prototype=new two shape();

two shape . prototype . constructor=two shape;三角形.原型.构造函数=三角形;

var my=新三角(5,10);my . GetArea();my . ToString();//三角形my.constructor//三角形(边,高)/脚本

原型继承

原型继承:原型链的末端是对象构造函数的原型属性所指向的原型对象。这个原型对象是所有对象的祖先,这个祖先实现了所有对象都与生俱来的方法,比如toString。其他内置构造函数的Prototype,比如Function、Boolean、String、Date、RegExp都是从这个祖先继承而来的,但是他们都定义了自己的属性和方法,让自己的后代展现出各自氏族的特点。

在ECMAScript中,继承的方法是通过原型链实现的。

复制的代码如下:脚本类型=' text/JavaScript '函数框(){//继承的函数称为supertype(父类,基类)this.name=' Jack}

function Tree()继承的函数{ //称为subtype(子类,派生类)this.age=300}//由原型链继承,分配给子类型//new Box()的原型属性会将Box结构和原型中的信息给Tree Tree . prototype=new Box();//Tree继承Box,通过原型形成链

var Tree=new Tree();alert(tree . name);//弹出杰克/脚本

原型链的问题:虽然原型链很强大,可以用来继承,但是也有一些问题。最重要的问题来自包含引用类型的值原型。包含引用类型的原型属性由所有实例共享;这就是为什么属性应该在构造函数中定义,而不是原型对象。当通过原型实现继承时,原型实际上变成了另一种类型的实例。因此,原始实例属性成为原型的属性。

创建子类型的实例时,不能将参数传递给超类型的构造函数。实际上,应该说,没有办法在不影响所有对象实例的情况下将参数传递给超类型构造函数。除了刚才讨论的原型中引用类型值引起的问题,原型链在实践中很少单独使用。

再举个栗子:复制代码如下:脚本类型=' text/JavaScript '函数person (name) {this。name=name//设置对象属性};

person . prototype.company=' Microsoft ';//设置原型人物的属性。prototype . say hello=function()//原型{alert ('hello,我是' this.company '的' this.name ')的方法;};

var比尔盖茨=新人('比尔盖茨');//创建人员对象比尔盖茨。sayHello();//继承了原型的内容,输出‘你好,我是微软的比尔盖茨’

var Jobs=新人(' Jobs ');乔布斯公司='苹果';//设置自己的公司属性,掩盖原型公司属性作业。sayhello=function () {alert ('hi,' this . name ' like ' this.company);};乔布斯。sayHello();//自我覆盖的属性和方法,输出‘嗨,像苹果这样的乔布斯’比尔盖茨。say hello();//乔布斯的覆盖不影响原型,比尔盖茨依然输出/脚本

请看下面的原型链示例:

复制的代码如下:脚本类型=' text/JavaScript '函数year () {this。值=21;} year . prototype={ method : function()}

} };

函数Hi(){ 0

};//将实例对象设置为高。prototype=newYear(),其hi的原型属性为yearhi . prototype . year=' Hello World ';

嗨.原型.构造器=嗨;

var测试=new Hi();//创建Hi的新实例

//原型链测试[Hi的Hi实例] Hi.prototype [Year的Year实例]{ Year : ' hello world ' } Year . prototype { method :};object.prototype {toString:};

/script

从上面的例子来看,测试对象继承自Hi.prototype和Year.prototype因此,他可以访问Year的原型方法,同时可以访问实例属性值

__ptoto__属性

__ptoto__属性(IE浏览器不支持)是实例指向原型对象的指针,其作用是指向构造函数的原型属性构造函数。通过这两个属性,您可以访问原型中的属性和方法。

Javascript中的对象实例本质上由一系列属性组成。在这些属性中,有一个不可见的特殊属性——__proto__,它的值指向对象实例的原型,一个对象实例只有一个唯一的原型。

复制的代码如下:脚本类型=' text/JavaScript ' function box(){//大写,表示构造函数box . prototype . name=' trig kit 4 ';//原型属性box . prototype . age=' 21 ';box . prototype . run=function()//prototype方法{ return this . name this . age ' studing ';} }

var Box 1=new Box();var Box 2=new Box();alert(box 1 . constructor);//构造属性,可以得到构造函数本身。//函数要由原型指针定位,然后得到构造函数本身/脚本

__proto__属性和原型属性之间的区别

原型是函数对象的一个特殊性质。__proto__是普通对象的隐式属性,新建时会指向prototype指向的对象;__ptoto__实际上是实体对象的属性,而prototype是属于构造函数的属性。__ptoto__只能在学习或调试环境中使用。

原型模式的执行流程

1.首先在构造函数实例中找到属性或方法,如果有,立即返回。2.如果没有构造函数的实例,查看它的原型对象,如果有,立即返回它

原型对象的

复制的代码如下:脚本类型=' text/JavaScript ' function box(){//大写,表示构造函数box . prototype . name=' trig kit 4 ';//原型属性box . prototype . age=' 21 ';box . prototype . run=function()//prototype方法{ return this . name this . age ' studing ';} }

var Box 1=new Box();alert(box 1 . name);//trigkit4,原型中的值box 1 . name=' Lee ';alert(box 1 . name);//李,说吧

var Box 2=new Box();alert(box 2 . name);//原型的值trigkit4没有被box1 /script修改

建造商的

复制的代码如下:脚本类型=' text/JavaScript ' function box(){ this。名称=' bill}

box . prototype . name=' trig kit 4 ';//原型属性box . prototype . age=' 21 ';box . prototype . run=function()//prototype方法{ return this . name this . age ' studing ';}

var Box 1=new Box();alert(box 1 . name);//Bill,原型框中的值1 . name=' Lee ';alert(box 1 . name);//李,把原理/剧本提前就好

版权声明:javascript学习笔记(5)原型和原型链的详细说明是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。