javascript中的每个对象都有一个内置的属性原型。Javascript中原型属性的解释是返回对象类型原型的引用。这意味着原型属性保存了对另一个JavaScript对象的引用,该对象是当前对象的父对象。复制代码如下: a . prototype=new B();理解原型不应将其与继承混淆。A的原型是b的一个实例,可以理解为A克隆了b中的所有方法和属性,A可以使用b的方法和属性,这里强调的是克隆而不是继承。有可能a的原型是b的实例,而b的原型也是a的实例.
继续看下面的分析:
私有变量和函数。
除非向外部提供接口,即函数的私有变量和函数,否则不能从外部访问函数内部定义的变量和函数。复制的代码如下: script type=' text/JavaScript ' function box(){ var color=' blue ';//私有变量var fn=function() //私有函数{。
} }/script使变量color和fn不能在函数对象Box之外访问,它们变成私有的:复制代码如下: var obj=new Box();alert(obj . color);//弹出未定义的预警(obj . fn);//同上
静态变量和函数。
当定义一个函数时,属性和函数用点“.”来表示仍然可以通过对象本身进行访问,但是不能访问它的实例。这样的变量和函数分别称为静态变量和静态函数。
复制的代码如下:脚本类型=' text/JavaScript '函数obj(){ };
Obj.num=72//静态变量Obj.fn=function() //静态函数{。
}
alert(Obj . num);//72警报(Obj.fn的类型)//功能
var t=new Obj();alert(t . name);//未定义的警报(t.fn类型);//未定义/脚本
示例和功能。
在面向对象编程中,除了一些库函数之外,我们在定义对象的时候还是要同时定义一些属性和方法,实例化之后就可以访问了。js也可以复制代码如下: Script Type=' text/JavaScript ' Function Box(){ this。a=[];//实例变量this.fn=function(){ //实例方法。
} }
控制台日志(Box.a的类型);//未定义的console.log(类型为Box . fn);//未定义
var Box=new Box();console . log(box . a的类型);//对象console . log(box . fn的类型);//函数/脚本
为实例变量和方法添加新的方法和属性。复制代码如下:脚本类型=' text/JavaScript ' Function Box(){ this。a=[];//实例变量this.fn=function(){ //实例方法。
} }
var Box 1=new Box();box 1 . a . push(1);box 1 . fn={ };console . log(box 1 . a);//[1]console . log(box 1 . fn的类型);//对象
var Box 2=new Box();console . log(box 2 . a);//[]console . log(box 2 . fn的类型);//函数/脚本
a和fn在Box1中进行了修改,但在box2中没有。由于数组和函数既是对象又是引用类型,因此它表明,尽管box1中的属性和方法与box2中的属性和方法同名,但它们不是引用,而是box对象定义的属性和方法的副本。
这对于属性来说不是问题,但是对于方法来说是一个大问题,因为方法都在执行完全相同的功能,但是它们被复制成两个副本。如果一个函数对象有几千个实例方法,那么它的每个实例都必须保留几千个方法的副本,这显然是不科学的,这是一个很大的问题。原型应运而生。
基本概念
我们创建的每个函数都有一个原型属性,它是一个指向对象的指针。此对象的目的是包含可由特定类型的所有实例共享的属性和方法。然后,prototype是通过调用构造函数创建的对象实例的原型对象。
使用原型的优点是对象实例可以共享它包含的属性和方法。也就是说,不需要在构造函数中添加定义对象的信息,但是可以直接添加到原型中。使用构造函数的主要问题是每个方法必须在每个实例中创建一次。
在JavaScript中,有两种类型的值,原始值和对象值。每个对象都有一个内部属性原型,我们通常称之为prototype。原型的值可以是对象或空值。如果它的值是一个对象,该对象也必须有自己的原型。这就形成了一个线性链,我们称之为原型链。
意义
函数可以用作构造函数。此外,只有函数具有prototype属性并且可以访问它,但是对象实例没有该属性,只有内部不可访问的_ _ prototype _ _属性。__proto__是对象中与相关原型的神秘链接。按照标准,__proto__是不对外开放的,也就是说是私有财产,但是火狐引擎已经把它暴露为公共财产,我们可以对外访问和设置。复制的代码如下:脚本类型=' 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()//prototype对象{ alert(this . name);}
var person1=新人(“拜伦”);//实例化对象console.log(person1。_ _ proto _ _);//Person console . log(Person 1 . constructor);//自己试试。控制台.日志(person . prototype);//指向原型对象person var person 2=new person(' frank ');名称属性包含在/scriptPerson的Person1实例中,同时自动生成一个__proto__属性,指向Person的原型,可以访问原型中定义的printName方法,大概是这样的:
每个JavaScript函数都有一个原型属性,它引用一个对象,这个对象就是一个原型对象。当原型被初始化时,它是空的,我们可以自定义其中的任何属性和方法,这些属性和方法将被构造函数创建的对象继承。
所以,现在问题来了。构造函数、实例和原型对象之间是什么关系?
构造函数、实例和原型对象之间的区别。
实例是通过构造函数创建的。一旦创建了实例,它就有一个构造函数属性(指向构造函数)和一个__proto__属性(指向原型对象)。
构造函数中有一个原型属性,它是指向其原型对象的指针。
原型对象中还有一个指向构造函数:person的指针(构造函数属性)。原型.构造者=人;
实例可以访问原型对象上定义的属性和方法。
这里person1和person2是例子,prototype是它们的原型对象。
再举个栗子:复制代码如下: script type=' 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对象。
数组实例
让我们看一个数组对象的例子。我们在创建对象array1时,Javascript引擎中array1的实际对象模型如下:复制代码如下:var array1=[1,2,3];
array1对象的长度属性值为3,但是我们可以通过以下方法向array1添加元素:复制代码如下: array 1 . push(4);push方法来自array1的__proto__成员指向对象的方法(array . prototey . push())。正是因为所有数组对象(由[])都包含一个__proto__成员,用推、反等方法指向同一个对象(Array.prototype),这些数组对象才能使用推、反等方法。
函数实例复制代码如下:function base () {this。id=' base'}
复制代码如下: var obj=new Base();这段代码的结果是什么?我们在Javascript引擎中看到的对象模型是:
新接线员到底做了什么?其实很简单。我做了三件事。复制的代码如下: var obj={ };物体。__原型_ _ _=基础.原型;base . call(obj);
原型链
原型链:从对象调用属性或方法时,如果对象本身没有这样的属性或方法,它会寻找与之关联的原型对象;如果原型没有,它会寻找它的前身原型;如果没有,它将继续寻找Prototype引用的对象。原型等等。直到原型。….原型未定义(对象的原型未定义),从而形成所谓的“原型链”。
复制的代码如下:脚本类型=' 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中,继承的方法依赖于原型链。复制的代码如下: script type=' text/JavaScript ' function box(){//继承的函数称为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 ';//设置property person . 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();//对//Jobs的覆盖并没有影响原型,所以比尔盖茨还是输出/脚本。
请看下面的原型链示例:
复制的代码如下:脚本类型=' 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.如果没有构造函数的实例,请查看它的原型对象,如果有,请立即返回它。
原型对象的复制代码如下: script type=' 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,原型框1.name='Lee '中的值;alert(box 1 . name);//李,说吧。
var Box 2=new Box();alert(box 2 . name);//原型的值trigkit4没有被box1 /script修改。
构造函数的复制代码如下: script type=' 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);//李,只需输入原理/脚本。
总结一下,整理一下:复制的代码如下: script type=' text/JavaScript ' function person(){ };
person . prototype . name=' trig kit 4 ';person . prototype . say=function(){ alert('hi');}
var p1=新人员();//prototype是p1和p2的原型对象var p2=new Person();//p2是内部带有_ _ prototype _ _属性的实例化对象,指向Person的原型。
console . log(P1 . prototype);//未定义,该属性为对象,无法访问console . log(person . prototype);//Person console . log(Person . prototype . constructor);//原型对象内部还有一个指针(构造函数属性),指向构造函数控制台。_ _ proto _ _);//这个属性是一个指向原型对象p1.say()的指针;//实例可以访问原型对象上定义的属性和方法。
/script
工厂复制代码如下:函数createobject (name,age){ varobj=new object();obj.name=name年龄=年龄;返回对象;}
该模式解决了实例化对象重复无数的问题,但还有一个问题,那就是无法找出它们是哪些对象实例。构造函数的方法不仅解决了重复实例化的问题,还解决了对象识别的问题。
使用构造函数的方法与工厂模式的不同之处在于:
1.构造函数方法不显示创建对象(new Object());2.将属性和方法直接分配给这个对象。没有退货单。
当使用构造函数并使用新的构造函数()时,则在后台执行new object();这在函数体中表示来自新对象()的对象。
1.判断属性是在构造函数的实例中还是在原型中,可以使用` hasOwnProperty()`函数。2.以文字创建的方式使用构造函数属性。它将指向对象,而不是指向实例。为什么构造函数以相反的方式指向一个对象?因为盒子;原型={ };这篇文章实际上是在创造一个新的对象。每次创建一个函数,都会同时创建它的原型,这个对象会自动获取构造函数属性。3.如果它是一个实例方法,它的方法地址是不同的,并且对于不同的实例化是唯一的。4.如果是原型方法,它的地址是共享的。