JavaScript中的原型
JavaScript中得到对象的方法
第一种方法:通过new Object得到
var person = new Object();
person.name = "xiaobao";
person.age = 18;
person.sex = "男";
person.say = function(){
console.log(this.name+this.age+this.sex);
}
person.say();
这种方法,当定义多个person的时候太麻烦
第二种方法:通过json得到
var person = {
"name" : "xiaobao",
"age" : 18,
"sex" : "男",
"say" : function(){
console.log(this.name+this.age+this.sex);
}
}
person.say();
这种方法也是,当定义多个person的时候太麻烦
var person = {
"name" : "xiaobao",
"age" : 18,
"sex" : "男",
"say" : function(){
console.log(this.name+this.age+this.sex);
}
}
person.say();
第三种方法:使用工厂模式function createPerson(name,age,sex){
var person = new Object();
person.name = name;
person.age = age;
person.sex = sex;
person.say = function(){
console.log(this.name+this.age+this.sex);
}
return person;
}
var person1 = createPerson("xiaobao",18,"男");
person1.say();
这种方法可以通过传递参数的方式可以定义多个person,但是对于得到的对象却不知道是什么类型
function createPerson(name,age,sex){
var person = new Object();
person.name = name;
person.age = age;
person.sex = sex;
person.say = function(){
console.log(this.name+this.age+this.sex);
}
return person;
}
var person1 = createPerson("xiaobao",18,"男");
person1.say();
第四种方法:使用构造函数function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.say = function(){
console.log(this.name+this.age+this.sex);
}
}
var person1 = new Person("xiaobao",18,"男");
person1.say();
console.log(person1 instanceof Person);
这种方法实际上跟工厂模式一样,不同之处只是先定义一个Person的所谓的类,再用new的方法来创建一个一个的对象,但是
say方法在每个对象创建后都存在了
一
个方法拷贝( 但是我们
发现代码在只有调用时,say方法才会在堆中创建),这样就增加了
内存的消耗了,如果在对象中有大量的方法时,内存的消耗就
会高,这样不行了
。简单地说就是因为say方法是一个闭包函数,每次
创建一个对象,say方法就会多一个,占用的内存会越来越多。
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.say = function(){
console.log(this.name+this.age+this.sex);
}
}
var person1 = new Person("xiaobao",18,"男");
person1.say();
console.log(person1 instanceof Person);
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.say = say;
}
function say(){
console.log(this.name+this.age+this.sex);
}
var person1 = new Person("xiaobao",18,"男");
person1.say();
console.log(person1 instanceof Person);
这种方法是将say方法拿出来作为全局函数,但是这样导致window也可以进行调用,失去了封装的意义,而且后面代码越写越多之后,方法越来越多,后期开发起来和优化起来都特别麻烦。因为以上方法都不理想,所以用原型的方法来创建对象
function Person(){}
Person.prototype.name = "xiaobao";
Person.prototype.age = 18;
Person.prototype.sex = "男";
Person.prototype.say = function(){
console.log(this.name+this.age+this.sex);
}
var person1 = new Person();
person1.say();
console.log(person1 instanceof Person);
//用来检测person1是不是指向Person的原型对象
console.log(Person.prototype.isPrototypeOf(person1));
先定义一个对象(首字母大写),再使用原形来给对象赋值,这样就将对象的属性和值放在了对象原型中,而且say方法只有对象自身可以访问,外界无法访问。
原型是js中非常特殊一个对象,当一个函数创建之后,会随之就产生一个原型对象,当通过这个函数的构造函数创建了一个具体的对象之后,在这个具体的对象中就会有一个属性指向原型。
//用来检测person1是不是指向Person的原型对象
console.log(Person.prototype.isPrototypeOf(person1));
//检测person1的构造器是不是指向Person对象
console.log(p1.constructor == Person);
//检测属性是不是在自己的内存中
console.log(p1.hasOwnProperty("name"));
//可以用delete语句来删除我们赋予对象自己的属性,但是原型中的是无法删除的
delete p1.name;
//检测某个对象自己或者对应的原型中是否存在某个属性
console.log("name" in p1);
//检测属性不在自己,在原型中
function hasPrototypeProperty(obj,prop) {
if (!obj.hasOwnProperty(prop)) {
if (prop in obj) {
return true;
}
}
return false;
}
console.log(hasPrototypeProperty(p1,"name"));
原型重写
如果对象中存在大量的属性或者方法的时候,使用之前的方式,感觉要写大量的【对象.prototype.属性名 】,感觉不是很好, 那么json的方式来写:
function Person() {}
Person.prototype = {
name : "xiaobao",
age : 18,
say : function() {
alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");
}
}
var p1 = new Person();
p1.say()
var p2 = new Person();
p2.name = "张三";
p2.age = 20;
p2.say();
但是这种写法,是将该对象的原型覆盖(这两种写法不一样的, 第一种是扩充,第二种是覆盖)
function Person() {}
Person.prototype = {
constructor:Person,//手动指向Person
name : "刘帅哥",
age : 18,
say : function() {
alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");
}
}
var p1 = new Person();
p1.say()
var p2 = new Person();
p2.name = "张三";
p2.age = 20;
p2.say();
//此时p1的构造器不在指向Person,而是指向了Object
//因为我们覆盖了Person的原型,所以如果constructor比较重要的话,</span><span style="color:#f8f8f2;font-weight: normal; font-family: Consolas; font-size: 10pt;">
//我们可以收到指向
console.log(p1.constructor == Person);
封装--原型创建对象
因为原型存在,我们实现了对象的封装,但是这种封装也同样可能存在问题的。
1、 我们无法像使用构造函数的那样将属性传递用于设置值
2、 当属性中有引用类型, 可能存在变量值的重复
function Person() {}
Person.prototype = {
constructor:Person,
name : "刘帅哥",
age : 18,
friends:["老孙","老牟"],
say : function() {
alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");
}
};
var p1 = new Person();
p1.friends.push("老刘");
alert(p1.friends);
//因为p1和p2对象指向了同一个原型链,所以当p1的friends发生变化是p2页就跟着
var p2 = new Person();
alert(p2.friends);
为了解决原型所带来的问题,需要通过组合构造函数和原型来实现对象的创建将:属性在构造函数中定义,将方法在原型中定义。这种有效集合了两者的优点,是目前最为常用的一种方式。
//属性在构造方法定义
function Person(name,age,friends) {
this.name = name;
this.age = age;
this.friends = friends;
}
/**
* 此时所有的属性都是保存在自己的内存中
* 方法都是定义在prototype(原型)中
*/
//方法在原型中定义
Person.prototype = {
constructor:Person,
say : function() {
alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");
}
};
var p1 = new Person("刘帅哥",18,["老孙","老徐"]);
p1.friends.push("老刘");
alert(p1.friends);
var p2 = new Person("曾小贤",20,["小丽","小美"]);
alert(p2.friends);
最终的定义 javascript 对象的方案就是基于组合的方式定义,将属性的定义放在构造函数中,将方法的定义放在原型中。