javascript 面向对象精要 第四章 构造函数和原型对象

第四章 构造函数和原型对象

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());

运行结果如下:

在生产环境中一般不建议修改内建对象!!

等待下一章更新哦奋斗

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值