JavaScript原型,原型链 !

js原型

问题:什么是js原型?

js每声明一个function,都有prototype原型,prototype原型是函数的一个默认属性,在函数的创建过程中由js编译器自动添加。

也就是说:当生产一个function对象的时候,就可以看到它了。

举个栗子:

prototype的属性值是一个对象,是属性的集合,是属性的集合,是属性的集合,重要事情说三遍!

为什么要说他的属性的集合呢?我再来举个栗子~:

function Person(name,age){
    this.name=name;
    this.age=age;
}
    Person.prototype.sayHello=function(){
    alert("使用原型得到Name:"+this.name);
}
var per=new Person("马小倩",21);
per.sayHello(); //输出:使用原型得到Name:马小倩

   

在函数Person里面自定义了属性name和age,那么这两个属性都是放在prototype,也就是说,我要添加sayHello这个属性到Person,则要这样写:Person.prototype.sayHello,才能添加Person的属性。

(这是个人理解,感觉不怎么太对?!但是这样理解好像也没什么问题。)

使用原型来优化代码:

普通code:

function add(x,y){
   return x+y;
}
function subtract(x,y){
   return x-y;
}
console.log(add(1,3));

  

第一种方式用原型优化后:

var Calculator = function(){

};
Calculator.prototype = {
    add:function(x,y){
     return x+y;
},
subtract:function(x,y){
     return x-y;
}
};
console.log((new Calculator()).add(1,3));

第二种方式用原型优化后:

var Calculator = function () {};
Calculator.prototype = function(){
   add = function(x,y){
   return x+y;
},
subtract = function(x,y){
    return x-y;
}
return{
     add:add,
     subtract:subtract
}
}();

console.log((new Calculator()).add(1,3));

  

它目的:封装私有的function,通过return的形式暴露出简单的使用名称,以达到public/private的效果。

----------------------------------------------------------------------------------华丽的分割线-------------------------------------------------------------------------------------------

js原型链

问题:什么是原型链?

原型链是实现继承的主要方法。其基本思想是:利用原型让一个引用类型继承另一个应用类型的属性和方法。

简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

好的概念解释完毕,现在看看实际操作原理。

prototype默认的有一个叫做constructor的属性,指向这个函数本身。

一般construtor就是我们平时对函数设置的实例化对象

如上图:SuperType是一个函数,下面包括他的原型对象prototype,原型对象指向了构造函数的指针,而构造函数指回像了原型对象的内部指针,这样就形成了链式关系了。

就是说,当一个函数对象被创建时候,Function构造器产生的函数对象会运行类似这样的一行代码:

this.prototype = {constructor:this};

这个prototype对象是存放继承特征的地方。因为js没有提供一个方法去确定哪个函数是打算用来做构造器,                                         所以每个函数都会得到一个prototype对象。constructor属性没有什么用,重要的是prototype对象。

实现原型链有一种基本模式,其代码大致如下:

function A(){
    this.Aproperty = "111";
}

A.prototype.getA = function(){
    return this.Aproperty;
};

function B(){
     this.Bproperty = "222";
}

B.prototype = new A();//继承A
B.prototype.getB = function(){
     return this.Bproperty;
};

var C = new B();
console.log(C.getA());//111

以上定义了两个类型A和B。每个类型分别有一个属性和一个方法。它们的主要区别是B继承了A,而继承是通过创建A的实例,并将实例赋给B.prototype实现的。实现的本质是重写原型的对象,代之以一个新的类型的实例。换句话说,原来存在于A的实例中的所有属性和方法,现在也存在于B.prototype中了。在确立了继承关系之后,我们给B.prototype添加了一个方法,这样就继承A的属性和方法的基础上又添加了一个新方法。

如图:

