1.对象的定义

ECMAScript中,对象是一个无序属性集,这里的“属性”可以是基本值、对象或者函数

2.数据属性与访问器属性

  • 数据属性即有值的属性,可以设置属性只读、不可删除、不可枚举等等

  • 访问器属性是用来设置getter和setter的,在属性名前加上”_”(下划线)表示该属性只能通过访问器访问(私有属性),但并不是说添个下划线就把属性变成私有的了,这只是习惯约定的一种命名方式而已。访问器属性没什么用,原因如下:

    高程中使用了上面的示例代码,原理是book对象的属性中_year是数据属性,而year是访问器属性,利用gettter和setter可以插入读写控制,听起来不错。

    但问题是_year和edition都是可枚举的,也就是说用for...in循环可以看到,而访问器属性year却是不可枚举的。应该公开的访问器不公开,却把应该隐藏的私有属性公开了。

    除此之外,这种定义访问器的方式并不是全浏览器兼容的,[IE9+]才完整支持,当然,也有适用于旧浏览器的方式(__defineGetter__()和__defineSetter__()),还是相当麻烦。

    总之,访问器属性没什么用。

3.构造函数

function Fun(){} var fun = new Fun();其中Fun是构造函数,与普通函数没有任何声明方式上的区别,只是调用方式不同(用new操作符调用)而已

构造函数可以用来定义自定义类型,例如:

与Java的类声明有些相似,但也有一些差异,比如this.fun只是一个函数指针,因此完全可以让它指向可访问的其它函数(如全局函数),但这样做会破坏自定义对象的封装性

4.函数与原型prototype

  1. 声明函数的同时也创建了一个原型对象,函数名持有该原型对象的引用(fun.prototype)

  2. 可以给原型对象添加属性,也可以给实例对象添加属性,区别是原型对象的属性是该类型所有实例所共享的,而实例对象的属性是非共享的

  3. 访问实例对象的属性时,先在该实例对象的作用域中查找,找不到才在原型对象的作用域中查找,因此实例的属性可以屏蔽原型对象的同名属性

  4. 原型对象的constructor属性是一个函数指针,指向函数声明

  5. 通过原型可以给原生引用类型(Object,Array,String等)添加自定义方法,例如给String添加Chrome不支持但FF支持的startsWith方法:

    注意:不建议给原生对象添加原型属性,因为这样可能会意外重写原生方法,影响其它原生代码(调用了该方法的原生代码)

  6. 通过原型可以实现继承,思路是让子类的prototype属性指向父类的实例,以增加子类可访问的属性,所以用原型链连接之后

    1
    2
    3
    4
    5
    子类可访问的属性
    = 子类实例属性 + 子类原型属性
    = 子类实例属性 + 父类实例属性 + 父类原型属性
    = 子类实例属性 + 父类实例属性 + 父父类实例属性 + 父父类原型属性
    = ...

    最终父父...父类原型属性被替换为Object.prototype指向的原型对象的属性

    具体实现是SubType.prototype = new SuperType();可称之为简单原型链方式的继承

5.创建自定义类型的最佳方式(构造函数模式 + 原型模式)

实例属性用构造函数声明,共享属性用原型声明,具体实现如下:

1
2
3
4
5
6
7
8
9
10
function MyObject(){
  //实例属性
  this.attr = value;
  this.arr = [value1, value2...];
}
MyObject.prototype = {
  constructor: MyObject,//保证子类持有正确的构造器引用,否则子类实例的constructor将指向Object的构造器,因为我们把原型改成匿名对象了
  //共享属性
  fun: function(){...}
}

6.实现继承的最佳方式(寄生组合式继承)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function object(obj){//返回原型为obj的没有实例属性的对象
  function Fun(){}
  Fun.prototype = obj;
  return new Fun();
}
function inheritPrototype(subType, superType){
  var prototype = object(superType.prototype);//建立原型链,继承父类原型属性,用自定义函数object处理是为了避免作为子类原型的父类实例具有实例属性,简单地说,就是为了切掉除多余的实例属性,可以对比组合继承理解
  prototype.constructor = subType;//保证构造器正确,原型链会改变子类持有的构造器引用,建立原型链后应该再改回来
  subType.prototype = prototype;
}
 
function SubType(arg1, arg2...){
  SuperType.call(this, arg1, arg2...);//继承父类实例属性
  this.attr = value;//子类实例属性
}
inheritPrototype(SubType, SuperType);

具体解释见代码注释,这种方式避免了SubType.prototype = new SuperType();简单原型链的缺点:

  • 子类实例共享父类实例引用属性的问题(因为原型引用属性是所有实例共享的,建立原型链后父类的实例属性就自然地成了子类的原型属性)。

  • 创建子类实例时无法给父类构造函数传参

7.实现继承的最常用方式(组合继承)

把上面的inheritPrototype(SubType, SuperType);语句换成:

1
2
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

