原型课堂 零基础之路和基础一样吗,,

原型批评/原型批评
是20世纪五六十年代流行于的一个十分的。其主要是加拿大的。不少认为,原型批评曾一度与批评和精神分析批评在起过“”的作用。
原型批评的理论基础/原型批评
主要是的学说和的理论。在批评时间中,原型批评试图发现文学作品中反复出现的各种意象、叙事结构和人物类型,找出她们背后的基本形式。批评家强调作品中的神话类型,认为这些深化同具体的作品比较起来是更基本的原型,并把一系列原型广泛应用于对作品的分析、阐释和评价。原型批评在20世纪60年代达到高潮,对文学研究产生了很大的影响。然而自70年代以后,原型批评的理论与方法随着批评的兴起而逐渐失去其影响。近年来国内外文学批评界有人试图从其他角度对原型批评进行重新解读、阐释和重构,研究它与文化研究及其他当代批评理论的关系,尤其是其整体性文化批评倾向及其对当前颇为盛行的文化批评的启蒙影响等问题。
&|&相关影像
互动百科的词条(含所附图片)系由网友上传,如果涉嫌侵权,请与客服联系,我们将按照法律之相关规定及时进行处理。未经许可,禁止商业网站等复制、抓取本站内容;合理使用者,请注明来源于。
登录后使用互动百科的服务,将会得到个性化的提示和帮助,还有机会和专业认证智愿者沟通。
此词条还可添加&
编辑次数:3次
参与编辑人数:3位
最近更新时间: 21:57:00
贡献光荣榜JavaScript中原型和原型链详解
投稿:junjie
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了JavaScript中原型和原型链详解,本文讲解了私有变量和函数、静态变量和函数、实例变量和函数、原型和原型链的基本概念,需要的朋友可以参考下
javascript中的每个对象都有一个内置的属性prototype,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。意思是是prototype属性保存着对另一个JavaScript对象的引用,这个对象作为当前对象的父对象。
A.prototype = new B();
理解prototype不应把它和继承混淆。A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。A能使用B的方法和属性。这里强调的是克隆而不是继承。可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。
继续看下面的分析:
私有变量和函数
在函数内部定义的变量和函数,如果不对外提供接口,外部是无法访问到的,也就是该函数的私有的变量和函数。
&script type="text/javascript"&
&&& function Box(){
&&&&&&& var color = "blue";//私有变量
&&&&&&& var fn = function() //私有函数
这样在函数对象Box外部无法访问变量color和fn,他们就变成私有的了:
var obj = new Box();
&&& alert(obj.color);//弹出 undefined
&&& alert(obj.fn);//同上
静态变量和函数
当定义一个函数后通过点号 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数。
&script type="text/javascript"&
&&& function Obj(){};
&&& Obj.num = 72;//静态变量
&&& Obj.fn = function()& //静态函数
&&& alert(Obj.num);//72
&&& alert(typeof Obj.fn)//function
&&& var t = new Obj();
&&& alert(t.name);//undefined
&&& alert(typeof t.fn);//undefined
实例变量和函数
在面向对象编程中除了一些库函数我们还是希望在对象定义的时候同时定义一些属性和方法,实例化后可以访问,js也能做到这样
&script type="text/javascript"&
&&&&&&&&& function Box(){
&&&&&&&&&&&&&&& this.a=[]; //实例变量
&&&&&&&&&&&&&&& this.fn=function(){ //实例方法
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&&&&&& console.log(typeof Box.a); //undefined
&&&&&&&&&&& console.log(typeof Box.fn); //undefined
&&&&&&&&&&& var box=new Box();
&&&&&&&&&&& console.log(typeof box.a); //object
&&&&&&&&&&& console.log(typeof box.fn); //function
为实例变量和方法添加新的方法和属性
&script type="text/javascript"&
function Box(){
&&&&&&&&&&&&&&& this.a=[]; //实例变量
&&&&&&&&&&&&&&& this.fn=function(){ //实例方法
&&&&&&&&&&&&&&& }
&&&&&&&&&&& }
&&&&&&&&&&& var box1=new Box();
&&&&&&&&&&& box1.a.push(1);
&&&&&&&&&&& box1.fn={};
&&&&&&&&&&& console.log(box1.a); //[1]
&&&&&&&&&&& console.log(typeof box1.fn); //object
&&&&&&&&&&& var box2=new Box();
&&&&&&&&&&& console.log(box2.a); //[]
&&&&&&&&&&& console.log(typeof box2.fn); //function
在box1中修改了a和fn,而在box2中没有改变,由于数组和函数都是对象,是引用类型,这就说明box1中的属性和方法与box2中的属性与方法虽然同名但却不是一个引用,而是对Box对象定义的属性和方法的一个复制。
这个对属性来说没有什么问题,但是对于方法来说问题就很大了,因为方法都是在做完全一样的功能,但是却又两份复制,如果一个函数对象有上千和实例方法,那么它的每个实例都要保持一份上千个方法的复制,这显然是不科学的,这可肿么办呢,prototype应运而生。
我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。那么,prototype就是通过调用构造函数而创建的那个对象实例的原型对象。
使用原型的好处是可以让对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中添加定义对象信息,而是可以直接将这些信息添加到原型中。使用构造函数的主要问题就是每个方法都要在每个实例中创建一遍。
在JavaScript中,一共有两种类型的值,原始值和对象值。每个对象都有一个内部属性 prototype ,我们通常称之为原型。原型的值可以是一个对象,也可以是null。如果它的值是一个对象,则这个对象也一定有自己的原型。这样就形成了一条线性的链,我们称之为原型链。
函数可以用来作为构造函数来使用。另外只有函数才有prototype属性并且可以访问到,但是对象实例不具有该属性,只有一个内部的不可访问的__proto__属性。__proto__是对象中一个指向相关原型的神秘链接。按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,我们可以对外访问和设置。
&script type="text/javascript"&
&&& var Browser = function(){};
&&& Browser.prototype.run = function(){
&&&&&&& alert("I'm Gecko,a kernel of firefox");
&&& var Bro = new Browser();
&&& Bro.run();
当我们调用Bro.run()方法时,由于Bro中没有这个方法,所以,他就会去他的__proto__中去找,也就是Browser.prototype,所以最终执行了该run()方法。(在这里,函数首字母大写的都代表构造函数,以用来区分普通函数)
当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(__proto__)指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。
&script type="text/javascript"&
function Person(name){&&&&&&&&&&&&&&&&&&&&&&&&&&&& //构造函数
&&&&&&&&&&&&&&& this.name=
&&&&&&&&&&& }
&&&&&&&&&&& Person.prototype.printName=function() //原型对象
&&&&&&&&&&& {
&&&&&&&&&&&&&&& alert(this.name);
&&&&&&&&&&& }
&&&&&&&&&&& var person1=new Person('Byron');//实例化对象
&&&&&&&&&&& console.log(person1.__proto__);//Person
&&&&&&&&&&& console.log(person1.constructor);//自己试试看会是什么吧
&&&&&&&&&&& console.log(Person.prototype);//指向原型对象Person
&&&&&&&&&&& var person2=new Person('Frank');
Person的实例person1中包含了name属性,同时自动生成一个__proto__属性,该属性指向Person的prototype,可以访问到prototype内定义的printName方法,大概就是这个样子的:
每个JavaScript函数都有prototype属性,这个属性引用了一个对象,这个对象就是原型对象。原型对象初始化的时候是空的,我们可以在里面自定义任何属性和方法,这些方法和属性都将被该构造函数所创建的对象继承。
那么,现在问题来了。构造函数、实例和原型对象三者之间有什么关系呢?
构造函数、实例和原型对象的区别
实例就是通过构造函数创建的。实例一创造出来就具有constructor属性(指向构造函数)和__proto__属性(指向原型对象),
构造函数中有一个prototype属性,这个属性是一个指针,指向它的原型对象。
原型对象内部也有一个指针(constructor属性)指向构造函数:Person.prototype.constructor = P
实例可以访问原型对象上定义的属性和方法。
在这里person1和person2就是实例,prototype是他们的原型对象。
再举个栗子:
&script type="text/javascript"&
&&& function Animal(name)&& //积累构造函数
&&&&&&& this.name =//设置对象属性
&&& Animal.prototype.behavior = function() //给基类构造函数的prototype添加behavior方法
&&&&&&& alert("this is a "+this.name);
&&& var Dog = new Animal("dog");//创建Dog对象
&&& var Cat = new Animal("cat");//创建Cat对象
&&& Dog.behavior();//通过Dog对象直接调用behavior方法
&&& Cat.behavior();//output "this is a cat"
&&& alert(Dog.behavior==Cat.behavior);//
可以从程序运行结果看出,构造函数的prototype上定义的方法确实可以通过对象直接调用到,而且代码是共享的。(可以试一下将Animal.prototype.behavior 中的prototype属性去掉,看看还能不能运行。)在这里,prototype属性指向Animal对象。
数组对象实例
再看个数组对象的实例。当我们创建出array1这个对象的时候,array1实际在Javascript引擎中的对象模型如下:
var array1 = [1,2,3];
array1对象具有一个length属性值为3,但是我们可以通过如下的方法来为array1增加元素:
array1.push(4);
push这个方法来自于array1的__proto__成员指向对象的一个方法(Array.prototye.push())。正是因为所有的数组对象(通过[]来创建的)都包含有一个指向同一个具有push,reverse等方法对象(Array.prototype)的__proto__成员,才使得这些数组对象可以使用push,reverse等方法。
函数对象实例
function Base() {&
&&& this.id = "base"
var obj = new Base();
这样代码的结果是什么,我们在Javascript引擎中看到的对象模型是:
new操作符具体干了什么呢?其实很简单,就干了三件事情。
var obj& = {};&
obj.__proto__ = Base.&
Base.call(obj);
原型链:当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找Prototype.Prototype引用的对象,依次类推,直到Prototype.….Prototype为undefined(Object的Prototype就是undefined)从而形成了所谓的“原型链”。
&script type="text/javascript"&
&&& function Shape(){
&&&&&&& this.name = "shape";
&&&&&&& this.toString = function(){
&&&&&&&&&&& return this.
&&& function TwoShape(){
&&&&&&& this.name = "2 shape";
&&& function Triangle(side,height){
&&&&&&& this.name = "Triangle";
&&&&&&& this.side =
&&&&&&& this.height =
&&&&&&& this.getArea = function(){
&&&&&&&&&&& return this.side*this.height/2;
&&& TwoShape.prototype = new Shape();
&&& Triangle.prototype = new TwoShape();
这里,用构造器Shape()新建了一个实体,然后用它去覆盖该对象的原型。
&script type="text/javascript"&
&&& function Shape(){
&&&&&&& this.name = "shape";
&&&&&&& this.toString = function(){
&&&&&&&&&&& return this.
&&& function TwoShape(){
&&&&&&& this.name = "2 shape";
&&& function Triangle(side,height){
&&&&&&& this.name = "Triangle";
&&&&&&& this.side =
&&&&&&& this.height =
&&&&&&& this.getArea = function(){
&&&&&&&&&&& return this.side*this.height/2;
&&& TwoShape.prototype = new Shape();
&&& Triangle.prototype = new TwoShape();
&&& TwoShape.prototype.constructor = TwoS
&&& Triangle.prototype.constructor = T
&&& var my = new Triangle(5,10);
&&& my.getArea();
&&& my.toString();//Triangle
&&& my.//Triangle(side,height)
原型继承:在原型链的末端,就是Object构造函数prototype属性指向的那个原型对象。这个原型对象是所有对象的祖先,这个老祖宗实现了诸如toString等所有对象天生就该具有的方法。其他内置构造函数,如Function,Boolean,String,Date和RegExp等的prototype都是从这个老祖宗传承下来的,但他们各自又定义了自身的属性和方法,从而他们的子孙就表现出各自宗族的那些特征。
ECMAScript中,实现继承的方法就是依靠原型链实现的。
&script type="text/javascript"&
&&& function Box(){&&&&&&&&&&&& //被继承的函数叫做超类型(父类,基类)
&&&&&&& this.name = "Jack";
&&& function Tree(){&&&&&&&&& //继承的函数叫做子类型(子类,派生类)
&&&&&&& this.age = 300;
&&& //通过原型链继承,赋值给子类型的原型属性
&&& //new Box()会将box构造里的信息和原型里的信息都交给Tree
&&& Tree.prototype = new Box();//Tree继承了Box,通过原型,形成链条
&&& var tree = new Tree();
&&& alert(tree.name);//弹出 Jack
原型链的问题:原型链虽然很强大,可以用它来实现继承,但它也存在一些问题。其中最主要的问题来自包含引用类型的值原型。包含引用类型的原型属性会被所有实例共享;而这也正是为什么要在构造函数中,而不是在原型对象中定义属性的原因。在通过原型来实现继承时,原型实际上回变成另一个类型的实例。于是,原先的实例属性也就变成了原型的属性。
在创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。再加上刚刚讨论的由于原型中包含引用类型值所带来的问题,实践中很少会单独使用原型链。
再举个栗子:
&script type="text/javascript"&
&&& function Person(name)
&&&&&&& this.name =//设置对象属性
&&& pany = "Microsoft";//设置原型的属性
&&& Person.prototype.SayHello = function() //原型的方法
&&&&&&& alert("Hello,I'm "+ this.name+ " of " + pany);
&&& var BillGates = new Person("BillGates");//创建person对象
&&& BillGates.SayHello();//继承了原型的内容,输出"Hello,I'm BillGates of Microsoft"
&&& var Jobs = new Person("Jobs");
&&& pany = "Apple";//设置自己的company属性,掩盖了原型的company属性
&&& Jobs.SayHello = function()
&&&&&&& alert("Hi,"+this.name + " like " + pany);
&&& Jobs.SayHello();//自己覆盖的属性和方法,输出"Hi,Jobs like Apple"
&&& BillGates.SayHello();//Jobs的覆盖没有影响原型,BillGates还是照样输出
看下面一个原型链例子:
&script type="text/javascript"&
&&& function Year(){
&&&&&&& this.value = 21;
&&& Year.prototype = {
&&&&&&& method:function(){
&&& function Hi(){
&&& //设置Hi的prototype属性为Year的实例对象
&&& Hi.prototype = new Year();
&&& Hi.prototype.year = 'Hello World';
&&& Hi.prototype.constructor = Hi;
&&& var test = new Hi();//创建一个Hi的新实例
&&& //原型链
&&& test [Hi的实例]
&&&&&&& Hi.prototype [Year的实例]
&&&&&&&&&&& {year:'Hello World'}
&&&&&&&&&&& Year.prototype
&&&&&&&&&&&&&&& {method:……};
&&&&&&&&&&&&&&& object.prototype
&&&&&&&&&&&&&&&&&&& {toString:...};
从上面例子中,test对象从Hi.prototype和Year.prototype中继承下来;因此他能访问Year的原型方法method,同时他能访问实例属性value
__ptoto__属性
__ptoto__属性(IE浏览器不支持)是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性constructor,通过这两个属性,就可以访问原型里的属性和方法了。
Javascript中的对象实例本质上是由一系列的属性组成的,在这些属性中,有一个内部的不可见的特殊属性——__proto__,该属性的值指向该对象实例的原型,一个对象实例只拥有一个唯一的原型。
&script type="text/javascript"&
&&& function Box(){&&&&&&& //大写,代表构造函数
&&&&&&& Box.prototype.name = "trigkit4";//原型属性
&&&&&&& Box.prototype.age = "21";
&&&&&&& Box.prototype.run = function()//原型方法
&&&&&&& {&
&&&&&&&&&&& return this.name + this.age + 'studying';
&&& var box1 = new Box();
&&& var box2 = new Box();
&&& alert(box1.constructor);//构造属性,可以获取构造函数本身,
&&&&&&&&&&&&&&&&&&&&&&&&&&& //作用是被原型指针定位,然后得到构造函数本身
&/script&&&
__proto__属性和prototype属性的区别
prototype是function对象中专有的属性。
__proto__是普通对象的隐式属性,在new的时候,会指向prototype所指的对象;
__ptoto__实际上是某个实体对象的属性,而prototype则是属于构造函数的属性。__ptoto__只能在学习或调试的环境下使用。
原型模式的执行流程
1.先查找构造函数实例里的属性或方法,如果有,就立即返回。
2.如果构造函数的实例没有,就去它的原型对象里找,如果有,就立即返回
原型对象的
&script type="text/javascript"&
&&& function Box(){&&&&&&& //大写,代表构造函数
&&&&&&& Box.prototype.name = "trigkit4";//原型属性
&&&&&&& Box.prototype.age = "21";
&&&&&&& Box.prototype.run = function()//原型方法
&&&&&&& {&
&&&&&&&&&&& return this.name + this.age + 'studying';
&&& var box1 = new Box();
&&& alert(box1.name);//trigkit4,原型里的值
&&& box1.name = "Lee";
&&& alert(box1.name);//Lee,就进原则
&&& var box2 = new Box();
&&& alert(box2.name);//trigkit4,原型的值,没有被box1修改
构造函数的
&script type="text/javascript"&
&&& function Box(){&&&&&&&&&&&&&&&&
&&&&&&& this.name = "Bill";
&&& Box.prototype.name = "trigkit4";//原型属性
&&& Box.prototype.age = "21";
&&& Box.prototype.run = function()//原型方法
&&&&&&&&&&& return this.name + this.age + 'studying';
&&& var box1 = new Box();
&&& alert(box1.name);//Bill,原型里的值
&&& box1.name = "Lee";
&&& alert(box1.name);//Lee,就进原则
综上,整理一下:
&script type="text/javascript"&
&&& function Person(){};
&&& Person.prototype.name = "trigkit4";
&&& Person.prototype.say = function(){
&&&&&&& alert("Hi");
&&& var p1 = new Person();//prototype是p1和p2的原型对象
&&& var p2 = new Person();//p2为实例化对象,其内部有一个__proto__属性,指向Person的prototype
&&& console.log(p1.prototype);//undefined,这个属性是一个对象,访问不到
&&& console.log(Person.prototype);//Person
&&& console.log(Person.prototype.constructor);//原型对象内部也有一个指针(constructor属性)指向构造函数
&&& console.log(p1.__proto__);//这个属性是一个指针指向prototype原型对象
&&& p1.say();//实例可以访问到在原型对象上定义的属性和方法
&function createObject(name,age){
&&& var obj = new Object();
&&& obj.name =
&&& obj.age =
工厂模式解决了实例化对象大量重复的问题,但还有一个问题,那就是根本无法搞清楚他们到底是哪个对象的实例。
使用构造函数的方法,既解决了重复实例化的问题,又解决了对象识别的问题。
使用构造函数的方法和工厂模式的不同之处在于:
1.构造函数方法没有显示的创建对象(new Object());
2.直接将属性和方法赋值给this对象
3.没有return 语句
当使用了构造函数,并且new 构造函数(),那么就在后台执行了new Object();
函数体内的this代表了new Object()出来的对象
1.判断属性是在构造函数的实例里,还是在原型里,可以使用`hasOwnProperty()`函数
2.字面量创建的方式使用constructor属性不会指向实例,而会指向Object,构造函数创建的方式则相反
为什么指向Object?因为Box.prototype = {};这种写法其实就是创建了一个新对象。
而每创建一个函数,就会同时创建它的prototype,这个对象也会自动获取constructor属性
3.如果是实例方法,不同的实例化,他们的方法地址是不一样的,是唯一的
4.如果是原型方法,那么他们的地址的共享的
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具有编程基础的产品经理,原型用Axure做好,还是直接写代码好?
请将本文分享给你的朋友:
花了两天时间用Axure画完了一个系统的原型,可是因为是Axure菜鸟,总在交互上处处受限。觉得用Axure还没有写代码实现原型来得快。当然我也懂得艺多不压身的道理,但是如果说我可以用代码来实现原型,那么会不会比Axure更好一些? ~~~~~~~~~~~~~~~~~~~~~~~~~~~
【有编程基础的产品经理,原型用Axure做好,还是直接写代码好?】
请将本文分享给你的朋友:
------分隔线----------------------------新人入坑,做原型没美术和雕刻功底可以做到大神们那样吗?_手办原型制作吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:88,801贴子:
新人入坑,做原型没美术和雕刻功底可以做到大神们那样吗?收藏
挂机一个月得百万,你还蓝瘦香菇么?
╮(╯▽╰)╭ 撒 谁知道呢
可以~1 请去置顶贴2 看教程学习3 自己捏4 决定去留
有可能的,然后大神会骂街
美术功底必须要有,否则匿肌肉都不咋理解了,要么你搞医学的
同是新人,加油
最好有,有些大神作品,看的出做的很细致,但是比例,骨骼神马的常常错位
当然可以 不过你至少具备下面几个条件虚心接受别人的意见 有毅力和耐心
本人也是新手一枚,和LZ一样,没基础。一起加油吧
“健康随e保(长青版)”老人防癌险,线上免体检。
功底还不是练出来的……没有就练不会就学,最主要的是要有耐心和毅力吧对了,抗打击能力也一定要高,一开始会很艰难的……
大神都是生下来就有美术和雕刻功底的,所以想做到大神那样,你别想了。
新人就直接石粉粘土吧什么美术雕刻基础就不用管了只要你舍得花时间做了几十个完成品之后超神都没问题
完全可以,你只要花和大神一样的时间去拥有原型美术雕刻功底过很多很多很多年就可以做到大神们那样了。
功底不重要 天才重要 同样时间的练习 天才高的人可能比天才低的人进步10倍甚至100倍 艺术类的特别如此
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或荒废了好几天,在宿舍闷了几天了,一直想着回家放松,什么也没搞,论文就让老师催吧。不过,闲的没事干的感觉真是不好,还是看看书,写写博客吧,今天和大家说说函数的原型。
原型是什么
第一次看到这个的时候,没太理解这个概念,其实也就是一个概念呗,没啥神秘的。书上说每个函数都有一个prototype属性(原型属性),这个属性是一个指针,指向一个对象(原型对象),这个对象包含这个函数创建的实例的共享属性和方法。也就是说原型对象中的属性和方法是所有实例共享的,打住,那我们就先创建一个函数看看,原型是什么东东
var test = function(){}
console.log(test.prototype);//Object {}
看来,是这的有这么一个属性,可以看出是一个对象,但是默认的是一个空的对象,既然是一个对象,那我们就可以给它添加属性和方法喽,试试看
var test = function (){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
console.log(test.prototype);//Object {}
我们成功的添加了属性和方法,骄傲吧,对象中的属性一会我们在解释,现在看看我们修改之后的原型对象,有啥用呢?刚才我们说过,原型对象中的属性和方法是这个函数new出来实例所共享的,那我们就new实例出来试试
var test = function test(){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
console.log(test.prototype);//Object {}
var o1 = new test();
console.log(o1.getName());
console.log(o1.name);
var o2 = new test();
console.log(o2.getName());
console.log(o2.name);
看上面的图,我们new出来两个实例,这两个实例中并没有name对象和getName()方法,但是我们却使用了该属性和方法,就是因为函数的原型对象中存在这个属性和方法,并且是每个实例都可以使用的,这就是原型的神秘之处。也就是说以后我们想在每一个实例中添加属性和方法,那我们就把这个共有的属性或方法直接添加到原型对象上就可以了。
理解原型对象
现在我们知道了,函数有一个prototype属性,这个属性是一个指针,指向一个原型对象,这个原型对象中的属性和方法是这个函数的实例所共有的。现在我们看看这个原型对象中的属性,看这幅图
我们给一个原型属性添加属性之后,这个对象就不是空得了,看第一个图,上面打印出来的Object是空的,其实这个对象不是空的,只是有些属性没有被枚举出来,看下图
嗯,这样就对了,无论啥时候,只要创建一个新函数,就为给这个函数创建一个prototype属性,在默认的情况下,所有的原型对象会自动添加一个constructor属性,从名字就可以看出来应该指向构造函数,看图
指向了构造函数,也就是test.prototype.constructor === test。
属性中还有一个__prototype__属性,我们先放一下,我们还是看new出来那个实例的图,这次我把属性展开大家看看
var test = function test(){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
console.log(test.prototype);//Object {}
var o1 = new test();
console.log(o1);
我们分别打印了test的原型对象和一个实例对象,我们可以看到原型对象和实例对象中都有一个__proto__对象,但是指向不同,原型对象中的__proto__指向Object,而实例中的__proto__指向内部明叫test的对象,展开这个对象可以看到就是原型对象。就是说每一个实例中有一个__proto__属性指向原型对象。是不是有点晕呢,画个图看看先
是不是清楚点了呢,每一个实例的内部都包含一个内部属性__proto__,指向了构造函数的原型,就是这个属性连接了实例和原型对象之间的关系,并且我们知道实例中不包含name属性和getName方法,但是我们却使用了getName(),就是通过这个__proto__属性查找的。
大家应该发现了test的原型对象中也有一个__proto__属性,这个属性指向谁呢,我们来分析一下。我们知道了__proto__属性存在一个实例中并指向的是一个原型对象,现在就是说test的原型对象时某一个对象的实例喽,因为它有一个__proto__属性嘛。那test的原型对象是哪个对象的实例呢?我们知道javascript所有的对象都是基于Object这个对象的,都是Object的实例,我们大胆的猜测就是Oject的实例,我们展开这个属性看看就知道我们猜的对不对了,看图
&嗯,我们看到了__proto__属性指向的对象中存在一些方法,这些方法就是我们前面介绍的Object对象的方法,好牛,我们猜对了。我们刚才说了一下,实例可以共享原型的方法和属性,也就是test的原型可以使用Object原型中方法,而test的实例可以使用test的原型中的方法,也就是说test的实例可以使用Object原型中的方法,嗯,就是这样,我们试一下,看代码,使用一个简单的函数试一下就知道了
var test = function test(){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
var o1 = new test();
console.log(o1.toString());
我们使用了Object原型中的方法,我们再一次猜对了。现在我们把上面的图补充完整
现在就完整了,这就是这个例子的完整原型图形。我们以前说过,所有的应用类型都是继承Object,所有函数的默认原型都是Object的实例,因此默认原型都包含一个默认指针指向Object.prototype。这就是我们所说的原型链,继承就是通过原型链实现的,这就是所有的自定义类型都会继承toString()和valueOf()等默认方法的根本原因。Object是所有引用类型的父类,可以这么理解。
isPrototypeOf
使用方法a.isprototypeOf(b),判断对象a是否是实例b__proto__指向的原型对象,如果是返回true,否则返回false。看个例子
var test = function test(){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
var o1 = new test();
console.log(test.prototype.isPrototypeOf(o1));//true
hasOwnProperty
这个方法是检测一个属性是否存在实例中,存在原型中会返回false,看例子
var test = function test(){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
var o = new test();
console.log(o.hasOwnProperty("name"));//false
o.name = "xing";//给实例添加属性
console.log(o.hasOwnProperty("name"));//true
对象实例可以访问保存在原型中的值,但是不能重写原型中的值。每次要读取某一个属性时,都会执行一次搜索:首先在对象本身开始查找,如果查找到了就返回这个属性,如果没有找到,则继续搜索__proto__指向的原型对象,如果还没有找到,则继续搜索原型对象中__proto__指向的原型对象,这样一直迭代下去,这就是原型链的作用。看例子
var test = function test(){}
test.prototype.name = "hainan";
test.prototype.age = "25";
test.prototype.getName = function(){console.log(this.name);}
var o = new test();
console.log(o.name);//hainan
o.name = "xing";//给实例添加属性
console.log(o.name);//xing
delete o.//删除实例的name属性
console.log(o.name);//hainan
重写原型对象
我们已经知道怎么给一个原型对象添加属性和方法,但是大家都会想到一个简单地方法来一起添加,就像这样
var test = function test(){}
test.prototype = {
name : "hainan",
age : "25",
getName : function(){return this.name}
};var o = new test(); o.getName();//"hainan"console.log(o.constructor == test);//false
我们思考一下,上面的代码test.prorotype现在已经指向了一个新的对象,已经不是原来那个默认的原型对象了,原来的默认原型对象我们之前只是添加属性并没有重写它,所有他的内部属性还是存在了,现在我们重写了这个对象,即prototype指向了一个新的对象了,那他原来的属性constructor就没有了,如果我们以后会使用这个属性,那我们应该人为的设置,例如
var test = function test(){}
test.prototype = {
constructor : test,
name : "hainan",
age : "25",
getName : function(){return this.name}
var o = new test(); o.getName();//"hainan"
console.log(o.constructor == test);//true
原型动态性
看个例子先
var test = function test(){}
var o = new test();
test.prototype.name = "hainan";
console.log(o.name);
我们一般的时候肯定是先设置原型在创建实例,这在任何情况下都是没有问题的。我们创建实例是在给原型添加属性之后,即使这样我们也可以在实例中使用这个属性,这就是原型的动态性。这是由于在原型中查找值的过程是一次搜索,所有你修改的属性可以立即在实例中得到体现。但是重写一个函数的原型就不是这样了,看例子
var test = function test(){}
var o = new test(); o.getName();//TypeError: Object #&test& has no method 'getName'
test.prototype = {
constructor : test,
name : "hainan",
age : "25",
getName : function(){return this.name}
出现了错误,也就是我先创建了一个实例,在重写函数的原型对象这是不行的。原因是这样的,由于实例中的__proto__指针只是指向原型,而不是构造函数,上面的这段代码中,我们创建实例的时候,这个实例中的__proto__指向的是函数的默认原型对象,当我们重写了这个函数的原型对象时,虽然函数的prototype属性指向了新的对象,但是实例中的已经创建好了,它__proto__并没有改变,这个属性还是指向的是默认的原型对象,所有它的内部没有这个方法。但是如果在重写原型之后创建一个实例的话,这个新的实例的__proto__指向的就是新的原型对象了,像这样
var test = function test(){}
test.prototype = {
constructor : test,
name : "hainan",
age : "25",
getName : function(){return this.name}
var o = new test(); o.getName();//"hainan"
原生对象的原型
原生对象和我们自定义对象一样,都存在原型,原生对象的方法都存在原型中,这样我们创建一个新的对象实例时,这些对象就会拥有这些方法,当然我们可扩展原型对象,这样我们以后new出来的原型对象的实例就会共享这个方法或属性了。
console.log(String.prototype.slice);//function
我们扩展一个Array类型,增加一个函数contains(),判断数组中是否包含一个值
Array.prototype.contains = function(){
var length = arguments.
if(length != 1) return;
for(var i=0;l=this.length,i&l;++i ){
if(arguments[0] === this[i]) return true;
return false;
var arr = [1,2,3];
console.log(arr.contains(1));//true
console.log(arr.contains(4));//false
这就成了。
PS:给大家截一个图大家看看,不懂的可以在下面讨论下
就先写到这吧,大家有不懂的可以在下面讨论吧,我不懂的话我再去问大神,大伙要是觉得写得乱的话推荐去看看《javascript高级程序设计》,那上面写得比较好。小伙伴们都要回家了吧,提前祝大家春节快乐,马上有钱,立马变土豪。
阅读(...) 评论()

我要回帖

更多关于 原型链和作用域链 的文章

 

随机推荐