function A(x){
   this.x = x;
 }
 A.prototype.a = "a";
 function B(x,y){
   this.y = y;
   A.call(this,x);
 }
 B.prototype.b1 = function(){
   alert("b1");
 }
 B.prototype = new A();
 B.prototype.b2 = function(){
   alert("b2");
 }
 B.prototype.constructor = B;
 var obj = new B(1,3);

  

   就是说把B的原型指向了A的1个实例对象,这个实例对象具有x属性,为undefined,还具有a属性,值为"a"。所以B原型也具有了这2个属性(或者说,B和A建立了原型链,B是A的下级)。而因为方才的类继承,B的实例对象也具有了x属性,也就是说obj对象有2个同名的x属性,此时原型属性x要让位于实例对象属性x,所以obj.x是1,而非undefined。第13行又定义了原型方法b2,所以B原型也具有了b2。虽然第9~11行设置了原型方法b1,但是你会发现第12行执行后,B原型不再具有b1方法,也就是obj.b1是undefined。因为第12行使得B原型指向改变,原来具有b1的原型对象被抛弃,自然就没有b1了。

  第12行执行完后,B原型(B.prototype)指向了A的实例对象,而A的实例对象的构造器是构造函数A,所以B.prototype.constructor就是构造对象A了(换句话说,A构造了B的原型)。

alert(B.prototype.constructor)出来后就是"function A(x){...}" 。同样地,obj.constructor也是A构造对象,alert(obj.constructor)出来后就是"function A(x){...}" ,也就是说B.prototype.constructor===obj.constructor(true),但是B.prototype===obj.constructor.prototype(false),因为前者是B的原型,具有成员:x,a,b2,后者是A的原型,具有成员:a。如何修正这个问题呢,就在第16行,将B原型的构造器重新指向了B构造函数,那么B.prototype===obj.constructor.prototype(true),都具有成员:x,a,b2。

  如果没有第16行,那是不是obj = new B(1,3)会去调用A构造函数实例化呢?答案是否定的,你会发现obj.y=3,所以仍然是调用的B构造函数实例化的。虽然obj.constructor===A(true),但是对于new B()的行为来说,执行了上面所说的通过构造函数创建实例对象的3个步骤,第一步,创建空对象;第二步,obj.__proto__ === B.prototype,B.prototype是具有x,a,b2成员的,obj.constructor指向了B.prototype.constructor,即构造函数A;第三步,调用的构造函数B去设置和初始化成员,具有了属性x,y。虽然不加16行不影响obj的属性,但如上一段说,却影响obj.constructor和obj.constructor.prototype。所以在使用了原型继承后,要进行修正的操作。

  关于第12、16行,总言之,第12行使得B原型继承了A的原型对象的所有成员,但是也使得B的实例对象的构造器的原型指向了A原型,所以要通过第16行修正这个缺陷。

时间: 2024-09-30 00:45:45

JavaScript原型,原型链 !的相关文章

Javascript的原型链图

90%的前端或者js程序员或者老师们对Javascript懂得不比这个多 给手机看的 但是这个图里的所有褐色单向箭头链就是Javascript的原型链(颜色标注对理解js原型链很关键) 这图中的各个__proto__ constructor .prototype 都是内部对象 这样画是为了简洁 举个例子 如果考虑__proto__ 作为内部对象 上图变为 原型链就是 constructor 和 prototype如果作为内部对象 放到相应的位置 图就变大麻团了 保证晕倒什么也记不住 不服请看 这

浅谈javascript的原型及原型链

