JavaScript学习第六章
1:理解对象
创建自定义对象的最简单方式为创建一个object的实例。例:
var A={
you:"a",
me:23,
love:function(){
alert()
}
}
6.1:属性类型
ECMAScript有两种属性:
1:数据属性
2:访问器属性
1.1:数据属性
1:[[Configurable]]:
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
用法:Configurable :true/false,
2:[[Enumerable]]:
表示能否通过for-in循环返回属性。
用法:Enumerable:true/false,
3:[[Writable]]:
表示能否修改属性的值。
用法:Writable:true/false,
4:[[Value]]:
包含这个属性的数据值。
默认值为Undefined
有关[[writable]]的例子:
var person = {
name:'Nichole'
};
Object.defineProperty(person,"name" , {
writable:false, // 设置属性不可修改(注意这里)
value:'Bubble'
});
console.log(person.name); // Bubble
person.name ='Hello';
// 非严格模式下,该操作被忽略;严格模式下,会导致抛出错误。
console.log(person.name); // Bubble
注:一旦将属性定义为不可配置的,就不能把它变回可配置的。
1.2.访问器属性
访问器属性不包含数据值,它包含一对getter()和setter()函数。在读取访问器属性时,会调用getter(),这个函数负责返回有效的值。
在写入访问器属性时,会调用setter()并传入新值,这个函数负责如何处理数据。
访问器属性有如下特性:
1:[[Configurable]]:
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
2:[[Enumerable]]:
表示能否通过for-in循环返回属性。
3:[[Get]]:
在读取属性时调用的函数,默认值为undefined
4:[[Set]]:
在写入属性时调用的函数,默认值为undefined
注:访问器属性不能直接定义,必须使用Object.defineProperty()来定义。例:
var A={
B:'Nichole',
count:0};
Object . defineProperty(person,'name', {
get:function(){
return this.B;
},
set:function(newValue){
this.B = newValue;
this.count +=1;
}});
A.name ='Bubble';
console.log(A.B) // Bubble
console.log(person.count) // 1
1.3:定义多个属性
可用Object.defineProperties()方法,定义多个属性。例:
var A={};
Object.defineProperties(A,{
B:{
Writable : true,
value : 12
},
B1:{
get : function(){
return this.B;
},
set.function(C){
if(C>11){
this.B = C;
}
}
}
});
1.3:读取属性的特性
使用 Object . getOwnPropertyDescriptor() 方法可取得给点属性的描述符。
语法
Object.getOwnPropertyDescriptor(obj , prop)
obj:需要查找的目标对象
prop:目标对象内属性名称
返回值:如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回undefined。
2:创建对象
创建一个对象,如此在使用同一个接口时,无需重复创建单个对象。
2:1工厂模式
例:function createObject1(name,age)
{
var obj=new Object();
obj.name=A;
obj.age=B;
obj.run=function(){
alert(this.name);
};
return obj;
}
var C=createObject1("loveyousiyun",27);
在上述createObject()函数被创建后,其可被无数次地调用,并返回一个含有两个属性的对象。
注:该模式存在无法识别对象类型的问题。
2.2构造函数模式
function CreateObject2(name,age)
{
var obj=new Object();
obj.name=A;
obj.age=B;
obj.run=function(){
alert(this.name);
};
return obj;
}
var C= new CreateObject2("loveyousiyun",27);
注:上述两个例子中,除了相同的部分外,CreateObject2()函数还存在以下不同之处:
1:没有显式地创建对象;
2:直接将属性和方法赋给了this对象;
3:没有return语句。
注:函数名CreateObject2开头使用的是大写字母C,在调用该函数时,必须使用new 操作符。
要创建CreateObject2的新实例,必须使用new操作符。以这种方式调用构造函数实际上会经历以下4个步骤:
(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
(3)执行构造函数中的代码(为这个新对象添加属性);
(4)返回新对象。
2.3:原型模式
prototype()属性:该属性是一个指针,指向一个对象。
其用途为:使所有对象实例共享它所包含的属性和方法。
例:
function A(){
A.prototype.name="xiao";
A.prototype.age=19;
A.prototype.useful=function(){
alert(this.name);
};
}
var qiming=new A();
qiming.useful(); //xiao
var siyun=new A();
alert(siyun.age); //19
siyun.useful(); //xiao
alert(siyun.useful==qiming.useful); //true
由上述例子,可知:qiming和siyun访问的是同一组属性和同一个useful()函数。
注:可以通过对象实例访问保存在原型中的值,但不能通过对象实例重写原型中的值。
例:
function A(){
A.prototype.name="xiao";
A.prototype.age=19;
A.prototype.useful=function(){
alert(this.name);
};
}
var qiming=new A();
var siyun=new A();
qiming.name="li";
alert(qiming.name); // li — — — 来自实例
alert(siyun.name); // xiao — — —来自原型
由上述例子可知,qiming.name会屏蔽原型对象中保存得的同名属性。
注:可通过delete删除实例属性。例:
function A(){
A.prototype.name="xiao";
A.prototype.age=19;
A.prototype.useful=function(){
alert(this.name);
};
}
var qiming=new A();
var siyun=new A();
qiming.name="li";
alert(qiming.name); // "li" — — — 来自实例
alert(siyun.name); // "xiao" — — —来自原型
delete qiming.anme;
alert(qiming.name); // "xiao" — — —来自原型
注:构造函数模式和原型模式可组合使用。
例1:
function Person(name,age){
this.name=name;
this.age=age;
this.friends=["Icarid","Chris"];
}
Person.prototype={
constructor:Person, //constructor是保存对函数对象指针
getName:function(){
alert(this.name)
}
}
var person1=new Person("Joe",23);
var person2=new Person("Leo",35);
person1.getName(); //Joe
person2.getName(); //Leo
alert(person1.getName==person2.getName); //true,说明两个实例 的方法的指针相同
alert(person1.friends); //Icarid,Chris
person1.friends.push("John"); //向数组中传递参数,添加到数组末尾
alert(person1.friends); //Icarid,Chris,John
alert(person2.friends); //Icarid,Chris,说明实例的属性都是分的, 即互不影响
使用构造函数与原型混合的模式,是ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。
2.5:动态原型模式
该模式可通过检查某个应该存在的方法是否有效,来决定是否初始化原型。例:
function CreateObject2(name,age)
{
this.name=A;
this.age=B;
if (typeof this.sayname!="function"){
CreateObject2.prototype.sayname = function(){
alert(this.name);
};
}
var C= new CreateObject2("loveyousiyun","qiming");
C.sayname();
注意if(){....}中的那部分,只有在sayname()方法不存在的情况下,才会将它添加到原型中。
2.6:寄生构造函数模式
例:
function
Person(name,age,job){
var A =newObject();
A.name = name;
A.age = age;
A.job = job;
A.sayName =function(){
alert(this.name);
}
return A;
}
注: 首先,返回的对象与构造函数或者与构造函数的原型属性之间没有关系,
也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。
因此不能依赖instanceof 操作符来确定对象类型。
2.7:稳妥构造函数模式
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this对象。
稳妥对象最适合使用在一些安全的环境,或者防止数据被其他引用程序改动的时候使用。
function Person(name,age,job)
{
var o = new Object(); // 创建需要返回的对象
var _name = name;
var _age = age;
var _job = job; // 在这边可以定义私有的变量和函数
o.sayName = function(){
alert(_name); // 添加需要返回的方法
}
return o; // 返回对象
}
3:继承
3.1:原型链
简介:一个引用类型继承另一个引用类型的属性和方法。
例:
function Father(){
this.property = true;
}
Father.prototype.useful = function(){
return this.property;
}
function Son(){
this.property = false;
}
//继承了Father
Son.prototype = new Father();
Son.prototype.useless = function()
{
return this.property;
}
var instance = new Son();
alert(instance.useful()); //true
上面的其实是Son继承了Father,而继承则是通过创建Father的实例,并将该实例赋给Son.prototype实现的,实现的本质就是重写原型对象,代之一个新类型的实例。
如何确定原型和实例的关系
1:使用instanceof操作符,只要这个操作符来促使实例与原型链中出现过的构造函数,结果就会返回true。
例:alert(instance instanceof Object); //true
2:使用insPrototypeof()方法
例:alert(Object.prototype.isPrototypeOf(instance)); //true
3.2:借用构造函数
借用构造函数实现继承的基本思想是:
在子类型的构造函数内部调用超类型的构造函数。因为函数知识在特定环境中执行代码的对象,因此可以通过apply( )方法和call( )方法在新创建的对象上执行构造函数。
例1:
function SuperType(){
this.colors=['red','blue','green'];
}
function Subtype(){
SuperType.call(this); //在当前环境中调用SuperType函数,
} 继承了SuperType()
var aaa=new Subtype();
alert(aaa.colors); //red,blue,green
aaa.colors.push('black');
alert(aaa.colors); //red,blue,green,black
var bbb=new Subtype();
alert(bbb.colors); //red,blue,green
上述例子中,Subtype()继承了SuperType(),代码中将Subtype()赋值于 aaa 与 bbb 。
3.3.组合继承
使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
例:
function SuperType(name) {
this.name = name;
this.numbers = [1,2,3];
}
//原型来定义方法,原型链的优点
SuperType.prototype.sayName = function () {
alert(this.name);
};
function SubType (name, age) {
//继承属性
SuperType.call(this, name);
this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
//子类新定义的方法一定要在上面的继承代码之后,要不然新写的方法就没了
SubType.prototype.sayAge = function () {
alert(this.age);
}
var instance1 = new SubType("MirrorAvatar", 3);
instance1.numbers.push(33);
instance1.numbers; // "[1,2,3,33]"
instance1.sayName(); //MirrorAvatar
instance1.sayAge(); //3
var instance2 = new SubType("Cindy", 4);
instance2.numbers; //"[1,2,3]"
instance2.sayName(); //Cindy
instance2.sayAge(); //4
3.4:寄生式继承
寄生式基础的思路与寄生构造函数和工厂模式类似,既创建一个仅用于封装继承过程的函数,该函数内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
function object(o){
function F(){
}
F.prototype=o;
return new F();
}; //这部分object(o)中,返回值是F(),其中 F.prototype=o
function createAnother(original){
var clone = object(original); // 通过调用函数创建一个新对象
clone.sayHi =function(){ //以某种方式增强真个对象
alert("hi");
}
return clone; //返回值是clone,其中clone
}
注意:creatAnother(original)会返回clone, 其中clone=F() , F.prototype=original,clone.sayHi="hi",(就怕自己看不懂。。。。。。。)
在这个例子中,createAnother() 函数接收一个参数,也就是将要作为新对象基础的对象。然后把这个对象(original)传递给object()函数,将返回的结果赋值给clone。再为其添加一个sayHi方法,最后返回clone对象。
可以像下面这样使用 createAnother()方法
var person={
name:"Nicholas",
friends:["Shelby","Court","Van"]
}
var now = createAnother(person);
now.sayHi(); // hi
3.5:寄生组合式继承
function inheritPrototype(Female,Person){
var protoType=Object.create(Person.prototype); //创建对象
protoType.constructor=Female; // 增强对象
Female.prototype=protoType; //指定对象
} //取代了Female.prototype=new Person();
//也取代了Female.prototype.constrcutor=Female
inheritPrototype(Female,Person);
Female.prototype.sayAge=function(){
console.log(this.name+' '+this.age);
}
var
fm=new Female('skila','female',19);
fm.sayName(); //skila female 19
fm.sayAge(); //skila19