这种方式的缺点是:由于调用了2次父类的构造方法,会存在一份多余的父类实例属性,具体原因如下:

第一次SuperType.call(this);语句从父类拷贝了一份父类实例属性给子类作为子类的实例属性,第二次SubType.prototype = new SuperType();创建父类实例作为子类原型,此时这个父类实例就又有了一份实例属性,但这份会被第一次拷贝来的实例属性屏蔽掉,所以多余。

JavaScript学习笔记2_面向对象的更多相关文章

  1. javascript 学习笔记之面向对象编程(一):类的实现

    ~~想是一回事,做是一回事,写出来又是一回事~~一直以来,从事C++更多的是VC++多一些,从面向过程到面向对象的转变,让我对OO的编程思想有些偏爱,将一个客观存在的规律抽象出来总是让人比较兴奋,通过 ...

  2. javascript 学习笔记之面向对象编程(二):继承&多态

    ~~接上篇~~上一篇实现了类的实现以及类成员变量和方法的定义,下面我们来了解下面向对象中两个最重要的特性:继承和多态. 继承 js中同样可以实现类的继承这一面向对象特性,继承父类中的所有成员(变量和属 ...

  3. JS学习笔记2_面向对象

    1.对象的定义 ECMAScript中,对象是一个无序属性集,这里的“属性”可以是基本值.对象或者函数 2.数据属性与访问器属性 数据属性即有值的属性,可以设置属性只读.不可删除.不可枚举等等 访问器 ...

  4. Java程序猿的JavaScript学习笔记(6——面向对象模拟)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  5. Java程序猿的JavaScript学习笔记(汇总文件夹)

    最终完结了,历时半个月. 内容包含: JavaScript面向对象特性分析,JavaScript高手必经之路. jQuery源代码级解析. jQuery EasyUI源代码级解析. Java程序猿的J ...

  6. Java程序猿的JavaScript学习笔记(8——jQuery选择器)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  7. Java程序猿JavaScript学习笔记(2——复制和继承财产)

    计划和完成在这个例子中,音符的以下序列: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaSc ...

  8. Java程序猿的JavaScript学习笔记(3——this/call/apply)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  9. Java程序猿JavaScript学习笔记(4——关闭/getter/setter)

    计划和完成这个例子中,音符的顺序如下: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScr ...

随机推荐

  1. 使用原理视角看 Git

    1. Git 的玩法 欢迎来到 Coding 技术小馆,我叫谭贺贺,目前我在 Coding.net 主要负责 WebIDE 与 Codeinsight 的开发.我今天带来的主要内容是 Git 的原理与 ...

  2. 高级软件测试技术(测试管理工具实践day4)

    今天是截止日期,有胡俊辉的指导下小组成员都了解使用了Bugzilla的基本使用.大家都在晚上之前把各自的文档汇总给汪鸿,由他撰写了操作手册.并且在下午杨瑞丰完成了视频的录制工作.但是在转化为MP4 格 ...

  3. 牌型总数——第六届蓝桥杯C语言B组(省赛)第七题

    原创 牌型种数 小明被劫持到X赌城,被迫与其他3人玩牌.一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张.这时,小明脑子里突然冒出一个问题:如果不考虑花色,只考虑点数,也不考虑自己得 ...

  4. Ubuntu设置root账户密码

    创建Ubuntu后是没有root账户的,执行 sudo passwd root 然后系统会提示你输入普通用户的密码.输入后,按回车,然后重复输入两次新的root密码即可激活root用户.

  5. C#验证身份证号码正确性

    18位号码: private static bool CheckIDCard18(string Id) { ; ), , ) || '), out n) == false) { return fals ...

  6. MariaDB 一些SQL语句的执行

    通过拼接的TAG_NAME字符串获取对应的TAG_ID字符串 形如: '丹药|练功流|轻松|学生|学院风' 查询结果:'10|35|36|40' SELECT GROUP_CONCAT(TAG_ID ...

  7. 游戏中遇到的BUG

    (1)bug描述:战斗中有英雄死亡,一方掉线之后再次上线,仍然可以看到死亡英雄空血条(英雄受到攻击才会显示血条) 解决方案:原来 当前血量小于英雄血量最大值时,证明英雄受到伤害,血条显示为true I ...

  8. angular 样式属性绑定

    <button (click)="onClick($event)">点我</button> <input type="> <ta ...

  9. 动态内存分配存在的问题(内存空洞)------c++程序设计原理与实践(进阶篇)

    new的问题究竟在哪里呢?实际上问题出在new和delete的结合使用上.考察下面程序中内存分配和释放过程: while(1){ Big* p=new big; //...... Small* n1= ...

  10. docker--基本命令

    仅做学习参考,可能有误 part1:启动docker服务 在Windows上使用MySQL时候,有时无法直接使用MySQL -uroot -p 来进入MySQL,这是因为我们没有启动会MySQL服务此 ...