对象


  可以想象成散列表,键值对,值可以是数据或函数

创建对象的方式


  1.工厂模式

 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("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

  2.构造函数模式

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

  经历了4个步骤:

  (1)创建一个新对象;

  (2)将构造函数的作用域赋给新对象(因此this指向了这个新对象)

  (3)执行构造函数中的代码(为这个新对象添加属性)

  (4)返回新对象

  

  验证构造函数模式创造出的实例

alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true

  任何函数,只要通过new操作符调用,就可以作为构造函数;而任何函数,如果不通过new操作符调用,跟普通函数不会有什么两样 

// 当作构造函数使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"
// 作为普通函数调用
Person("Greg", 27, "Doctor"); // 添加到window
window.sayName(); //"Greg"
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"

  person1和person2都一个名为sayName()的方法,这2个方法不是同一个Function实例,每定义一个对象,就是实例化了一个对象。

  其实这是为了引申出JavaScript的原型模式,但就面向对象编程来说,各自的实例拥有各自的域本身是符合自然规律的,而JavaScript是通过原型来实现的,类似C#通过类方法的override倒是更符合正常的世界观。不过在OOP在各种语言中怎么实现的方式上,增加这种计算机域的解决方法也是可行的啊,有些语言不仅实例拥有自己独立的域,甚至不可更改,类似Scala就有这种机制,看在现在宿主环境的份上,解放开发者就是胜利,至于JavaScript就是苦了老搞不清原型的同志

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName(){
alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

  通过全局函数来实现实例公用方法,可是这样对象就没有封装性了。

  3.原型模式

  创建的每个函数都有一个prototype属性,是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中

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(); //"Nicholas" var person2 = new Person();
person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true

  只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。默认情况下,所有原型对象都会自动获得一个constructor属性,这个属性包含一个指向prototype属性所在函数的指针。

  每当代码读取某个对象实例的某个属性,都会执行一次搜索,目标是给定名字的属性。搜索首先从对象实例本身开始,如果找到则返回;如果没找到则继续搜索原型对象。

  如果在实例中添加了一个属性,而该属性与实例原型中一个属性同名,就会在实例中创建该属性,该属性将会屏蔽原型中的同名属性。  

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(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg"——来自实例
alert(person2.name); //"Nicholas"——来自原型

  通过使用delete操作符可以完全删除实例属性,从而让我们能够重新访问原型中的属性

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();
var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg"——来自实例
alert(person2.name); //"Nicholas"——来自原型
delete person1.name;
alert(person1.name); //"Nicholas"——来自原型

  使用hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中。这方法只在给定属性存在于对象实例中时,才会返回true

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();
var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false
person1.name = "Greg"; alert(person1.name); //"Greg"——来自实例
alert(person1.hasOwnProperty("name")); //true alert(person2.name); //"Nicholas"——来自原型
alert(person2.hasOwnProperty("name")); //false delete person1.name;
alert(person1.name); //"Nicholas"——来自原型
alert(person1.hasOwnProperty("name")); //false

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

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();
var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true person1.name = "Greg";
alert(person1.name); //"Greg" ——来自实例
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true
alert(person2.name); //"Nicholas" ——来自原型
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true delete person1.name;
alert(person1.name); //"Nicholas" ——来自原型
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

  判断属性是原型中的属性只要in返回true而hasOwnProperty()返回false

  

  简洁的原型写法

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

  每创建一个函数,就同时创建它的prototype对象,这个对象也会自动获得constructor属性,这种简洁的写法完全重写了默认的prototype对象,因此constructor属性就变成了新对象的constructor属性(指向Object构造函数)

var friend = new Person();

alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true

  可以特意指定

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

  由于在原型中查找值的过程是一次搜索,因此对原型对象所做的任何修改都能立即从实例上反映出来,即使是先创建了实例后修改原型也是如此

  但这样也会遇到一些问题

  

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

  friend实例指向的原型中不包含sayName方法

  

  重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系;它们引用的仍然是最初的原型

  原型对象的问题

  原型中所有属性是被多个实例共享,对于函数非常合适。但对于引用类型的属性来说,就是灾难。

  

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

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

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

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); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

  5.动态原型模式  

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);
};
}
}

引用:

《JavaScript高级程序设计中文版》

