原型对象prototype属性,construtor,检验js的数据类型
原型模式创建对象
函数的原型对象
在了解如何使用原型模式创建对象之前,有必要先搞清楚什么是原型对象。
我们创建的每一个构造函数都有一个prototype属性,该属性是一个指针,该指针指向了一个对象。对于我们创建的构造函数,该对象中包含可以由所有实例共享的属性和方法。
constructor 是每一个对象的属性
因为 Function 在javacsript中是一个对象Object,又是所有方法的构造器.注意:
,function Function(),function Object(),function Array(),function String(),function Student(),function Cat(),function abc()作为对象,它们都是Function的实例对象。因此有construtor属性,
所以他们的构造器:Function.constructor === Object.constructor ===Array.constructor === Student.constructor === f Function()
function Object(),function Array(),function String(),function Student() 在javascript中既是Function的实例对象.又是object,array,string,stu的构造器.
为此object,array,string,stu是对应Object,Array,String,Student的实例对象,所以
object.constructor=== f Object,array.constructor=== f Array,string..constructor=== f String,stu..constructor=== f Student
function Object(),function Array(),function String(),function Student()作为构造函数时,
Function.prototype为什么返回的又是一个函数?????
Object.prototype指向Object构造函数的原型对象,该原型对象中的一些属性和方法是所有实例共享的,也就是全局的属性和方法,例如toString ()、valueOf()
Array.prototype指向Array构造函数的原型对象,同上有所有实例共性的属性个方法。也就是常见的数组方法和属性。
String.prototype,Student.prototype等都是同理。
function Object(),function Array(),function String(),function Student()作为构造函数时,它们的实例对象
object._proto_ === Object.prototype
array._proto_ === Array.prototype
string._proto_ === String.prototype
stu._proto_ === Student.prototype
constructor可以被改写,所以使用要小心。
对象实例和原型对象的关联
在调用构造函数创建新的实例时,该实例的内部会自动包含一个[[Prototype]]指针属性,该指针指便指向构造函数的原型对象。注意,这个指针关联的是实例与构造函数的原型对象而不是实例与构造函数:
array的 constructor 属性返回 function Array() { [native code] }
num 数字 constructor 属性返回 function Number() { [native code] }
string constructor 属性返回 returns function String() { [native code] }
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var ary=fruits.constructor;
alert(ary);//弹出function Array() { [native code] }
alert(fruits.constructor===ary);//弹出true
alert(fruits.constructor===Array);//也是弹出true
因此:Student.prototype.constructor===Student
javascript中类型检测方法有很多:
- typeof
- instanceof
- Object.prototype.toString
- constructor
- duck type
最常见的就是typeof:
比较特殊的是typeof null返回“object”。
历史原因,规范尝试修改typeof null返回“null”修改完大量网站无法访问,为了兼容,或者说历史原因返回"object"。
typeof会返回一个变量的基本类型,只有以下几种:number,boolean,string,object,undefined,function;typeof对4种基本类型(number,boolean,undefined,string),function,object,很方便,但是其他类型就没办法了。
1.javascript的typeof返回哪些数据类型
object number function boolean underfind.string
判断一个对象是不是数组对象?用typeof返回“object”。
instanceof只能用来判断对象和函数,不能用来判断字符串和数字等,返回的是一个布尔值。instanceof是检测左边对象的原型链是否指向右边构造函数的prototype属性的,所以我们也可以用它来判断:
ar b = '123';
alert(b instanceof String); //false,instanceof无法判断字符串
alert(typeof b); //string,tpyeof返回变量的基本数据类型
var c = new String("123");
alert(c instanceof String); //true,instanceof可判断对象
alert(typeof c); //object,typeof判断对象时都返回object
var arr = [1,2,3];
alert(arr instanceof Array); // true
instanceof在判断对象是不是数组对象Array,String,Date,Number,Boolean正则等时很好用。
instanceof坑:不同window或iframe之间的对象类型检测不能使用instanceof!
除了instanceof来判断数组之外,还有就是数组对象的arr.constructor属性。
在默认情况下,所有原型对象会自动包含一个constructor属性,该属性也是一个指针,指向prototype所在的函数.这个属性在我们使用js系统或者自己创建的对象的时候,会默认的加上.
任何对象都有constructor属性,继承自原型的,constructor会指向构造这个对象的构造器或者构造函数。
constructor可以被改写,所以使用要小心。
var arr = [1,2,3]; //创建一个数组对象
alert(arr.constructor === Array); // true
可以使用jquery的$.type()方法。
使用原型模型创建对象
直接在原型对象中添加属性和方法
了解了原型对象之后,我们便可以通过在构造函数原型对象中添加属性和方法来实现对象间数据的共享了。例如:
function Student() {
}
Student.prototype.name = "easy";
Student.prototype.age = 20;
Student.prototype.alertName = function(){
alert(this.name);
};
var stu1 = new Student();
var stu2 = new Student();
stu1.alertName(); //easy
stu2.alertName(); //easy
alert(stu1.alertName == stu2.alertName); //true 二者共享同一函数
以上代码,我们在Student的protptype对象中添加了name、age属性以及alertName()方法。但创建的stu1和stu2中并不包含name、age属性以及alertName()方法,而只包含一个[[prototype]]指针属性。当我们调用stu1.name或stu1.alertName()时,是如何找到对应的属性和方法的呢?
当我们需要读取对象的某个属性时,都会执行一次搜索。首先在该对象中查找该属性,若找到,返回该属性值;否则,到[[prototype]]指向的原型对象中继续查找。
由此我们也可以看出另外一层意思:如果对象实例中包含和原型对象中同名的属性或方法,则对象实例中的该同名属性或方法会屏蔽原型对象中的同名属性或方法。原因就是“首先在该对象中查找该属性,若找到,返回该属性值;”
拥有同名实例属性或方法的示意图:
上图中,我们在访问stu1.name是会得到”EasySir”:
alert(stu1.name); //EasySir
通过对象字面量重写原型对象
很多时候,我们为了书写的方便以及直观上的”封装性”,我们往往采用对象字面量直接重写整个原型对象:
function Student() {
}
Student.prototype = {
constructor : Student,
name : "easy",
age : 20,
alertName : function() {
alert(this.name);
}
};
要特别注意,我们这里相当于用对象字面量重新创建了一个Object对象,然后使Student的prototype指针指向该对象。该对象在创建的过程中,自动获得了新的constructor属性,该属性指向Object的构造函数。因此,我们在以上代码中,增加了constructor : Student使其重新指回Student构造函数。
原型模型创建对象的局限性
原型模型在对象实例共享数据方面给我们带来了很大的便利,但通常情况下不同的实例会希望拥有属于自己单独的属性。我们将构造函数模型和原型模型结合使用即可兼得数据共享和”不共享”。
构造与原型混合模式创建对象
我们结合原型模式在共享方法属性以及构造函数模式在实例方法属性方面的优势,使用以下的方法创建对象:
//我们希望每个stu拥有属于自己的name和age属性
function Student(name, age) {
this.name = name;
this.age = age;
}
//所有的stu应该共享一个alertName()方法
Student.prototype = {
constructor : Student,
alertName : function() {
alert(this.name);
}
}
var stu1 = new Student("Jim", 20);
var stu2 = new Student("Tom", 21);
stu1.alertName(); //Jim 实例属性
stu2.alertName(); //Tom 实例属性
alert(stu1.alertName == stu2.alertName); //true 共享函数
以上,在构造函数中定义实例属性,在原型中定义共享属性的模式,是目前使用最广泛的方式。通常情况下,我们都会默认使用这种方式来定义引用类型变量。