javascript原型对象prototype
“我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。”
引用类型才具有prototype属性,包含:
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的更多相关文章
- JavaScript 的原型对象 Prototype
在 JavaScript 中,每当定义一个对象(或函数)时候,对象中都会包含一些预定义的属性,其中一个属性就是原型对象 prototype. var myObject = function( name ...
- JavaScript的原型对象prototype、原型属性__proto__、原型链和constructor
先画上一个关系图: 1. 什么是prototype.__proto__.constructor? var arr = new Array; 1. __proto__是原型属性,对象特有的属性,是对象指 ...
- [js高手之路]使用原型对象(prototype)需要注意的地方
我们先来一个简单的构造函数+原型对象的小程序 function CreateObj( uName, uAge ) { this.userName = uName; this.userAge = uAg ...
- JavaScript -- 原型:prototype的使用
JavaScript -- 原型:prototype的使用 在 JavaScript 中,prototype 是函数的一个属性,同时也是由构造函数创建的对象的一个属性. 函数的原型为对象. 它主要在函 ...
- javaScript系列 [03]-javaScript原型对象
[03]-javaScript原型对象 引用: javaScript是一门基于原型的语言,它允许对象通过原型链引用另一个对象来构建对象中的复杂性,JavaScript使用原型链这种机制来实现动态代理. ...
- C# -- 等待异步操作执行完成的方式 C# -- 使用委托 delegate 执行异步操作 JavaScript -- 原型:prototype的使用 DBHelper类连接数据库 MVC View中获取action、controller、area名称、参数
C# -- 等待异步操作执行完成的方式 C# -- 等待异步操作执行完成的方式 1. 等待异步操作的完成,代码实现: class Program { static void Main(string[] ...
- js高级——构造函数,实例对象和原型对象——prototype、__proto__和constructor构造器
一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别 ...
- 原型对象prototype和原型属性[[Prototype]]
构造器:可以被 new 运算符调用, Boolean,Number,String,Date,RegExp,Error,Function,Array,Object 都是构造器,他们有各自的实现方式. 比 ...
- 构造函数、原型对象prototype、实例、隐式原型__proto__的理解
(欢迎一起探讨,如果有什么地方写的不准确或是不正确也欢迎大家指出来~) PS: 内容中的__proto__可能会被markdown语法导致显示为proto. 建议将构造函数中的方法都定义到构造函数的原 ...
随机推荐
- Cobbler学习之二--Cobbler的Web管理和维护
Cobbler的Web管理模块和命令行模块是可以分开工作的,没有依赖关系. 1 WebUI的功能 查看所有的对象和配置文件 添加或者删除system,distro, profile 执行“cobble ...
- invalidate()和postInvalidate()的使用与区别
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型: Android UI操作并不是线程安全的,并且这些操作必须在UI线程 ...
- 带回调函数的js运动框架
function startMove(obj, json, endFun) { //开始前关闭之前obj上的定时器 clearInterval(obj.timer); //定时器 obj.timer ...
- android wifi P2P CONNECT, INVITE和JOIN流程选择
android wifi P2P CONNECT, INVITE和JOIN流程选择
- UITextField 的重写
在很多产品设计的时候,产品设计人员设计出来的输入框总会要求,文字的内容距离做边框多少像素,编辑区域的其实点,距离左边多少像素,很多人绝的难以适应!其实这些都不存在很大的技术难度,一下这些方式都可以达到 ...
- mysql 按时间段统计(年,季度,月,天,时)
按年汇总,统计: select sum(mymoney) as totalmoney, count(*) as sheets from mytable group by date_format(col ...
- redis/php redis扩展 安装
作者:silenceper 日期:2013-10-03 原文地址: http://silenceper.com/archives/952.html 我是在CentOS 6.3 中进行的. 使用到的软件 ...
- [转]全面理解Unity加载和内存管理
[转]全面理解Unity加载和内存管理 最近一直在和这些内容纠缠,把心得和大家共享一下: Unity里有两种动态加载机制:一是Resources.Load,一是通过AssetBundle,其实两者本质 ...
- 解剖SQLSERVER 第二篇 对数据页面头进行逆向(译)
解剖SQLSERVER 第二篇 对数据页面头进行逆向(译) http://improve.dk/reverse-engineering-sql-server-page-headers/ 在开发Orc ...
- Ubuntu Server 15.04的安装
U盘启动工具的制作就跟Windows系统以及Linux各版本的desktop版不同,用的工具也是我第一次见到的“Win32_Disk_Imager”(点击下载) 安装过程请参考:http://www. ...