《JavaScript高级程序设计》手札之三:对象操作技巧

1.面向对象的一个标志是有没有类的概念,ecmascript没有。ecmascript的对象可以想象成散列表,一组名值对。值可以是数据或函数。每个对象都是基于一个引用类型创建的。

2.对象字面量语法:
var person=
{
name:"Nichole",
age:29,
job:"Software Engineer",
sayName:function()
{alert(this.name);}
}
person.sayName();
3.修改属性,可以修改属性的configurable(能否通过delete删除属性从而重新定义属性),enumerable(能否通过for-in循环返回属性),writable(能否修改属性的值),不过多数情况下,没有必要利用Object.defineProperty提供的这些高级功能。调用Object.defineProperty()方法时,如果不指定,configurable,enumerable,writable特性的默认值都是false.
var person={};
Object.defineProperty(person,"name",{writable:false,value:"Nichole"});
alert(person.name);//Nichole;
person.name="Greg";
alert(person.name);//Nichole;
4.工厂模式:用函数来封装特定接口以创建对象。解决了多个相似对象的问题,但却没有解决对象识别问题(即怎样知道一个对象的类型)。
eg:
function creatperson(name,age,job)
{
    var o=new Object();
    o.name=name;
    o.age=age;
    o.jb=job;
    o.sayName=function()
    {
        alert(this.name);
    };
    return o;
}
var person1=creatperson("John",29,"HR");
person1.sayName();//John;
alert(person1.jb);//HR;
5.构造函数模式:区别于普通函数,即有new关键字。每定义一个函数就实例化了一个对象。
eg:
function Person(name,age,job)
{
    this.name=name;
    this.age=age;
    this.jb=job;
    this.sayName=function()
    {
        alert(this.name);
    };
}
var person1=new Person("John",29,"HR");
var person2=new Person('Nichole',30,'Programer');
person1.sayName();
person2.sayName();//不同实例上的同名函数是不相等的。(即同名函数做不同的事)
alert(person1 instanceof Person);
eg2:
function Person(name,age,job)
{
    this.name=name;
    this.age=age;
    this.jb=job;
    this.sayName=sayName;
}
function sayName()
{
    alert(this.name);
}//即同名函数做相同的事,但是,既然是全局函数,却只能特定函数调用 
var person1=new Person("John",29,"HR");
var person2=new Person('Nichole',30,'Programer');
person1.sayName();
person2.sayName();
6.原型模式:我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是可以由特定类型的所有实例共享的属性和方法。即不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。
①eg: 
function Person()
{
Person.prototype.name="Nicholas";
Person.prototype.age=29;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function()
{
  alert(this.name);
};
}
var person1=new Person();
person1.sayName();
var person2=new Person();
person2.sayName();//多个对象实例共享原型。
alert(Person.prototype.constructor==Person);//true;Person.prototype指向了对象,Person.prototype.constructor又指回Person本身。
②搜索首先从对象实例本身开始,如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的值。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在该实例中创建该属性,该属性会屏蔽原型中的属性。(但是并不是覆盖了,因为先查找实例,后查找原型对象,一旦有值就返回,所以访问不到原型对象,删了实例对象值,原型对象的没变)
eg2:
function Person()
{
Person.prototype.name="Nicholas";
Person.prototype.age=29;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function()
{
  alert(this.name);
};
}
 
var person1=new Person();
person1.name="Grag";
delete person1.name;//Nicholas;如果没有,则为Grag,delete可以删除读取的值。原型依然可以读取,也可以删除Person.prototype.name;
alert(person1.name);
③hasOwnProperty()方法用来检测是否来自实例,如果是,返回true,来自原型返回false;
eg:
function Person()
{
  Person.prototype.name="Nicholas";
  Person.prototype.age=29;
  Person.prototype.job="Software Engineer";
  Person.prototype.sayName=function()
  {
    alert(this.name);
  };
}
var person1=new Person();
person1.name=“Grag”;//删掉这句返回false
alert(person1.hasOwnProperty("name"));//true;
拓展检测:
function Person()
{
  Person.prototype.name="Nicholas";
  Person.prototype.age=29;
  Person.prototype.job="Software Engineer";
  Person.prototype.sayName=function()
  {
    alert(this.name);
  };
}
 
function hasPrototypeProperty(object,name)
{
 return  !object.hasOwnProperty(name)&&(name in object);//检测一个属性有木有原型
}
 
var person1=new Object();
alert(hasPrototypeProperty(person1,"name"));
④简单写法:
function Person(){
}
 
Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};
var friend = new Person();
friend.sayName();   //Nicholas
function Person(){
}
var friend = new Person();
 
Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};
 
friend.sayName();   //error
 
7.原型模式缺点,所有实例都共享属性,基本值的属性可以通过添加同名属性覆盖,但是引用类型不行,eg:
function Person(){
}
Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"],
    sayName : function () {
        alert(this.name);
} };
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);    //"Shelby,Court,Van"
alert(person2.friends);    //"Shelby,Court,Van"
alert(person1.friends === person2.friends);  //true
8.创建自定义类型最常见的方式是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度的节省了内存。这种构造函数与原型混成的模式,是目前ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。
eg:
function Person(name, age, job){
    this.name=name;
    this.age=age;
    this.job=job;
    this.friends=["Shelby","Court"];
}
Person.prototype={
    constructor:Person,
    sayName:function(){
        alert(this.name);
    }
}
var person1=new Person("Nicholas",29,"Software Engineer");
var person2=new Person("Greg",27,"Doctor");
person1.friends.push("Van");
alert(person1.friends);
alert(person2.friends)
9.动态原型模式:此模式中,已经创建了实例的情况下重写原型,会切断现有实例与新原型之间的联系。参考6中⑤
function Person(name, age, job){
    this.name=name;
    this.age=age;
    this.job=job;
    if(typeof this.sayName!="function"){
        Person.prototype.sayName=function() {
            alert(this.name);
        }
    }
}
var person1=new Person("Nicholas",29,"Software Engineer");
person1.sayName();

posted on 2016-04-28 16:54  鸣动我心  阅读(161)  评论(0编辑  收藏  举报