javascript面向对象学习笔记——创建对象(转)

工厂模式

该模值抽象了创建具体对象de过程。用函数来封装噫特定接口创建对象的细节。

function createPerson(name,age,job){
    var o=new Object();
    o.name=name;
    o.age=age;
    o.job=job;
    o.sayName=function(){
        alert(this.name);
    };
    return o;
}
var person1=createPerson("Chiaki",21,"Software Engineer");
person2=createPerson("Wu",20,"Student");

特点:可以无数次调用,解决了创建多个相似对象的问题,但没有解决对象识别的问题(即怎样知道一个对象的类型)。

构造函数模式

创建自定义的构造函数,从而定义自定义对象类型的属性方法。

function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
    this.sayName=function(){
        alert(this.name);
    };
}
var person1=new Person("Chiaki",21,"Software Engineer");//person1的constructor(构造函数)属性指向Person
var person2=new Person("Wu",20,"Student");//person2的constructor(构造函数)属性指向Person

person1和person2都有一个constructor(构造函数)属性,该属性指向person.

alert(person1.constructor==Person);//true
alert(person2.constructor==Person);//true

构造函数模式与工厂模式的区别:

1、没有显示的创建对象;

2、直接将属性和方法赋给this对象;

3、没有return语句;

4、构造函数函数名以大写字母开头,非构造函数函数名以小写字母开头;

5、创建构造函数的新实例必须使用new操作符,例如var person1=new Person(“Chiaki”,21,”Web Engineer”);

6、将来可以将他的实例标识为一种特定的类型。

构造函数与其他函数的区别与联系:两者的调用方式不同;任何函数只要用new操作符调用,就可以把它当作构造函数,不通过new操作符调用,则和普通函数没什么区别。

//将上例当作构造函数使用
var person=new Person("Chiaki",21,"Software Engineer");
person.sayName();//Chiaki
//作为普通函数调用
Person("Wu",20,"Student");
window.sayName();//Wu//在全局作用域中调用一个函数,this对象总是指向Global对象(即浏览器的window对象)
//在另一个对象作用域中调用
var o=new Object();
Person.call(o,"lola",21,"designer");//使用call()在对象o的作用域中调用Person()函数,调用后o就拥有了Person()函数的所有属性和sayName()方法
o.sayName();//lola

缺点:每个方法都要在每个实例上重新创建一遍。

alert(person1.sayName==person2.sayName);//false

解决方法:把函数定义转到构造函数外,但是此方法可能需要定义多个全局函数,将导致该自定义引用类型毫无封装性可言。

function Person(name,ago,job){
    this.name=name;
    this.age=age;
    this.job;
    this.sayName=sayName;
}
function sayName(){
    alert(this.name);
}
var person1=new Person("Chiaki",21,"Software Engineer");
var person2=new Person("Wu",20,"Student");
//person1和person2对象共享在全局作用域中定义的同一个sayName函数

原型模式

我们创建的每一个函数都有一个property(原型)属性,这个属性是一个指针,指向一个对象(该对象包含可以由特定类型的所有实例共享的属性和方法)。

function Person(){
}
Person.prototype.name="Chiaki";
Person.prototype.age=21;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function(){
    alert(this.name);
};
var person1=new Person();
person1.sayName();//Chiaki
var person2=new Person();
person2.sayName();//Chiaki

这里写图片描述

创建一个新函数就会根据特定的规则为其生成一个prototype属性,该属性指向函数的原型对象,原型对象自动获得一个constructor属性,这个属性包含一个指向prototype属性所在函数的指针。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性[[Prototype]]),指向构造函数的原型对象。

可以通过对象实例访问保存在原型中的值,却不能通过对象实例重写原型中的值(当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性)。

function Person(){
}
Person.prototype.name="Chiaki";
Person.prototype.age=21;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function(){
    alert(this.name);
};
var person1=new Person();
var person2=new Person();
person1.name="Wu";
alert(person1.name);//Wu——来自实例//当alert()访问person1.name时,在该实例上搜索到一个名为name的属性,则不必搜索原型
alert(person2.name);//Chiaki——来自原型//当alert()访问person2.name时,在该实例上搜索不到一个名为name的属性,就继续搜索原型,结果在那里找到了name属性。

使用delete操作符可以完全删除实例属性:。

var person1=new Person();
var person2=new Person();
person1.name="Wu";
alert(person1.name);//Wu
alert(person2.name);//Chiaki
delete person1.name;
alert(person1.name);//Chiaki//delete操作符删除了person1.name,从而恢复了对原型中name属性的连接

可使用hasOwnProperty()方法检测一个属性是否存在于实例中,还是存在原型中。

alert(person1.hasOwnProperty("name"));//false//person1实例中没有name属性
person1.name="Wu";//person1重写name属性,即person1实例中有name属性
alert(person1.hasOwnProperty("name"));//true//原型与in操作符:单独使用、在for-in循环中使用。

单独使用时,in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在实例中还是原型中。

alert("属性" in 实例);如果该实例中有该属性则返回true,否则返回false。

