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

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

1.Object
2.Function
3.Array
4.Date
5.String
6.RegExp
比如:
 var fn=new String("text");
String.prototype.value="val";
console.log(fn.value); //val
 function Person(name){
this.name=name;
}
Person.prototype.getName = function() {
return this.name;
};
var p1 = new Person("Evan"); console.log(p1.name); //Evan
console.log(p1.getName()); //Evan

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

再看一个更详细的例子:

 function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
console.log(this.name)
};
var person1 = new Person();
var person2 = new Person();
person2.sayName(); //Nicholas
console.log(person1.sayName == person2.sayName); //true

一张图看各对象的关系:

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

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

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

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


person1.name = "me"; //先在实例中找,没有再到原型中找
console.log(person1.name);//me
console.log(person1.constructor == Person);//true //用hasOwnPrototy()检测是否在实例中,为false说明属性来自原型
console.log(person1.hasOwnProperty("name")) ;//true
console.log(person2.hasOwnProperty("name")) ;//false //用一个in,检测是否有次属性,无论在实例还是原型中
console.log("name" in person1) ;//true
console.log("name" in person2) ;//true

若更改整个 Person.prototype:

 Person.prototype = {xx:"xx"};
person1.xx; //undefined
var ppp=new Person();
ppp.xx; //输出:xx

只会改变后面实例的对象,之前的不会改变。之前引用的不会被垃圾清理。

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

接上例。


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

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

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

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

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

prototype :返回是对象的原型。

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

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

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

看一个复杂的例子:

   var Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
}
Person.prototype.Salary = 50000; var Programmer = function () { };
Programmer.prototype = new Person();
Programmer.prototype.WriteCode = function () {
alert("programmer writes code");
};
Programmer.prototype.Salary = 500; var p = new Programmer();
p.Say();
p.WriteCode();
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)

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

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

关于继承

  function Animal(){}
Animal.prototype.say=function(){return "www"};
function Person(){}
Person.prototype.say=function(){return "hello"};
Person.prototype = new Animal();
6 var p2 = new Person();
p2.say(); //www

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

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


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

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

只需在继承后重写即可

   function Animal(){}
Animal.prototype.say=function(){return "www"};
function Person(){}
Person.prototype.say=function(){return "hello"};
Person.prototype = new Animal();
Person.prototype.say=function(){return "i am people"} //这里重写父类函数
var p2 = new Person(); p2.say(); //i am people

引用类型的问题:

 function SuperType(){this.color = ["red","blue","green"]}
function SubType(){
}
SubType.prototype=new SuperType();
var s1=new SubType();
s1.color.push("black");
console.log(s1.color);//["red", "blue", "green", "black"]
var s2=new SubType();
console.log(s2.color);//["red", "blue", "green", "black"]

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

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

这样肯定不合常理。更改

 function SuperType(){this.color = ["red","blue","green"]}
function SubType(){
SuperType.call(this);
}
SubType.prototype=new SuperType();
var s1=new SubType();
s1.color.push("black");
console.log(ss.color); //["red", "blue", "green", "black"]
var s2=new SubType();
console.log(s2.color); //["red", "blue", "green"]

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

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

或者这样继承:

     function Person(){}
Person.prototype.language="chinese";
Person.prototype.eat= function () {
console.log("eating");
}
function Programmer(){}
Programmer.prototype=Object.create(Person.prototype);//js原生复制函数
Programmer.prototype.constructor=Programmer; //指回子类自己
Programmer.prototype.language="javascript";//覆盖父类

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

javascript原型对象prototype的更多相关文章

  1. JavaScript 的原型对象 Prototype

    在 JavaScript 中,每当定义一个对象(或函数)时候,对象中都会包含一些预定义的属性,其中一个属性就是原型对象 prototype. var myObject = function( name ...

  2. JavaScript的原型对象prototype、原型属性__proto__、原型链和constructor

    先画上一个关系图: 1. 什么是prototype.__proto__.constructor? var arr = new Array; 1. __proto__是原型属性,对象特有的属性,是对象指 ...

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

    我们先来一个简单的构造函数+原型对象的小程序 function CreateObj( uName, uAge ) { this.userName = uName; this.userAge = uAg ...

  4. JavaScript -- 原型:prototype的使用

    JavaScript -- 原型:prototype的使用 在 JavaScript 中,prototype 是函数的一个属性,同时也是由构造函数创建的对象的一个属性. 函数的原型为对象. 它主要在函 ...

  5. javaScript系列 [03]-javaScript原型对象

    [03]-javaScript原型对象 引用: javaScript是一门基于原型的语言,它允许对象通过原型链引用另一个对象来构建对象中的复杂性,JavaScript使用原型链这种机制来实现动态代理. ...

  6. C# -- 等待异步操作执行完成的方式 C# -- 使用委托 delegate 执行异步操作 JavaScript -- 原型:prototype的使用 DBHelper类连接数据库 MVC View中获取action、controller、area名称、参数

    C# -- 等待异步操作执行完成的方式 C# -- 等待异步操作执行完成的方式 1. 等待异步操作的完成,代码实现: class Program { static void Main(string[] ...

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

    一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别 ...

  8. 原型对象prototype和原型属性[[Prototype]]

    构造器:可以被 new 运算符调用, Boolean,Number,String,Date,RegExp,Error,Function,Array,Object 都是构造器,他们有各自的实现方式. 比 ...

  9. 构造函数、原型对象prototype、实例、隐式原型__proto__的理解

    (欢迎一起探讨,如果有什么地方写的不准确或是不正确也欢迎大家指出来~) PS: 内容中的__proto__可能会被markdown语法导致显示为proto. 建议将构造函数中的方法都定义到构造函数的原 ...

随机推荐

  1. java学习:ArrayList的实现及原理

    1. ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部 ...

  2. [UCSD白板题] Sorting: 3-Way Partition

    Problem Introduction The goal in this problem is to redesign a given implementation of the randomize ...

  3. awk 学习笔记

    awk的语法有两种形式 awk [options] 'script' var=value file(s) awk [options] -f scriptfile var=value file(s) 选 ...

  4. oracle基本操作

    登入oraclesqlplus / as sysdba启动oraclestartup停止oracleshutdown 创建新用户create user username identified by p ...

  5. wpf 报错: 在 AddNew 或 EditItem 事务过程中不允许“DeferRefresh”。

    今天修改Bug的时候遇到一个问题: datagrid 设置了双击事件,双击弹出一个窗口,在多次点击后报错:在 AddNew 或 EditItem 事务过程中不允许“DeferRefresh” 网上查了 ...

  6. Java反射机制调用private类型的构造方法

    单例类: package singleton; public class SingletonTest { // 私有构造方法 private SingletonTest(){ System.out.p ...

  7. mysql 基本操作语句

    mysql 基本操作笔记: 创建表demo:CREATE TABLE `role` ( `role_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMME ...

  8. zoj 3717 - Balloon(2-SAT)

    裸的2-SAT,详见刘汝佳训练指南P-323 不过此题有个特别需要注意的地方:You should promise that there is still no overlap for any two ...

  9. 关于FluentNhibernate数据库连接配置,请教

      在用FluentNHibernate映射数据库,出现这个问题,一天多了也没解决,求各位大神支招 问题是与map对应的表已成功创建,出错的地方是最后的 .BuildSessionFactory(); ...

  10. Oracle常用函数笔记

    一.字符函数 1.dual 临时表 oracle中的临时变量表,此表只返回第一行第一列 例如:select sysdate from dual 输出:2014-6-9 11:20:39 2.Initc ...