js原型

时间:2022-09-08 13:52:47

1、js基本类型和对象类型
js的简单类型包括数字(其中NaN为数字类型)、字符串(类似'A'为字符,js没字符类型)、布尔值、null值和undefined值。其他所有的值都是对象。数字、字符串和布尔值“貌似”是对象,因为它们拥有方法,但它们是不可变的,所以不是对象。js的对象时可变的键控集合(keyed collections)。在js中,数组、函数、正则表达式是对象。

2、js原型的重要知识点
首先要知道一个很重要的知识点,一句话:所有对象都有原型对象。


3、对比其他语言的理解
原型对象,就是其它语言中的类中的静态属性和静态方法,总之是静态-static就对了.原理是: 内存中只有一份。


4、原型链
每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性 时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样 一直找下去,也就是我们平时所说的原型链的概念。
按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是火狐和谷歌(ie除外)的引擎将他暴露了出来成为了一个共有的属性,我们可以对外访问和设置。因为ie不存在__proto__属性,所以在ie中,当对象创建后,对象的原型链就已经确定,无法更改。
由于原型对象本身也是对象,根据上边的定义,它也有自己的原型,而它自己的原型对象又可以有自己的原型,这样就组成了一条链,这个就是原型链,JavaScritp引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined.原型链一般实现为一个链表,这样就可以按照一定的顺序来查找。
prototype是构造器原型,其实prototype只是一个假象,他在实现原型链中只是起到了一个辅助作用,换句话说,他只是在new的时候有着一定的价值,而原型链的本质,其实在于__proto__。实例如下:

 var base = {
name : "base",
getInfo : function(){
return this.name;
}
} var ext1 = {
id : 0,
__proto__ : base
} var ext2 = {
id : 9,
__proto__ : base
} document.write(ext1.id);
document.write(ext1.getInfo());
document.write(ext2.id);
document.write(ext2.getInfo());

结果:
0
base
9
base
图1
js原型
其中proto__属性在ie中无法看到,在谷歌、火狐浏览器的debug下能看到这个属性。上面实例在ie中,ext1.name为undefined。ie中,ext1的对象在debug中内部结构如下:
js原型
在谷歌浏览器debug中内部结构如下:
js原型


5、分析一(对象字面量)
示例代码如下:

 var base = {
name : "base",
getInfo : function(){
return this.name;
}
}

谷歌浏览器debug模式下base对象的内部结构如下:
js原型


6、分析二(普通函数)
示例代码如下:

 function test(){
document.write("hello world");
}

谷歌浏览器debug模式下base对象的内部结构如下:
js原型


7、分析三(构造函数)
示例代码如下:

 function createObj(name){
this.name = name;
}

var o3 = new createObj("yql");
谷歌浏览器debug模式下base对象的内部结构如下:
js原型


8、使用某对象作为原型的方法
当你创建一个新对象时,你可以选择某个对象作为它的原型。js提供的实现机制杂乱而复杂,但其实它可以被明显的简化。我们将给Object增加一个beget方法,这个方法创建一个使用原对象作为其原型的新对象。示例代码如下:

 if(typeof Object.beget !== 'function'){
Object.beget = function(obj){
var F = function(){};
F.prototype = obj;//__proto__属性在ie中不存在,只能通过构造函数的prototype来设置原型
return new F();
};
}
var obj = {
msg:"hello world"
};
var newObj = Object.beget(obj);
document.write(newObj.msg);//hello world

谷歌浏览器debug模式下base对象的内部结构如下:
js原型
ie浏览器debug模式下base对象的内部结构如下:
js原型


9、我的理解
示例一:

 var obj = {
name : "zhangsan"
};
document.write(obj.name)//zhangsan
document.write(obj.age)//undefiend
Object.prototype.age = 28;
document.write(obj.age);//

示例二:

function ObjConstructor(name){
this.name = name;
}
var obj = new ObjConstructor("zhangsan");
document.write(obj.name+"<br />");//zhangsan
document.write(obj.age+"<br />");//undefiend
ObjConstructor.prototype.age = 28;
Function.prototype.sex = "M";
Object.prototype.home = "hb";
document.write(obj.age+"<br />");//28,obj.__proto__===ObjConstructor.prototype,即obj的原型为ObjConstructor.prototype对象
document.write(obj.sex+"<br />");//undefined,说明对象obj不能访问到Function.prototype
document.write(obj.home+"<br />");//hb,obj的原型的原型为Obj.prototype对象

示例三:

 var str = new String();
document.write(str.name);//undefined
String.prototype.name="zhangsan";
Object.prototype.age = 28;
Function.prototype.sex = "M";
document.write(str.name);//zhangsan,str的原型指向String.prototype对象
document.write(str.age);//28,str的原型的原型指向Object.prototype对象
document.write(str.sex);//undefined,str的原型链中没有指向Function.prototype对象

根据上面3个示例,可以得出以下几点内容:
1、对象在构造时,js引擎会设定该对象的原型(虽然谷歌、火狐的浏览器下可以修改对象原型的指向,但是ie中无法修改,而且按照标准,原型为隐藏的,不推荐可以修改)。对象构造完成后,对象的原型指向
的对象无法更改。如示例一中obj的原型指向Object.prototype对象,示例二中obj的原型指向ObjConstructor.prototype对象,示例三中str的原型指向String.prototype对象,这3个对象的原型指向的对象不能修改为
其他对象,只能是对应构造函数的prototype指向的对象。
2、只有函数有prototype属性,普通对象没有prototype属性。对象构造后,对象的原型指向其构造函数的prototype属性的对象。如示例一中obj的构造函数为function Object(){...},示例二中obj的构造函数为
function ObjConstructor(name){...},示例三中str的构造函数为function String(){...},所以他们的原型指向分别为Object.prototype对象、ObjConstructor.prototype对象和String.prototype对象。
3、自定义的函数的构造函数为function Function(){...},所以自定义的函数的原型为Function.prototype对象。如示例二中ObjConstructor的原型指向Function.prototype对象。
4、构造函数的prototype属性指向普通对象(不是函数),所以构造函数.prototype对象的原型为Object.prototype(不包括多层构造的情况)。如示例二中ObjConstructor.prototype的原型为Object.prototype
5、__proto__属性为对象(包括函数)的原型属性(ie中该属性为隐藏,按标准,该属性应该为隐藏的,但是可以用该属性来理解原型),prototype为函数的属性。当使用构造函数构造对象后,对象的原型
(即对象.__proto__)为构造函数的prototype(构造函数.prototype)所指向的对象。 容易理解错误的是,虽然对象的原型与prototype有紧密的联系,但是对象的原型不是对象的prototype属性。
6、按照java语言,可以这样理解:构造函数为类,所以推荐构造函数名称首字母大写。对象的原型的属性或方法可以理解为类的属性或方法(即java类中用static修饰的属性或方法)。