javascript原型对象prototype

“我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。”

引用类型才具有prototype属性,包含:

1.Object

2.Function

3.Array

4.Date

5.String

6.RegExp

比如:

1 var fn=new String("text");
2 String.prototype.value="val";
3 console.log(fn.value);  //val
 1 function Person(name){
 2     this.name=name;
 3 }
 4 Person.prototype.getName = function() {
 5         return this.name;
 6     };
 7 var p1 = new Person("Evan");
 8
 9 console.log(p1.name);  //Evan
10 console.log(p1.getName());  //Evan

这个prototype属性也就相当于动态添加属性或方法

再看一个更详细的例子:

 1 function Person(){
 2 }
 3 Person.prototype.name = "Nicholas";
 4 Person.prototype.age = 29;
 5 Person.prototype.job = "Software Engineer";
 6 Person.prototype.sayName = function(){
 7     console.log(this.name)
 8 };
 9 var person1 = new Person();
10 var person2 = new Person();
11 person2.sayName();  //Nicholas
12 console.log(person1.sayName == person2.sayName); //true

一张图看各对象的关系:

Person里面只有一个prototype属性,指向原型对象。原型对象中constructor指向它的构造函数(它的来源),和其他原型属性方法。

Person.prototype就是原型  isPrototypeOf确定二者是否有关系,Object.getPrototypeOf获取原型值

1   console.log(Person.prototype); //Object {name: "Nicholas", age: 29, job: "Software Engineer"}  (原型对象)
2   console.log(Person.prototype.isPrototypeOf(person1)) //true;
3   console.log(Object.getPrototypeOf(person1).name) //Nicholas;
4   console.log(Person.prototype.constructor == Person); //true

若将上例稍改一下,给实例化的person1添加name属性并赋值:  name:me

 1 ↑
 2 person1.name = "me";
 3
 4 //先在实例中找,没有再到原型中找
 5 console.log(person1.name);//me     console.log(person1.constructor == Person);//true
 6
 7 //用hasOwnPrototy()检测是否在实例中,为false说明属性来自原型
 8 console.log(person1.hasOwnProperty("name")) ;//true
 9 console.log(person2.hasOwnProperty("name")) ;//false
10
11 //用一个in,检测是否有次属性,无论在实例还是原型中
12 console.log("name" in person1) ;//true
13 console.log("name" in person2) ;//true

person1和person2是实例化的Person,也能访问Person的原型对象,用指针[[Prototype]]来实现,我们不可操作[[Prototype]],但可以有另一个__proto__来访问。

接上例。

1  ↑
2  console.log(person1.prototype);//undefined
3  console.log(Person.prototype);//Object {name: "Nicholas", age: 29, job: "Software Engineer"}
4  console.log(person1.__proto__);//Object {name: "Nicholas", age: 29, job: "Software Engineer"}
5  console.log(Person.__proto__);//function(){}

实例化对象调用原型对象,是__proto__指针,不是prototype属性。它本身没有原型对象,是去调用构造函数的原型对象。

当构造函数(Person)调用__proto__指针时,返回它本身。

