面向对象

一、理解对象

每当new一个person对象都有相同的属性和方法。这些属性在创建时都带有一些特征值

let p = {
    name: "nihao";
    age : "26";
    sayName : function () {
         alert ( this.name );
    }
}    

ECMAScript中有两种属性数据属性和访问器属性。

1、数据属性

  • [[Configurable]]:表示能否通过delete删除属性,能否修改属性,默认true
  • [[Emumerable]]:是否可枚举,遍历 for-in
  • [[Writable]]:修改属性的值
  • [[Value]]::包含这个数据属性的值

修改默认特性, Object.defineProperty( obj,"属性名","描述符对象" ) 

var person = {};
Object.defineProperty(person, "name", {
  writable: false,
  value: "aa"
});
console.log(person.name);//aa
person.name="bb";

 

2、访问器属性

  • [[Configurable]]:表示能否通过delete删除属性,能否修改属性,默认true 
  • [[Emumerable]]:是否可枚举,遍历 for-in
  • [[Get]]:在读取的时候调用的函数,默认undefined
  • [[Set]]:在写入的时候调用的函数,默认undefined

访问器属性不能直接定义,必须使用Object.defineProperty()来定义

var book = {
    _year: 2004,
    edition: 1
}

Object.defineProperty(book,"year",{
  get: function () {
    return this._year;
  },
  set: function ( newYear ) {
     if ( newYear > 2004 ) {
                this._year = newYear;
                this.edition += newYear - 2004;
            }
  }
})

book.year = 2005;
alert(book.edition) //2

//定义多个属性,区别同一时间创建

var book = {};

Object.defineProperties( book, {

    _year:{
        value:2004,
    }
    
    edition: {
        value: 1,
    }

    year: {
        get: function () {
            return this._year;
     },
        set: function ( newYear ) {
            if ( newYear > 2004 ) {
                this._year = newYear;
                this.edition += newYear - 2004;
            }
        }
    }

})   

读取属性特性:Object.getOwnPropertyDescriptor( obj,"属性名" ) 

 

 


 

 

二、创建对象

 

Object构造函数对象字面量都可以创建单个对象,他们的缺点:使用同一个接口创建很多对象,会产生大量的重复代码;于是有了很多设计模式来结局以上问题;

 

设计模式

 

1、工厂模式:在函数内创建一个对象,给对象赋予属性及方法再将对象返回

function Person() {
    var People = new Object();
    People.name = 'nihao';
    People.age = '25';
    People.sayName= function(){
        return this.name;
    };
    return People;
}
 
var a = Person();
console.log(a.name);//nihao

优点:同一类型同一属性可以重复调用;

缺点:同一类型不同属性值的不能调用;

 

2、构造函数模式:无需在函数内部重新创建对象,在函数内使用 this 关键字,创建属性和方法。再使用 new 运算符创建实例,通过传参生成不同的实例。

function Person() {
    this.name = 'nihao';
    this.age = '25';
    this.sayName = function(){
        return this.name;
    };
}
var a = new Person();
console.log(a.name);//nihao
console.log(a.sayName());//nihao

缺点:每个方法都要在每个实例上重新创建一遍,因js中函数是对象,因此每定义一个函数,也就实例化了一个对象。不同实例上的同名函数不相等

function Person() {
    this.name = 'nihao';
    this.age = '25';
    this.sayName = sayName ; //将sayName 属性设置等于全局的sayName函数,此时sayName 包含了指向函数的指针,因而不同实例共享全局作用域中定义的同一个sayName()函数
}
function sayName  () {
    alert(this.name )
}

缺点:需要全局定义函数,破坏了封装性

优点:构造函数模式解决了工厂设计模式所遇到的问题

 

3、原型模式:创建一个构造函数,再函数外为通过prototype方式添加属性和方法,最后通过new 运算符生成实例,可以让所有对象实例共享它所包含的属性及方法

function Person() {
}

Person.prototype.name= "nihao";
Person.prototype.age= 25;
Person.prototype.sayName = function() {
  alert(this.name);
};

var p1= new Person();
var p2= new Person();

优点:语义上,看起来所有属性都是同一个对象,解决了上两种方式所遇到的问题;

缺点:不能通过给构造函数传递参数来初始化属性的值,对于包含引用类型来说,如果其中某个实例属性重新赋值,会导致其他的实例同一属性也会发生变化

function Person() {
}

Person.prototype.name= "nihao";
Person.prototype.age= 25;
Person.prototype.friends = ["张三","李四"]
Person.prototype.sayName = function() {
  alert(this.name);
};

var p1= new Person();
var p2= new Person();

p1.friends.push("王老五");

console.log(p1.friends)  //"张三","李四","王老五"
console.log(p2.friends)  //"张三","李四","王老五"

 

4、混合的构造函数/原型方式:利用构造函数定义实例属性,利用原型方式来定义共享的方法和属性

function Person() {
    this.name = 'nihao';
    this.age = '25';
    this.friends = ["张三","李四"];
}

Person.prototype = {
   constructor: Person,
   sayName: function () {
        alert(this.name)
    }
}

 

posted @ 2017-07-02 17:16  唐新  阅读(101)  评论(0编辑  收藏  举报