重温Javascript(二)-对象的更多相关文章

  1. 第一百二十节,JavaScript事件对象

    JavaScript事件对象 学习要点: 1.事件对象 2.鼠标事件 3.键盘事件 4.W3C与IE JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功 ...

  2. 【JavaScript】重温Javascript继承机制

    上段时间,团队内部有过好几次给力的分享,这里对西风师傅分享的继承机制稍作整理一下,适当加了些口语化的描述,留作备案. 一.讲个故事吧 澄清在先,Java和Javascript是雷锋和雷峰塔的关系.Ja ...

  3. 基本类型和引用类型的值 [重温JavaScript基础(一)]

    前言: JavaScript 的变量与其他语言的变量有很大区别.JavaScript 变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类 ...

  4. javascript的对象

    简介: JavaScript 中的所有事物都是对象:字符串.数字.数组.日期,等等.在 JavaScript 中,对象是拥有属性和方法的数据. 一.对象的类型 本地对象:就是ECMA定义好的一些对象, ...

  5. 从零构建JavaScript的对象系统

    一.正统的类与继承 类是对象的定义,而对象是类的实例(Instance).类不可直接使用,要想使用就必须在内存上生成该类的副本,这个副本就是对象. 以Java为例: public class Grou ...

  6. 据说每个大牛、小牛都应该有自己的库——JavaScript原生对象拓展

    在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏,一是,关于写个自己的库的想法由来 ...

  7. 关于JavaScript中对象的继承实现的学习总结

    一.原型链 JavaScript 中原型链是实现继承的主要方法.其主要的思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.实现原型链有一种基本模式,其代码如下. function Super ...

  8. javascript中对象的深度克隆

    记录一个常见的面试题,javascript中对象的深度克隆,转载自:http://www.2cto.com/kf/201409/332955.html 今天就聊一下一个常见的笔试.面试题,js中对象的 ...

  9. JavaScript DOM对象和JQuery对象相互转换

    1.分析源代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  10. 从头开始学JavaScript (二)——变量及其作用域

    原文:从头开始学JavaScript (二)--变量及其作用域 一.变量 ECMAscript变量是松散型变量,所谓松散型变量,就是变量名称可以保存任何类型的数据,每个变量仅仅是一个用于保存值的占位符 ...

随机推荐

  1. solr-建立单机版的服务器

    回到之前打开的页面,刷新,wenda就出来了: 这个wenda是单机版的.

  2. iOS内购流程一(协议、税务和银行业务)

    协议.税务和银行业务,这一选项是当你App使用了In-app purchaes时候,你跟苹果签订协议的,需要签订合同和填写你的银行收款等信息 一.填写法人信息 1.登录iTunes Store,点击协 ...

  3. IOSerialize,xml和json,soap序列化器,二进制序列化器,XML序列化器,文件 检查、新增、复制、移动、删除

    1 文件夹/文件 检查.新增.复制.移动.删除,2 文件读写,记录文本日志/读取配置文件3 三种序列化器4 xml和json1.文件夹/文件 检查.新增.复制.移动.删除,2 文件读写,记录文本日志/ ...

  4. qsc52(三角形线性插值)

    题目链接:http://qscoj.cn/problem/52/ 题意:中文题诶- 思路:水题,只要知道三角形插值和判断点在三角形内就OK了 关于三角形插值:http://www.cnblogs.co ...

  5. python2与python3 版本区别

    目录 编码 输入输出 中文 除法 长整形 内置函数map xrange init reduce 字符串类型 dict字典 经典类 新式类 未完待补充 编码 python2默认编码器为ascii码(只支 ...

  6. atom 插件 python语法验证linter-flake8-------填坑

    python的语法相对于一般语言的语法比较严格.对于刚刚从前端入门python的我来说,有时候代码写完了,然后报错,好多语法错误.所以这个时候一个好的语法验证插件是很好的.linter-flake8这 ...

  7. JMeter(7) 优化判断返回类型和返回值

    之前判断接口类型和返回值用beanshell,可见JMeter(5)-JMeter之BeanShell使用 优化点 接口测试里面对返回字段的类型验证和值验证为基本需求,将方法导成jar文件,导入之后方 ...

  8. CSS样式之操作属性二

    ********css样式之属性操作******** 一.文本属性 1.text-align:cnter 文本居中 2.line heigth 垂直居中 :行高,和高度对应 3.vertical-al ...

  9. redis最佳实践

    总结: String类型的value(string/list/set/hash)使用StringRedisTemplate 其他类型的value(string/list/set/hash/object ...

  10. 转 SecureCRT 遇到一个致命的错误且必须关闭——解决

    http://blog.csdn.net/lisheng19870305/article/details/45537759 问题描述: 1.以前安装过SecureCRT,现在出现问题,手工卸载不完全, ...