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值。
javascript面向对象学习笔记——创建对象(转)的更多相关文章
- JavaScript面向对象学习笔记
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)--每个对象拥有一个原型对象,对象以其原型为模板.从原型继承方法和属性.原型对象也可能拥有原型, ...
- JavaScript正则表达式学习笔记(二) - 打怪升级
本文接上篇,基础部分相对薄弱的同学请移步<JavaScript正则表达式学习笔记(一) - 理论基础>.上文介绍了8种JavaScript正则表达式的属性,本文还会追加介绍几种JavaSc ...
- javascript正则表达式 - 学习笔记
JavaScript 正则表达式 学习笔记 标签(空格分隔): 基础 JavaScript 正则表达式是用于匹配字符串中字符组合的模式.在javascript中,正则表达式也是对象.这些模式被用于Re ...
- JavaScript简易学习笔记
学习地址:http://www.w3school.com.cn/js/index.asp 文字版: https://github.com/songzhenhua/github/blob/master/ ...
- javaScript 对象学习笔记
javaScript 对象学习笔记 关于对象,这对我们软件工程到学生来说是不陌生的. 因为这个内容是在过年学到,事儿多,断断续续,总感觉有一丝不顺畅,但总结还是要写一下的 JavaScript 对象 ...
- 【MarkMark学习笔记学习笔记】javascript/js 学习笔记
1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...
- Javascript MVC 学习笔记(一) 模型和数据
写在前面 近期在看<MVC的Javascript富应用开发>一书.本来是抱着一口气读完的想法去看的.结果才看了一点就傻眼了:太多不懂的地方了. 仅仅好看一点查一点,一点一点往下看吧,进度虽 ...
- Javascript作用域学习笔记(三)
看完<你不知道的javascript>上,对作用域的新的理解(2018-9-25更) 一.学习笔记: 1.javascript中的作用域和作用域链 + 每个函数在被调用时都会创建一个 ...
- PHP:面向对象学习笔记,重点模拟Mixin(掺入)
背景 相对于Python.Node和Ruby来说PHP算是一门容易学习和使用的语言,因为这个特点也使其成为WEB开发领域的佼佼者,本文记录一下我对PHP面向对象部分的学习笔记. 先来一个复杂的例子:M ...
随机推荐
- Delphi RICHEDIT中插入图象
unit InsRich;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- Selenium2Library系列 keywords 之 _SelectElementKeywords 之 list_selection_should_be(self, locator, *items)
def list_selection_should_be(self, locator, *items): """Verifies the selection of sel ...
- DataGrid的打印预览和打印
using System;using System.Drawing;using System.Collections;using System.ComponentModel;using System. ...
- C# 中如何判断某个字符串是否为空的方法 分享了三个方法来判断字
1. 三种常用的字符串判空串方法:Length法:bool isEmpty = (str.Length == 0);Empty法:bool isEmpty = (str == String.Empty ...
- HTML 5:你必须知道的data属性
原文:All You Need to Know About the HTML5 Data Attribute 译文:你必须知道HTML 5 的Data属性 译者:dwqs HTML 5的Data属性可 ...
- 内核源码分析之进程调度机制(基于3.16-rc4)
进程调度所使用到的数据结构: 1.就绪队列 内核为每一个cpu创建一个进程就绪队列,该队列上的进程均由该cpu执行,代码如下(kernel/sched/core.c). DEFINE_PER_CPU_ ...
- 【Spark学习】Apache Spark作业调度机制
Spark版本:1.1.1 本文系从官方文档翻译而来,转载请尊重译者的工作,注明以下链接: http://www.cnblogs.com/zhangningbo/p/4135905.html 目录 概 ...
- HDU4861:Couple doubi(费马小定理)
题意: 给出k个球和质数p,对每个球以公式val(i)=1^i+2^i+...+(p-1)^i (mod p)计算出它的价值,然后两个人轮流拿,最后拿到的球的总价值大的获胜,问我们先手是否获胜. 我们 ...
- ocp 1Z0-043 61-130题解析
61. You are working in an online transaction processing (OLTP) environment. You realize that the sal ...
- POJ 3670 Eating Together (DP,LIS)
题意:给定 n 个数,让你修改最少的数,使得它变成一个不下降或者不上升序列. 析:这个就是一个LIS,但是当时并没有看出来...只要求出最长LIS的长度,用总数减去就是答案. 代码如下: #inclu ...