function Person(){
}
Person.prototype.name="Chiaki";
Person.prototype.age=21;
Person.prototype.job="Software Engineer";
Person.prototype.sayName=function(){
    alert(this.name);
};
var person1=new Person();
var person2=new Person();
     alert(person1.hasOwnProperty("name"));//false//name属性在原型中
alert("name" in person1);//true
person1.name="Wu";alert(person1.hasOwnProperty("name"));//true//重新name属性后,person1实例中有name属性
alert("name" in person1);//true
hasPrototypeProperty() 方法判断访问到的属性是否存在于原型中。
var person =new Person();
alert(hasPrototypeProperty(perso,"name"));//true
person.name="Wu";//重写person.name,原型中的name属性被屏蔽,则访问到的name属性来自实例person
alert(hasPrototypeProperty(person,"name");//false

in操作符和hasOwnProperty()方法同时使用可以判断属性是处于对象中还是处于原型中。

在for-in循环中使用,返回所有能够通过对象访问的可枚举(enumerated)属性,包括实例中的属性和原型中的属性。屏蔽了原型中不可枚举属性(即[[enumerable]]设置为false)的实例属性也会在for-in循环中返回(IE 8 及更早的版本除外).

var o={
    name:"Chiaki"
};
for (var prop in o){
    alert(prop);//name
}

IE早期版有个bug会导致屏蔽不可枚举属性的实例属性不会出现在for-in循环中。

默认不可枚举的属性和方法有:hasOwnProperty()、propertyIsEnumerable()、toLocaleString(),toString()和valueOf();ECMAScript5也将constructor和prototype属性的[[Enumerable]]设置为false。

Object.keys()方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。

var keys=Object.keys(Person.prototype);
alert(keys);//"name,age,job,sayName"
var p1=new Person();
p1.name="Wu";
p1.age=20;
var p1Keys=Object,keys(p1);
alert(p1Keys);//"name,age"
Object.getOwnPropertyNames()返回所有实例属性
var keys=Object.getOwnPropertyNames(Person.prototype);
alert(keys);//“constructor,name,age,job,sayName"

更简单的原型语法:

Person.prototype={}
function Person(){}
Person.prototype={
    name:"Chiaki",
    age:21,
    job:"Software Engineer",
    sayName:function(){
        alert(this.name);
    }
};

上例中,我们将Person.prototype设置为等于一个以对象字面量形式创建的新对象,此时constructor属性不再指向Person.(原因:Person.prototype={}本质上完全重写了创建构造函数Person时默认的prototype对象,因此constructor属性就变成了新对象的constructor属性【指向Object构造函数】)。

此时如果constructor的值很重要时可特意将它设置回适当的值,如下:

funtion Person(){
}
Person.prototype={
    constructor:Person,//重设constructor属性将导致它的[[enumerable]]特性被设置为true,可以通过Object.defineProperty()修改成不可枚举的
    name:"Chiaki",
    age:21,
    job:"Software Engineer",
    sayName:function(){
        alert(this.name);
    }
};

原型的动态性:由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反应出——即使先创建了实例后修改原型也照样如此。

var friend=new Person();
Person.prototype.sayHi=function(){
    alert("hi");
}
friend.sayHi();//"hi"

实例和原型时间的连接是一个指针而非一个副本,因此可以随时为原型添加属性和方法,并且修改能够立即在所有对象实例中反应出来。但是如果是重写整个原型对象,将会切断构造函数和最初原型之间的联系。实例中的指针仅指向原型而非构造函数。

原型对象的问题:1、省略了为构造函数传递初始化参数的环节,结果所有实例在默认情况下都将取得相同的属性值;2、原型对象具有共享的本性,对于包含引用类型值的属性,如果一个原型对象创建的两个实例其中一个修改了引用类型的属性值,将导致另一个实例的该引用类型的属性值也被改变。

function Person(){}
Person.prototype={
    constructor=Person,
    friends:["lola","cherry"],
}
var person1=new Person();
var person2=new Person();
person1.friends.push("van");
alert(person1.friends);//lala,cherry,van
alert(person2.friends);//lola,cherry,van
alert(person1.friends==person2.friends)//true

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

构造函数模式用于定义实例属性,原型模式用于定义方法和共享属性。

function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
    this.friends=["lola","cherry"];
}
Person.prototype={
    constructor:Person,
    sayName:function(){
        alert(this.name);
    }
}
var person1=new Person("Chiaki",21,"Software Engineer");
var person2=new Person("Wu",20,"Student");
person1.friends.push("Van");
alert(person1.friends);//lola,cherry,Van
alert(person2.friends);//lola,cherry
alert(person1.friends==person2.friends);//false//friends是构造函数中定义的实例属性
alert(person1.sayName==person2.sayName);//trues//sayName()是原型中定义的,具有共享性

动态原型模式

把所有信息封装在构造函数中,而通过在构造函数中初始化原型又保持了同时使用构造函数和原型的优点。即通过检查某个应该村咋的方法是否有效来决定是否需要初始化原型。

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 friend=new Person("Chiaki",21,"Software Engineer");
friend.sayName();

寄生式构造函数模式

创建一个函数以封装创建对象的代码,然后返回新创建的对象。

