JavaScript创建对象

目录

一、对象

(一)创建对象的两种基本形式

1、创建对象-Object构造函数形式

2、创建对象-对象字面量形式

(二)属性类型

1、数据属性的4个特性

2、访问器属性的4个特性

3、操纵特性

二、创建对象

(一)工厂模式

(二)自定义构造函数

(三)原型模式

1、原型模式

2、原型对象和实例的操纵

(四)组合使用构造函数模式和原型模式


《JavaScript高级程序设计》学习笔记

ECMA-262把对象定义为:对象是无序属性的集合,其属性可以包含基本值、对象或函数

一、对象


(一)创建对象的两种基本形式

1、创建对象-Object构造函数形式

var person = new Object(); //使用Object构造函数创建对象
person.name = "zhangSan";
person.say = function(){
    alert(this.name);
};

person.say();

2、创建对象-对象字面量形式

var person = { //直接使用对象字面量形式创建对象
    name:"zhangSan",
    say:function(){
        alert(this.name)
    }
};

person.say();

(二)属性类型

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

特性是用来描述属性的行为特征,特性是内部值

  • 数据属性包含一个数据值的位置,即可以存放基本数据类型和引用数据类型。
  • 访问器属性不包含数据值,包含一对getter和setter函数。用于访问或者设置数据

1、数据属性的4个特性

  • [[Configurable]]:是否可通过delete删除属性,能否修改属性的特征或者把属性修改为访问器属性,默认true。
  • [[Enumerable]]:表示能否通过for-in循环返回属性,默认true。
  • [[Witable]]:能否修改属性的值,默认true。
  • [[Value]]:属性的值,默认undefined。

2、访问器属性的4个特性

  • [[Configurable]]:是否可通过delete删除属性,能否修改属性的特征或者把属性修改为访问器属性,默认true。
  • [[Enumerable]]:表示能否通过for-in循环返回属性,默认true。
  • [[Set]]:在写入属性时调用的函数,默认为undefined。
  • [[Get]]:在读取属性时调用的函数,默认为undefined。

3、操纵特性

ECMAScript5 的 Object.defineProperty()方法可以操纵特性。该方法接受三个参数:属性所在的参数、属性的名字和一个描述符对象。

  • 操纵数据属性特性
//操纵数据属性特性
var person = {};
Object.defineProperty(person,"name",{ //注意第二个参数要加双引号
    writable:false,
    value:"zhangSan"
})


alert(person.name);// zhangSan
person.name = "li";

alert(person.name);// zhangSan
  • 操纵访问器属性特性
//操纵访问器属性特性
var book = {
            _year: 2004,
            edition: 1
        };
          
        Object.defineProperty(book, "year", {
            get: function(){
                return this._year;
            },
            set: function(newValue){
            
                if (newValue > 2004) {
                    this._year = newValue;
                    this.edition += newValue - 2004;
                
                }
            }
        });
        
        book.year = 2005;
        alert(book.edition);   //2

4、读取属性特性

var book = {};
        
        Object.defineProperties(book, {
            _year: {
                value: 2004
            },
            
            edition: {
                value: 1
            },
            
            year: {            
                get: function(){
                    return this._year;
                },
                
                set: function(newValue){
                    if (newValue > 2004) {
                        this._year = newValue;
                        this.edition += newValue - 2004;
                    }                  
                }            
            }        
        });
        //使用getOwnPropertyDescriptor()方法读取属性的特性
        var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
        alert(descriptor.value);          //2004
        alert(descriptor.configurable);   //false
        alert(typeof descriptor.get);     //"undefined"
        
        var descriptor = Object.getOwnPropertyDescriptor(book, "year");
        alert(descriptor.value);          //undefined
        alert(descriptor.enumerable);     //false
        alert(typeof descriptor.get);     //"function"

二、创建对象


(一)工厂模式

使用Object构造函数方式或对象字面量形式在创建多个类似的对象时,会产生大量的重复代码。为了解决重复代码的问题,使用工厂模式创建对象。

function createObject(name,age,job){ //调用一次函数即可创建一个对象
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    }

    return o;
}

p = createObject("xufeng",28,"best");
p.sayName();

缺点:工厂模式创建的对象无法得知对象类型,因为这种新对象并没有类型名字。同时也无法让实例共享属性和方法

(二)自定义构造函数

为了解决工厂模式的缺点,自定义构造函数可以将它的实例标识作为一种特定的类型。

使用自定义构造函数定义:

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}

var p = new Person("小明",20,"student");
var s = new Person("老师",39,"Teacher");

alert(p instanceof Object);  //true
alert(p instanceof Person);  //true,对象视为Person类型

