ECMA-262 把对象定义为:”无序属性的集合,其属性可以包含基本值、对象或者函数。”可以把 ECMAScript 的对象想象成散列表:无非就是一组名值对,其中值可以是数据或函数。
 
6.1.理解对象
创建自定义对象的两种方式:
(1)创建一个 Object 的实例:  var person = new Object(); 
(2)对象字面量(首选):  var person = {};  
---------------------------------------------------------------------------------------------
ECMAScript 中有两种属性:数据属性和访问器属性。
数据属性包含一个数据值的位置。
    要修改属性默认的特性,必须使用 ECMAScript 5 的 Object.defineProperty() 方法。
访问器属性不包含数据值,它们包含一对 getter 和 setter 函数。
    访问器属性不能直接定义,必须使用 Object.defineProperty() 来定义。
    __year:year 前面的下划线是一种常用的标记,表示只能通过对象方法访问。
----------------------------------------------------------------------------------------------
定义多个属性:Object.defineProperties() 方法,可同时定义数据属性和访问器属性。
----------------------------------------------------------------------------------------------
读取属性的特性:Object.getOwnPropertyDescriptor() 方法,可以取得给定属性的描述符。
 
6.2.创建对象
6.2.2 构造函数模式
构造函数与其他函数的唯一区别,就在于调用它们的方式不同。任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过 new 操作符来调用,那它就跟普通函数也不会有什么两样。
// 当作构造函数使用
var person = new Person("Nick", 29, "Software Engineer");
person.sayName(); //"Nick" // 作为普通函数调用
Person("Greg", 27, "Doctor");
window.sayName(); //"Greg" //在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"

构造函数的主要问题:每个方法都要在实例上重新创建一遍,因为 ECMAScript 中的函数是对象,因此每定义一个函数,也就实例化了一个对象。

6.2.3 原型模式
我们创建的每个函数都有一个 prototype(原型)属性,该属性是一个指针,指向一个对象。
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。
(1)理解原型对象
    无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个 constructor (构造函数)属性,该属性包含指向 prototype 属性所在函数的指针。
    创建了自定义的构造函数之后,其原型对象默认只会取得 constructor 属性;至于其他方法,则都是从 Object 继承而来的。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针([[Prototype]],内部属性),指向构造函数的原型对象。
在所有实现中都无法访问到[[Prototype]],可以通过 isPrototypeOf() 方法来确定对象之间是否存在实例和原型的关系:
alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true
ECMAScript 5 新增了一个新方法,叫 Object.getPrototypeOf(),返回 [[Prototype]] 的值:
alert(Object.getPrototypeOf(person1) === Person.prototype);    //true
alert(Object.getPrototypeOf(person1).name); //"Nicholas"
使用 hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是存在于原型中。这个方法(不要忘了它是从 Object 继承来的)只在给定属性存在于对象实例中时,才会返回 true。通过该属性,什么时候访问的是实例属性,什么时候访问的是原型属性就一清二楚了。
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

ECMAScript 5 的 Object.getOwnPropertyDescriptor() 方法只能用于实例属性,要取得原型属性的描述符,必须直接在原型对象上调用 Object.getOwnPropertyDescriptor() 方法。

(2)原型与 in 操作符
有两种方式使用 in 操作符:单独使用和在 for-in 循环中使用。在单独使用时,in 操作符会在通过对象访问给定属性时返回 true,无论该属性存在于实例中还是原型中。
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;
同时使用 hasOwnProperty() 方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中。
function hasPrototypeProperty ( object, name ) {
return !object.hasOwnProperty ( name ) && ( name in object );
}
在使用 for-in 循环时,返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。屏蔽了原型中不可枚举属性(即将 [[Enumerable]] 标记为 false 的属性)的实例属性也会在 for-in 循环中返回,因为根据规定,所有开发人员定义的属性都是可枚举的。
不可枚举的属性和方法:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()、valueOf()、constructor、prototype
取得对象上所有可枚举的实例属性,可以使用 ECMAScript 5 的 Object.keys() 方法。
如果想要得到所有实例属性,无论它是否可枚举,都可以使用 Object.getOwnPropertyNames() 方法。
Object.keys() 和 Object.getOwnPropertyNames() 方法都可以用来替代 for-in 循环。
(3)更简单的原型语法
function Person(){
} Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function () {
alert(this.name);
}
};

注意:以这种方式重设 constructor 属性会导致它的 [[Enumerable]] 特性被设置为 true。默认情况下,原生的 constructor 属性是不可枚举的。

