每天一个小知识点4(原型与构造函数总结二)



原型与构造函数总结 二


原型

无论什么时候只要创建了一个新的函数,就会有一组特定的规则为该函数去创建一个prototype属性,这个属性都指向的是原型对象而所有的原型对象都会默认获得一个constructor属性,这个属性包含一个指向prototype属性所在的函数指针People.prototype.constructor指向People---通过这个构造函数可以为原型对象添加其他的属性和方法


案例:

function People(){} People.prototype.name="zhangsan";
 People.prototype.age=18;
 People.prototype.sex="male"
 People.prototype.say=function(){
 alert(this.name);
 }
  var p1=new People();
 p1.name="xiaozuo";
 alert(p1.name)-----注意这里打印出来的值是指我们给定的值,覆盖了原型中的值,但是并没有改变它
var p2=new People();
alert(p2.name)----这里打印出来的是原型中的值

注意检测 原型是否属于对象

注意我们在打印p1的时候,在打印的过程中因为已经找到了name这个属性,也就是xiaozuo这个值,所以不会再向上找值(最终一直找到原型当中去) 但是p2没有给他赋值也就是说p2本质上来说没有name这个属性的,所以他必须找到一个值并且打印出来,所以一直会找到原型当中去

所以这里的根本原因是当为对象的实例添加了一个属性的时候,这个属性就会屏蔽原型对象中的同名属性,换个角度来说,也就是阻止去找这个默认的属性 哪怕你赋值为null也会去找

People.prototype.name=null;

同样的,当我们给这个属性赋值为null的时候会去找上方的东西嘛? 注意修改两个地方

People.prototype.name="zhangsan"  ;

  var p1=new People();
 p1.name=null;
 alert(p1.name)

打印结果为null 也就是说我们新覆盖的值即使为null他也会组织去寻找那个原型中的值

我们可以通过delete这个来取消覆盖

 delete  p1.name
 alert(p1.name)

重要函数hasOwnProperty()---检测一个属性是存在于原型还是实例中

 var p1=new People();
 p1.name="zhangsan";
 alert(p1.hasOwnProperty("name"))----true因为我们为p1给了一个name的属性值

  var p1=new People();
 //p1.name="zhangsan";
alert(p1.hasOwnProperty("name"))--false

in关键字

使用in关键字检测对象是否拥有某个属性

var p1=new People();
alert(p1.hasOwnProperty("name"))--false我们并没有为p1赋值name属性,但是他会从原型中找到这个值
alert("name" in p1)---true name属性从原型当中而来

枚举取得对象所有的属性

var key=Object.keys(People.prototype)
alert(key)
注意点
 var key=Object.keys(People.prototype)
alert(key)
var p1=new People();
p1.name="zhangsan";
p1.age=13;
 var keys=Object.keys(p1)
 alert(keys)

原型简写

上面案例中使用原型是不是有点麻烦呢?每一个属性都需要People.prototype.age=18; 这么的方式去写,那有没有简单一点的办法呢?

function People(){}
People.prototype={
name:"zhangsan",
age:18,
gender:'male',
say:function(){
alert(this.name)
}
}

在这里我们将People的prototype设置为等于一个以对象字面量形式创建的新对象,和上面的结果是一样的 但是,我们看这样一个东西

 function People(){}
People.prototype={
name:"zhangsan",
age:18,
gender:'male',
say:function(){
alert(this.name)
}
}
var  zhangsan=new People();
alert(zhangsan instanceof Object)
alert(zhangsan instanceof People)
alert(zhangsan.constructor==People)  // 打印结果为false
alert(zhangsan.constructor==Object)

原因,我们这次的写法和之前有所不同,每创建一个函数,就会创建它的prototype对象,这个对象会自动获得constructor属性,而我们这次的写法,实际上完全覆盖了默认的prototype对象,因此constructor也指向了别的东西(Object)

function People(){}
People.prototype={
name:"zhangsan",
age:18,
gender:'male',
say:function(){
alert(this.name)
}
}
var  zhangsan=new People();
alert(zhangsan instanceof Object)
alert(zhangsan instanceof People)
alert(zhangsan.constructor==People)  // 打印结果为false
alert(zhangsan.constructor==Object)