function Person(name,age,job){
    var o=new Object();
    o.name=name;
    o.age=age;
    o.job=job;
    o.sayName=function(){
        alert(this.name);
        };
    return o;
}
var friend=new Person("Chiaki",21,"Software Engineer");
friend.sayName();//Chiaki

构造函数在不返回值的情况下默认会返回新对象实例,而通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值。构造函数返回的对象与构造函数或者构造函数的原型属性之间没有关系。

稳妥构造函数模式

稳妥对象:即没有公共属性,且方法也不用this的对象。适用于安全的环境中(该环境下禁用this和new)或者在在防止数据被其他应用程序改动时使用。

function Person(name,age,job){
    //创建要返回的对象
    var o=new Object();
    //可以在这里定义私有变量和函数
    //添加方法
    o.sayName=function(){
        alert(name);
    }
    //返回对象
    return o;
}

这种模式下创建的对象在,除使用sayName方法外,没办法访问name值。

时间: 2024-11-05 02:24:30

javascript面向对象学习笔记——创建对象(转)的相关文章

javascript面向对象学习笔记(二)——创建对象

javascript面向对象学习笔记(二)--创建对象 工厂模式 该模值抽象了创建具体对象de过程.用函数来封装噫特定接口创建对象的细节. function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; return o; } var person1=createPerson("Chiaki&

Javascript面向对象学习笔记(二)--创建对象(七种模式)

一.工厂模式 考虑到ECMAScript中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节 function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; return o; } var person1=createPerson("小码农",18,"

JavaScript面向对象学习笔记

面向对象:变量和属性一样的.属性:属于一个对象变量:属于任何一个人函数:方法:属于一个对象难点:this:当前的方法属于谁,this就是谁的例子window.show = function(){ alert(this);}//this是windowfunction show(){ alert(this);}Object:用来实现对象var obj = new Object();例子:var obj = new Object();obj.name = "zhaobw";obj.age =

Php面向对象学习笔记 – 构造、析构、对象赋值、克隆

Php面向对象学习笔记 – 构造.析构.对象赋值.克隆 class student { public  $stu_id;       // 定义成员变量 public  $stu_name; public  function sayName()   // 成员函数 { echo $this->stu_name;   // $this  访问该对象的成员变量 } } $stu = new  Student;      // 创建对象 $stu->stu_id = '0607001'; $stu-

面向对象学习笔记

abstract:抽象类或方法的关键字注意事项:一个类中至少有一个抽象方法不允许有大括号主要意义就是规范方法,要求必须按照抽象中的方法来写继承抽象类的类,必须重载完全抽象类的方法抽象类是不能被实例化的,因为本身没有意义 extends 继承的关键字 类中常用的关键字:final 被定义的类不能被继承,该类的方法不能被继承,相当于一个锁的功能self self::静态成员,相当于类名称::静态成员,和this是有区别的,$this访问类中的内容必须实例化,而self是直接可以访问类中的内容的,多用

JavaScript闭包学习笔记

原文:JavaScript闭包学习笔记 闭包(closure)是JavaScript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于JavaScript初学者应该是很有用的. 一.变量的作用域 要理解闭包,首先必须理解JavaScript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. JavaScript语言的特殊之处,就在于函数内部可以直接读取全局变量. 1 var n=999; 2 3 function f1() { 4 alert

JavaScript正则表达式学习笔记之一 - 理论基础

自从年前得空写了两篇文章之后就开始忙了,这一忙就是2个月??.当时信誓旦旦说的定期写篇博客的计划也就泡汤了??,不过好在最近有空,顺便总结一下这两个月遇到的几个问题.第一个问题就是项目中用到了一些正则才发现之前被自己忽略的正则是时候补一补了.恰逢今天周六??,就把自己学习JavaScript正则表达式的笔记整理成文,写了这篇关于正则表达式理论基础的文章,希望本文能对有需要的同学提供帮助.号外:本文相对基础,大神请忽略??. 一. 基本概念 正则表达式是用于匹配字符串中字符组合的模式. 一种几乎可

JavaScript对象-学习笔记

JavaScript权威指南学习笔记,禁止转载! 5.对象 对象的属性是无序的,每个属性都有一个字符串key和值value, 数据属性的标签:writable.enumerable.configurable.value 访问器属性的标签:enumerable.configurable.get.set.get表示属性可读,set表示属性可写.属性前面有下划线表示只能通过对象方法get/set访问的属性,也就是访问器属性. (1)创建对象 1)字面量var obj={x:1,y:2}; 2)new:

JavaScript 面向对象学习——1

公司项目采用Ext,结果本人发现入门不易!尤其是采用JavaScript编写面向对象程序,经常使用jQuery的知道,jQuery是面向函数编程的,所以很容易入门.然而,Ext是面向对象的,那么,当你想要自定义Ext组件的时候,或者使用Ext组件的时候就会很苦恼.所以,要先学习Javascript面向对象基础,其次查看Ext源代码. 这将是后期的学习路线,博客路线. 1 Javascript是基于原型(Prototype based)的面向对象的语言,Java语言,是基于类模式(Class ba