__proto__与prototype的区别:(IE不支持__proto__

__proto__:对象的内部原型的引用。

prototype :返回是对象的原型。

当我们访问一个对象的属性 时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样 一直找下去,也就是我们平时所说的原型链的概 念。所以__proto__是联系各对象的桥梁。

1  var Person = function () { };
2  var p = new Person();
3  alert(p.__proto__ === Person.prototype);  //true

这个例子很容易理解,实例p的来源就是Person的原型

看一个复杂的例子:

 1   var Person = function () { };
 2      Person.prototype.Say = function () {
 3       alert("Person say");
 4     }
 5   Person.prototype.Salary = 50000;
 6
 7   var Programmer = function () { };
 8   Programmer.prototype = new Person();
 9   Programmer.prototype.WriteCode = function () {
10      alert("programmer writes code");
11   };
12      Programmer.prototype.Salary = 500;
13
14   var p = new Programmer();
15      p.Say();
16   p.WriteCode();
17   alert(p.Salary);

我们来做这样的推导:

var p=new Programmer()可以得出p.__proto__=Programmer.prototype;

而在上面我们指定了Programmer.prototype=new Person();我们来这样拆分,var p1=new Person();Programmer.prototype=p1;那么:

p1.__proto__=Person.prototype;

Programmer.prototype.__proto__=Person.prototype;

由根据上面得到p.__proto__=Programmer.prototype。可以得到p.__proto__.__proto__=Person.prototype。

好,算清楚了之后我们来看上面的结果,p.Say()。由于p没有Say这个属性,于是去p.__proto__,也就是 Programmer.prototype,也就是p1中去找,由于p1中也没有Say,那就去p.__proto__.__proto__,也就是 Person.prototype中去找,于是就找到了alert(“Person say”)的方法。

(参考:http://rockyuse.iteye.com/blog/1426510)

1 var student = {name:‘aaron‘};
2 console.log(student.__proto__);//Object {}

JS中的所有对象都是继承自Object对象,所以这里来源是Object {}

关于继承

1  function Animal(){}
2  Animal.prototype.say=function(){return "www"};
3  function Person(){}
4  Person.prototype.say=function(){return "hello"};
5  Person.prototype = new Animal();
6  var p2 = new Person();
7  p2.say();  //www

当一个对象的prototype指向另一对象时,就实现了继承。如例子中Person继承Animal

此时,要注意,父类和子类都有自己的prototype。继承后,子类的实例对象构造函数就指向父类了。如下

1 ↑
2 console.log(p2.constructor);//function Animal(){}
3 console.log(Object.getPrototypeOf(Person.prototype).constructor) ;//function Animal(){}

按道理这很正常,理应如此。但有时不是我们想要的结果。如上例子,虽然继承了父类,但 p2.say()我想让它输出子类的结果,那怎么弄呢

只需在集成后重写即可

1   function Animal(){}
2   Animal.prototype.say=function(){return "www"};
3   function Person(){}
4   Person.prototype.say=function(){return "hello"};
5   Person.prototype = new Animal();
6   Person.prototype.say=function(){return "i am people"} //这里重写父类函数
7   var p2 = new Person();
8
9   p2.say();  //i am people

引用类型的问题:

1 function SuperType(){this.color = ["red","blue","green"]}
2 function SubType(){
3 }
4 SubType.prototype=new SuperType();
5 var s1=new SubType();
6 s1.color.push("black");
7 console.log(s1.color);//["red", "blue", "green", "black"]
8 var s2=new SubType();
9 console.log(s2.color);//["red", "blue", "green", "black"]

s1和s2是子类的实例化,s1把继承父类的color属性进行添加,按理说只能s1自己添加。结果把子类实例化出的其他对象的属性都改了。

SubType.prototype=new SuperType();相当于:子类是父类的一个实例,子类自己拥有了color属性。但实例化子类时,s1和s2共享color属性,导致更改时一起改了。

这样肯定不合常理。更改

 1 function SuperType(){this.color = ["red","blue","green"]}
 2 function SubType(){
 3 SuperType.call(this);
 4 }
 5 SubType.prototype=new SuperType();
 6 var s1=new SubType();
 7 s1.color.push("black");
 8 console.log(ss.color); //["red", "blue", "green", "black"]
 9 var s2=new SubType();
10 console.log(s2.color); //["red", "blue", "green"]

call()函数在闭包时有讲,把某个函数绑定到某个对象中。在这里,就相当于把父类函数拿过来,在自己作用域调用,借用构造函数,也相当于重写了父类。

所以每次实例化子类,都要调用子类重写的函数,进行一次分配,每个实例拥有自己的color属性。互不干扰。

此文章是学习小结,如有不正,望指正。

时间: 2024-10-10 22:45:39

javascript原型对象prototype的相关文章

[js高手之路]使用原型对象(prototype)需要注意的地方

我们先来一个简单的构造函数+原型对象的小程序 1 function CreateObj( uName, uAge ) { 2 this.userName = uName; 3 this.userAge = uAge; 4 } 5 CreateObj.prototype.showUserName = function () { 6 return this.userName; 7 } 8 CreateObj.prototype.showUserAge = function () { 9 return

js高级构造函数,实例对象和原型对象——prototype、__proto__和constructor构造器

一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别. 先上代码,最常用的: function Person(name, age) { this.name = name; this.age = age; this.eat= function() { alert('吃西红柿') } } var person1 = new Person('小米', 28

浅谈JS中的构造函数、原型对象(prototype)、实例中的属性/方法之间的关系

原文链接:https://segmentfault.com/a/1190000016951069 构造函数:函数中的一种,通过关键字new可以创建其实例.为了便于区分,通常首字母大写:原型对象:一种特殊的对象,构造函数创建时自动生成:与构造函数形成一一对应,如同人和影子般的关系:实例:通过构造函数实例出来的对象: 在定义构造函数时,在其内部(“{“和”}”)进行定义属性和方法.当我们通过关键字new,对构造函数进行实例化的时候.实例会对构造函数的这些属性进行拷贝出一份副本,然后将其归属为当前实例

[js高手之路]原型对象(prototype)与原型链相关属性与方法详解

一,instanceof: instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型. 我在之前的两篇文章 [js高手之路]构造函数的基本特性与优缺点 [js高手之路]一步步图解javascript的原型(prototype)对象,原型链 已经分享过了. function CreateObj(uName) {             this.userName = uName;             this.showUserName = function

JavaScript 原型对象和原型链

开篇 之前对js中的原型链和原型对象有所了解,每当别人问我什么是原型链和原型对象时,我总是用很官方(其实自己不懂)的解释去描述.有一句话说的好:如果你不能把一个很复杂的东西用最简单的话语描述出来,那就说明你没有真正的理解.最近正在读<Javascript高级程序设计>,书中对原型对象和原型链的描述让我受益匪浅,下面仅用一个对比性的例子来说明. 我们经常会这么写 1 function Person () { 2 this.name = 'John'; 3 } 4 var person = new

javascript -- 原型对象

原型对象: 每个对象都有一个参考对象,这个参考对象称之为原型对象.原型对象有自己的属性和方法.当A是B的原型对象时,那 么B拥有A中的所有属性和方法. 原型对象的工作原理: 使用原型对象定义一个新的对象时,该对象不会立即拥有原型对象的属性和方法,在调用的时候本对象内部没有的属性和方法是才回去调用原型中的属性和方法.(动态分配). 原型对象的引用: 在javascript中每一个函数都定义了一个prototype属性用于引用原型对象. Js代码 1 function computer(){ 2 3

一文带你彻底理解 JavaScript 原型对象

一.什么是原型 原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承. 1.1 函数的原型对象 在JavaScript中,我们创建一个函数A(就是声明一个函数), 那么浏览器就会在内存中创建一个对象B,而且每个函数都默认会有一个属性 prototype 指向了这个对象( 即:prototype的属性的值是这个对象 ).这个对象B就是函数A的原型对象,简称函数的原型.这个原型对象B 默认会有一个属性 constructor 指向了这个函数A ( 意思就是说:con

JavaScript原型对象的属性和方法

前面介绍了普通对象的原型链结构,下面会先介绍一下原型对象中的属性和方法,然后介绍函数对象的原型链,最后将原型链进行整合一下. 第一部分Object.prototype的属性和方法 1 Object.prototype.toString方法 因为Object.prototype顶级对象中定义了toString方法,所以任何对象都有一个toString方法. 可以用来检测对象的类型,当然只能检测内置对象的类型,如果是自定义构造函数创建的对象的话无法准确检测出来类型. 使用方式:Object.prot

javascript原型对象

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getS