自定义构造函数名字以大写字母开头,要使用构造函数创建实例,必须使用new操作符。在创建构造函数时经历以下4步(重要):

  1. 创建一个新对象
  2. 将函数内的作用域赋予新对象(this指向新对象)
  3. 执行构造函数的代码(为新对象添加属性)
  4. 返回新对象

缺点:每个通过构造函数创建的对象不能共享属性和方法。如上述的sayName ()方法,调用一次Person构造函数便生成一次函数实例。

 

(三)原型模式

1、原型模式

  1. 每个函数均有一个prototype(原型)属性,该属性指向函数的原型对象。该对象的用途是可以包含由特定类型的所有实例共享的属性和方法。所有的原型对象会自动获得constructor属性,回指向函数。
  2. 每个实例均有一个内部属性[[Prototype]],该属性指向其构造函数的原型对象。
function Person(){};//自动创建Person的原型对象

 

使用函数的prototype(原型)属性让对象之间可以共享属性和方法,解决自定义构造函数无法共享属性和方法的缺点。

每个构造函数和实例无直接关系。而构造函数的实例有内部属性[[Prototype]]指向构造函数的原型对象。

function Person(){};

//将需共享的属性和方法放入构造函数的原型对象,实现共享
Person.prototype.name = "zhangSan";
Person.prototype.age = 28;
Person.prototype.sayName = function(){
    alert(this.name);
};

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

alert(p1.sayName == p2.sayName); //true

p1、p2共享Person构造函数原型对象内的属性name、age,和方法sayName。

缺点:原型模式会共享原型对象中所有的属性和方法。由于共享机制,若属性为引用类型,则实例之间可能会共享属性的修改,即实例之间的属性值会相互影响。

    function Person(){};

    Person.prototype.name = "zhangSan";
    Person.prototype.friends = ["li","wang","xu"];
    Person.prototype.age = 30;
    Person.prototype.sayName = function(){
        alert(this.name);
    };

    var p1 = new Person();
    var p2 = new Person();
    p1.friends.push("niu")
    
    //修改p1的属性会影响p2的属性
    alert(p2.friends);//li,wang,xu,niu

2、原型对象和实例的操纵

每个实例均有一个内部属性[[Prototype]],该属性指向其构造函数的原型对象,但所有实现无法访问内部属性[[Prototype]]。

(1)isPrototypeOf

使用isPrototypeOf()方法判断对象之间是否存在原型关系,若存在则返回true。

alert(Person.prototype.isPrototypeOf(p1));  //true

 

(2)Object.getPrototypeOf

ECMAScript5增加了一个新方法Object.getPrototypeOf(),该方法返回实例的[[Prototype]]的值。

alert(Object.getPrototypeOf(p1).name); //zhangSan

 

(3) hasOwnProperty

hasOwnProperty()检查一个属性是否存在于实例中。

    function Person(){};

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

    var p1 = new Person();
    p1.age = 30;
    
    alert(p1.hasOwnProperty("name"));//false,name不存在于p1实例中
    alert(p1.hasOwnProperty("age")); //true,age存在于p1实例中

由于in操作符可以判断该实例是否可以访问某个对象,因此hasOwnProperty()方法配合in操作符可以判断属性是否存在于实例中,还是存在于原型中。

function hasPrototypeProperty(object,name){
    //若name不存在与实例中,且in操作符能访问name属性,则name属性存在于原型中
    return !obeject.hasOwnProperty(name) && (name in object);
}}

(4) Object.keys

使用Object.keys()可以取得对象上所有可枚举的属性。

    function Person(){};

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

    var p1 = new Person();
    p1.age = 30;
    
    alert(Object.keys(Person.prototype));//name,age,sayName
    alert(Object.keys(p1));//age

(5)Object.getOwnPropertyName

取得所有属性,其中包括不可枚举属性

function Person(){};

    Person.prototype.name = "zhangSan";
    Person.prototype.age = 28;
    Person.prototype.sayName = function(){
        alert(this.name);
    };
    
    alert(Object.getOwnPropertyNames(Person.prototype));//constructor,name,age,sayName

 

(四)组合使用构造函数模式和原型模式

单用原型模式会由于共享机制而发生实例间属性的相互影响。因此可以将需共享的属性和方法放入对象原型中,而将无需共享的属性放入构造函数,实现构造函数模式和原型模式。

function Person(){ 
    //将无需共享的属性放入构造函数   
    this.name = "zhangSan";
    this.friends = ["li","wang","xu"];
    this.age = 30;
};
//将需要共享的方法放入原型对象中
Person.prototype.sayName = function(){
    alert(this.name);
};

var p1 = new Person();
var p2 = new Person();
p1.friends.push("niu");
//实例间的属性不会相互影响
alert(p2.friends);//li,wang,xu

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值