6.2.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 Enginner");
var person2 = new Person("Greg", 27, "Doctor"); person1.friends.push("Van");
alert(person1.friends); //"Shelby, Court, Van"
alert(person2.friends); //"Shelby, Court"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

参考文章:深入解读JavaScript面向对象编程实践

JS核心系列:浅谈 原型对象和原型链

A Plain English Guide to JavaScript Prototypes

《JS高程》对象&原型学习笔记的更多相关文章

  1. 《JS高程》事件学习笔记

    事件:文档或浏览器窗口中发生的一些特定的交互瞬间,也即用户或浏览器自身执行的某种动作. -------------------------------------------------------- ...

  2. 《JS高程》数据类型学习笔记

    认认真真看完了<JavaScript高级程序设计>第3章的基本概念,原来一直不明白的知识点都在这里面啊...T_T...基础真的很重要,很重要,很重要... 现在终于明白了读书的技巧,书读 ...

  3. js类、原型——学习笔记

    js 内置有很多类,我们用的,都是从这些类实例化出来的. function Object () {} function Array () {} function String () {} functi ...

  4. 《JS高程》引用类型学习笔记

    2月圆满的结束了,结束之前是如凤凰般的涅槃.一边上班,一边搞科研的忙碌有点让人透不过气,心会不由得浮躁起来.但是,无论什么事情,只要充满耐心.专心去做,总会朝好的方向发展,心态真的很重要.Anyway ...

  5. 《Node.js核心技术教程》学习笔记

    <Node.js核心技术教程>TOC \o "1-3" \h \z \u 1.章模块化编程 2019.2.19 13:30' PAGEREF _101 \h 1 08D ...

  6. JavaScript原型学习笔记

    1 理解JavaScript原型 什么是原型? 原型是一个对象,其他对象可以通过它实现属性继承. 任何一个对象都可以成为原型么? 是 哪些对象有原型 所有的对象在默认的情况下都有一个原型,因为原型本身 ...

  7. C++中临时对象的学习笔记

    http://www.cppblog.com/besterChen/category/9573.html 所属分类: C/C++/STL/boost  在函数调用的时候,无论是参数为对象还是返回一个对 ...

  8. 关于js的对象原型继承(一)

    javascript中,对象的继承是通过原型去继承. 可以这样理解:js中的对象,包含的除了属性和方法,还有一个最基本的原型__proto__对象.这个原型__proto__指向谁,这个对象就继承谁. ...

  9. 深度剖析前端JavaScript中的原型(JS的对象原型)

          这张图片有点劝退了,哈哈哈~    通过原型机制,JavaScript 中的对象从其他对象继承功能特性:这种继承机制与经典的面向对象编程语言的继承机制不同.本文将探讨这些差别,解释原型链如 ...

随机推荐

  1. Socket通信(转)

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户 ...

  2. NOIP2005 等价表达式 解题报告

    明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和 ...

  3. Debug的F5~F8用法

    快捷键(F6)单步执行程序,遇到方法时跳过. 快捷键(F8)执行此断点到最后,进入下一个断点开始之处. 快捷键(F5)单步执行程序,遇到方法时进入. 快捷键(F7)单步执行程序,从当前方法跳出.

  4. Delphi 的 7zip 压缩算法

    http://blog.csdn.net/warrially/article/details/8039915

  5. ie浏览器兼容性快速处理小招

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. zookeeper启动失败无法查看status-----用户权限

    最近一直在调试zookeeper,总是出现莫名其妙的问题 QuorumPeerMain 进程存在,但是无法查看status, JMX enabled by defaultUsing config: / ...

  7. office2013不能正常使用

    感觉非常卡一样 还不能显示内容 工具栏也点不动   这个应该是Office硬件图形加速惹得祸,解决办法: 文件>选项>高级>显示,找到“禁用硬件图形加速”在前面打勾,关闭再打开就OK ...

  8. SimpleDateFormat()简单了解

    比如:SimpleDateFormat sdf1 = new  SimpleDateFormat("yyyy年MM天dd日 HH时mm分ss秒 一年中的第 D 天 一年中第w个星期 一月中第 ...

  9. UIScrollerView常见属性

    CGSize contentSize :设置UIScrollView的滚动范围 CGPoint contentOffset :UIScrollView当前滚动的位置 UIEdgeInsets cont ...

  10. Android布局— — —表格布局

    表格布局 以表格的形式来显示界面中的控件,表格的每一行为一个TableRow,每当一个控件添加到TableRow中,就生成一个单元格. 语法格式: <TableLayout xmlns:andr ...