浅谈javascript的原型及原型链 这里,我们列出原型的几个概念,如下: prototype属性 [[prototype]] __proto__ prototype属性 只要创建了一个函数,就会为该函数创建一个prototype属性,指向该函数的原型对象.实例对象是不会拥有该属性的.默认情况下,该原型对象也会获得一个constructor属性,该属性包含一个指针,指向prototype属性所在的函数. Person.prototype.constructor===Person [[proto

Javascript的原型和原型链

prototype :每个函数都会有这个属性,这里强调,是函数,普通对象是没有这个属性的(这里为什么说普通对象呢,因为JS里面,一切皆为对象,所以这里的普通对象不包括函数对象).它是构造函数的原型对象: __proto__ :每个对象都有这个属性,,这里强调,是对象,同样,因为函数也是对象,所以函数也有这个属性.它指向构造函数的原型对象: constructor :这是原型对象上的一个指向构造函数的属性 创建对象的三种方式 通过对象直接量 通过对象直接量创建对象,这是最简单也是最常用的创建对象的

JavaScript原型&原型链

原型&原型对象 先来一段简单的代码: function Fun(name) { this.name = name } var obj = new Fun('obj') JavaScript中的对象都有一个[[Prototype]]内置属性(即部分浏览器实现的__proto__属性),这是一个访问器属性,通过这个可以访问对象的[[Prototype]]:对象就是以这个属性为模板,来"继承"方法和属性. JavaScript中的方法都有一个prototype属性,有一个constr

JavaScript ES5类 原型 原型链 组合、原型、寄生式继承

ES5类 原型  原型链 继承 JavaScript中,原型是相对于构造函数(类)的叫法(或者说概念),原型链是相对于构造函数(类)的实例对象的叫法. 对于JavaScript对象,如果在对象自身上找不到该属性,那么就会向上沿着原型链继续查找该属性 创建一个ES5类 在ES5中,类是由函数名首字母大写的函数,通过关键字new创建的. 类的构造函数就是函数自身 一般情况下,ES5类的原型对象prototype是自身构造函数,该类的实例化对象的原型链对象__proto__也是该构造函数,这二者指向同

史上最清晰的JavaScript的原型讲解

一说起JavaScript就要谈的几个问题,原型就是其中的一个.说了句大话,史上最清晰.本来是想按照大纲式的行文写一下,但写到后边感觉其实就一个概念,没有什么条理性,所以下面就简单按照概念解释的模式谈下这个问题. 1.JavaScript的原型是什么? 原型,首先他是个对象.和在以对象为核心的JavaScript这门语言中的其他普通对象来说一样,只不过他的角色有点特殊.但首先要明白他就是一个对象,是一个无序的属性和值的序列对. 2.谁会具有原型这个对象? 所有的对象(包括函数这个对象)在默认的情

深入理解javascript之原型

理解原型 原型是一个对象,其他对象可以通过它实现属性继承.任何一个对象都可以成为继承,所有对象在默认的情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型.任何一个对象都有一个prototype的属性,记为:__proto__.每当我们定义一个对象,其__proto__属性就指向了其prototype.示例如下: var foo = { x: 10, y: 20 }; 即使我们不指定prototype,该属性也会预留.如果我们有明确指向的话,那么链表就连起来了.需要注意的是,p

深刻理解JavaScript基于原型的面向对象

主题一.原型 一.基于原型的语言的特点 1 只有对象,没有类;对象继承对象,而不是类继承类. 2  "原型对象"是基于原型语言的核心概念.原型对象是新对象的模板,它将自身的属性共享给新对象.一个对象不但可以享有自己创建时和运行时定义的属性,而且可以享有原型对象的属性. 3 除了语言原生的顶级对象,每一个对象都有自己的原型对象,所有对象构成一个树状的层级系统.root节点的顶层对象是一个语言原生的对象,其他所有对象都直接或间接继承它的属性. 显然,基于原型的语言比基于类的语言简单得多,我

理解JavaScript 的原型属性

1.原型继承 面向对象编程可以通过很多途径实现.其他的语言,比如 Java,使用基于类的模型实现: 类及对象实例区别对待.但在 JavaScript 中没有类的概念,取而代之的是一切皆对象.JavaScript 中的继承通过原型继承实现:一个对象直接从另一对象继承.对象中包含其继承体系中祖先的引用——对象的 prototype 属性. 2. JavaScript 实现继承的语言特性 当尝试访问 JavaScript 对象中不存在的属性时,解析器会查找匹配的对象原型.例如调用 car.toStri

javascript数组原型方法

1.javascript数组原型方法. 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>jstest</title> 6 </head> 7 <body> 8 <script> 9 var arr = ["1","2&q