原因,我们这次的写法和之前有所不同,每创建一个函数,就会创建它的prototype对象,这个对象会自动获得constructor属性,而我们这次的写法,实际上完全覆盖了默认的prototype对象,因此constructor也指向了别的东西(Object)

如果constructor非常重要,则可以这样

function People(){}
People.prototype={
constructor:People,
name:"zhangsan",
age:18,
gender:'male',
say:function(){
alert(this.name)
}
}
var p=new People();
alert(p.constructor)

原型模式

 function People(){}
People.prototype={
name:"zhangsan",
age:18,
gender:'male',
say:function(){
alert(this.name)
}
}
var  zhangsan=new People();
alert(zhangsan.constructor)

构造器模式

function People(name,age,sex){  
   this.name=name;
  this.age=age;
   this.sex=sex;
this.say=new Function("alert(this.name)")

   var  zhangsan=new People("zhangsan",18,"male");
   alert(zhangsan.constructor)

原型动态性:

function People(){}
People.prototype.name="zhangsan";
People.prototype.age=18;
People.prototype.sex="male"
People.prototype.say=function(){
alert(this.name);
}
var p1=new People();
p1.say=function(){
alert("hi")
}
   p1.say()

虽然第二个say方法是在p1对象构造出来之后才改写的,但是依然能用 但是:

    function People(){}
    var p1=new People();

People.prototype={
name:"zhangsan",
age:18,
gender:'male',
say:function(){
alert(this.name)
}
}

p1.say()---报错了,因为原型是咋创建了对象之后才改写的

当然除了我们自定义的对象有原型外,原生态的对象也是有原型的


继承: 关于继承我之前已经讲过一种方式了call继承 那么继承到底有什么好处呢?继承是OO编程中最重要的思想

原型链:

ECMAscript中描述了原型链的概念,并且将原型链作为最主要的继承方式,主要思想是让一个引用对象继承另一个引用对象的属性和方法

使用原型链:

 function parentClass() {
this.methoda = function() {
alert("parentClass method");
}
}
function subClass() {
this.methodb = function() {
alert("subClass method");
}
}
subClass.prototype = new parentClass();
var temp = new subClass();
temp.methoda();
temp.methodb();

案例2:

 function SuperType(){
   this.colors=["red","yellow","green"]
   }
function SubType(){}
SubType.prototype=new SuperType();
   var v=new SubType();
alert(v.constructor)

原型链的问题1:

  function SuperType(){
   this.colors=["red","yellow","green"]
   }
function SubType(){}
SubType.prototype=new SuperType();
   var v=new SubType();
alert(v.colors )
   v.colors.push("hello")
   var v2=new SubType();
   alert(v2.colors )---注意这里,因为继承,所以所有共享实力都使用了同一个原型,原型中会发生改变

原型问题2:没法向父类构造参数中传递参数

所以一般比较少的使用原型链

比较多的使用构造函数继承,最简单的就是之前的call方法了


原型式继承

大师级人物道格拉斯提出了种经典的函数

function object(people){
    function F(){}
    F.prototype=people;
    return new F();
}

和原型区分开来 在函数类不限创建了一个临时的构造函数,然后将传入的对象作为原型,最后返回临时对象的一个新实力,从本质来讲的话object()对传入其中的对象执行了一次复制

ECMAscript通过新增Object.create()方法来规划了原型继承,这个方法和接受两个参数 1:新对象原型的对象2:新对象定义额外属性的对象(可选) 在传入一个参数的情况下Object.create() 和object()方法是一样的 var people={ name:"zhangsan" } var student=Object(people); student.name="lisi"; alert(people.name)// 注意这里,和原型模式是一样的,类型的值始终会被共享出去

案例2:

 var people={
 name:"zhangsan"
 }
var student=Object(people);
student.name="lisi";
 alert(student.name);
 var student2=Object(people);
 student2.name="wangwu";
alert(student2.name);

在没有必要大规模创建构造函数,仅仅让一个对象和另外一个对性保持类似的情况下,原型继承是完全可以胜任的

关于js中继承有很多中方式,这里就不一一列举了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值