JavaScript学习笔记(12):构造函数的问题点和原型

构造函数在生成实例时预留了保存各个实例所需要的内存空间。如在getName的例子中,实例化需要复制Member类中firstName、lastName属性以及getName的方法。但是在所有实例中内容都是一样的,所以实例为单位预留内存空间就浪费了。

所以,为了在JavaScript中给对象添加成员,准备了prototype这个属性。

prototype:声明原型,会被继承到实例化的对象中。prototype中添加的成员可在根据这个类或者构造函数生成的所有实例中使用。

var Member=function(firstName, lastName){
    this.firstName=firstName;
    this.lastName=lastName;
};
Member.prototype.getName=function(){
    return this.lastName+' '+this.firstName;
};

var mem= new Member('Jack','Chen');
console.log(mem.getName());

getName用prototype引用为原型对象,使得Mamber类的实例mem可以正确地访问。

使用prototype的两个好处:

1、节省内存

2、可以实时识别、添加或者更改成员:不向实例中复制,就可以在实例中动态地识别对原型对象的变更

var Member=function(firstName, lastName){
    this.firstName=firstName;
    this.lastName=lastName;
};

var mem= new Member('Jack','Chen');

Member.prototype.getName=function(){
    return this.lastName+' '+this.firstName;
};

console.log(mem.getName());

上述例子中,getName()的方法是在实例mem创造以后才添加的,依然可以正确地识别到getName的方法体。

var Member=function(){};
Member.prototype.sex='male';
var mem1=new Member();
var mem2=new Member();

console.log(mem1.sex+'|'+mem2.sex);    //male|male
mem2.sex='female';
console.log(mem1.sex+'|'+mem2.sex);    //male|female

delete mem1.sex
delete mem2.sex

console.log(mem1.sex+'|'+mem2.sex);    //male|male

delete mem1/delete mem2语句删除了属性,但是对prototype原型对象没有任何影响。如果要删除原型对象需要使语句:

delete Member.prototype.sex

这个代码会删除原型,所以所有引用了这个原型的实例都会收到影响。

如果要删除某个实例,可以使用以下的方法:

var Member=function(){};
Member.prototype.sex='male';
var mem1=new Member();
var mem2=new Member();

console.log(mem1.sex+'|'+mem2.sex);    //male|male
mem2.sex='female';
console.log(mem1.sex+'|'+mem2.sex);    //male|female


mem2.sex=undefinded;

console.log(key+' '+mem[key];

当要设定多个原型时,

var Member=function(firstName, lastName){
  this.firstName= firstName;
  this.lastName= lastName;
};
Member.prototype={
  getName:function(){
    return this.lastName+' '+this.firstName;
  },
  toString: function(){
    return this.lastName+this.firstName;
  }
}

这样使用字面量

1、可以减少「Member.prototype...」这样的代码输入;

2、更改对象名的时候减少需要修改的地方;

3、同一个对象成员定义在一个代码块中,提高代码的可持续性。

定义静态属性、静态方法

静态属性/静态方法是不需要生成任何实例也可以直接从对象中调用的属性/方法。

定义静态属性/方法时,不能定义在原型对象中。

静态成员不会添加到对象生成的实例中。

两个注意点:

1、静态属性通常是只读的;

2、在静态方法中,不能使用this关键字。(this关键字指向的是实例本身,而静态方法是没有实例的)

原型链和继承

var Animal=function(){};

Animal.prototype={
  walk:function(){
    console.log('tata');
  }
};

var Dog=function(){
  Animal.call(this);    //<=========(1)
};

Dog.prototype=new Animal();    //<=========(2)
Dog.prototype.bark=function(){
  console.log('wow wow');
}

var d=new Dog();
d.walk();    //tata
d.bark();    //wow wow

在(1)的部分将Animal对象的实例设置为Dog对象的原型。这样,Dog对象的实例中调用在Animal对象中定义的walk的方法。

原型链分析逻辑顺序:

1.检索Dog对象的实例d中有没有成员==>2.没有相对应成员时,检索Dog对象的原型(Animal对象)的实例==>3.还是没有检索到目的成员时,在检索原型(Anmal的原型)……如果还没有检索到,则再往上检索上层的原型(到最顶层的Object.prototype为止)。

到检索到目的成员时,检索终止。


JavaScript中继承关系时可以动态变更的

和Java、C++等语言不通,JavaScript的同一个对象,可以在某个时间继承对象A,在下一个时间继承对象B。

var Animal=function(){};

Animal.prototype={
  walk: function(){
    console.log('tata');
  }
};

var SuperAnimal=function(){};

SuperAnimal.prototype={
  walk: function(){
    console.log('didi');
  }
};

var Dog =function(){};

Dog.prototype=new Animal();
var d1=new Dog();
d1.walk();        //<========titi

Dog.prototype=new SuperAnimal();
var d2=new Dog();
d2.walk();        //<========didi
d1.walk();        //<========titi(1)


Dog.prototype先定义为Animal的实例,生成了实例d1

Dog.prototype再定义为SuperAnimal的实例,生成了实例d2

在(1)中,Dog.prototype已经被定义了SuperAnimal的实例,但是依然输出Animal的结果,说明原型链是在生成实例的时候就固定了,保存下来,并且于之后的改变无关。

Animal-----dog-----d1.walk;

SuperAnimal-----Dog-----d2.walk;

那么如何判断对象从属的类?

JavaScript严格来说,没有类的感念,根据某个对象生成的实例不一定会拥有相同的成员。

判断脚本中处理类型的4种方法:

1、constructor。可以获取对象继承的构造函数

var Animal=function(){};
var Hamster=function(){};
Hamster.prototype=new Animal();

var a=new Animal();
var h=new Hamster();

console.log(a.constructor===Animal);    //true
console.log(h.constructor===Animal);    //true
console.log(h.constructor===Hamster();  //false

Animal---Hamster--h

Animal---a

2、instanceof。判断继承的构造函数

var Animal=function(){};
var Hamster=function(){};
Hamster.prototype=new Animal();

var a=new Animal();
var h=new Hamster();


console.log(h.instanceof Animal);    //true
console.log(h.instanceof Hamster();  //true

使用instanceof运算符,不仅可以判断原本的构造函数,还可以判断原型链上的其他的构造函数。

3、isPrototypeOf。查看引用原型

var Animal=function(){};
var Hamster=function(){};
Hamster.prototype=new Animal();

var a=new Animal();
var h=new Hamster();


console.log(Hamster.isPrototypeOf(h));    //true
console.log(Animal.isPrototypeOf(h);  //true

此处的用法跟instanceof相似,只是这里用来查看对象引用的原型。

4、in。判断有没有成员

var obj={hoge: functionn(){}, foo: function(){}};

console.log('hoge' in obj);        //true
console.log('pyy' in obj));        //false

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值