4.1 构造函数
构造函数就是你用new创建对象时调用的函数。使用构造函数的好处/目的:所有用同一个构造函数创建的对象都具有同样的属性和方法。构造函数也是函数,你可以用同样的方法定义它。唯一的区别是构造函数名首字母应该大写。
function Person(){}
var person1= new Person();
var person2= new Person();
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Person); //true
console.log(person1.constructor===Person); //true
console.log(person2.constructor===Person); //true
运行结果如下:
上述代码段定义了一个空的构造函数Person()。person1 和person2 都会被认为是一个新的Person类型的实例。new会自动创建给定类型的对象并返回他们。你也可以用instanceof操作符获取对象的类型。
构造函数属性constructor可以检查一个对象的类型。每个对象在创建时都自动拥有一个构造函数属性。
构造函数允许你用一致的方式初始化一个类型的实例,也可以在构造函数中用Object.defineProperty()方法来帮助我们初始化。
function Person(name){
Object.defineProperty(this,"name"{
get: function(){
return name;
},
set: function(newName){
name=newName;
},
enmerable:true,
configurable:true
});
this.sayName=function(){
console.log(this.name);
};
}
4.2 原型对象
可以把原型对象看作是对象的基类。几乎所有的函数(除了内建函数)都有一个名为prototype的属性,该属性是一个原型对象用来创建新的对象实例。所有创建的对象实例共享该原型对象。且这些对象实例可以访问原型对象的属性。
var book={
title:"wangzi"
};
console.log("title" in book);
console.log(book.hasOwnProperty("title"));
console.log("hasOwnProperty" in book);
console.log(book.hasOwnProperty("hasOwnProperty"));
console.log(Object.prototype.hasOwnProperty("hasOwnProperty"));
运行结果如下:
hasPOwnProperty是原型属性。
4.2.1 [[prototype]]属性
一个对象实例通过内部属性[[prototype]]跟踪其原型对象。该属性是一个指向该实例使用的原型对象的指针。当你用new创建一个新的对象时,构造函数的原型对象会被赋给该对象的[[prototype]]属性。
可以调用对象的Object.getPrototypeOf()方法读取[[prototype]]属性的值。
你也可以用isPrototypeOf()方法来检查,某个对象是否是另一个对象的原型对象。
var object={};
var prototype=Object.getPrototypeOf(object);
console.log(prototype===Object.prototype);
console.log(Object.prototype.isPrototypeOf(object));
运行结果如下:
object是一个泛用对象。
无法给一个对象的原型属性赋值。如果你定义一个toSring()的自有属性,自有属性会覆盖原型属性。仅当自有属性被删除时,原型对象才会再一次被使用。
4.2.2 在构造函数中使用原型对象
以下是新Person构造函数
function Person(name){
this.name=name;}
Person.prototype.sayName=function(){
console.log(this.name);
};
var person1=new Person("hui");
var person2=new Person("xia");
console.log(person1.name);
console.log(person2.name);
person1.sayName();
person2.sayName();
sayName()现在是一个原型属性而不是自有属性。运行结果如下:
也可以在原型对象上存储其它类型的数据。
function Person(name){
this.name=name;}
Person.prototype.sayName=function(){
console.log(this.name);
};
Person.prototype.favorites=[];
var person1=new Person("hui");
var person2=new Person("xia");
person1.favorites.push("piza");
person2.favorites.push("tomato");
console.log(person1.favorites);
console.log(person2.favorites);
favorites属性被定义在原型对象上,意味着person1.favrites和person2.favrites 指向同一个数组。运行结果如下:
可以在原型对象上一一添加属性,也可以直接用一个对象字面形式替换原型对象。
function Person(name){
this.name=name;
}
Person.prototype={
sayName: function(){
console.log(this.name);
},
toString: function(){
return "[person "+this.name+"]";
}
};
但是上述代码有一个副作用。
var person1=new Person("hui");
console.log(person1 instanceOf Person);
console.log(person1.constructor===Person);
console.log(person1.constructor===Object);
运行结果如下:
使用对象字面形式改写原型对象改变了构造函数的属性,因此它现在指向Object而不是Person。
解决:改写原型对象时手动重置constructor 属性。
function Person(name) {
this.name = name;
}
Person.prototype={
constructor:Person,
sayName: function(){
console.log(this.name);
},
toString: function(){
return "[person "+this.name+"]";
}
};
var person1=new Person("hui");
console.log(person1 instanceof Person);
console.log(person1.constructor === Person);
console.log(person1.constructor === Object);
运行结果为:
构造函数、原型对象、对象实例三者之间的关系。
4.2.3 改变原型对象
[[prototype]]属性包含了一个指向原型对象的指针,任何原型对象的改变都立即反映到所有引用它的对象实例上。
当你在一个对象上使用Object.seal()或 Object.freeze()时,完全是在操作对象的自有属性。你无法添加自有属性或改变冻结对象的自有属性,但仍可以通过在原型对象上添加属性来扩展这些对象实例。
function Person(name) {
this.name = name;
}
Person.prototype={
constructor:Person,
sayName: function(){
console.log(this.name);
},
toString: function(){
return "[person "+this.name+"]";
}
};
var person1=new Person("hui");
var person2=new Person("xia");
Object.freeze(person1);
Person.prototype.sayHi=function(){
console.log("Hi");
};
person1.sayHi();
person2.sayHi();
[[prototype]]属性是对象实例的自有属性,属性本身被冻结,但其指向的值(原型对象)并没有被冻结。运行结果如下:
4.2.4 内建对象的原型对象
所有内建对象都有构造函数,因此也有原型对象给你去改变。
比如,在数组上添加一个新的sum方法,只需简单修改Array.prototype.sum=function(){...}。在sum内部,也可以自由使用数组的其他方法。
字符串这一原始封装类型,它的原型对象也可以改变。
String.prototype.capitalize=function(){
return this.charAt(0).toUpperCase()+this.substring(1);
};
var m="hello world!";
console.log(m.capitalize());
运行结果如下:
在生产环境中一般不建议修改内建对象!!
等待下一章更新哦