第6章 面向对象的程序设计

ECMAScript中没有类的概念;

1.创建对象-历史

1.1 创建实例,添加方法和属性 → 对象字面量

缺点: 使用同一接口创建很多对象,产生大量重复代码

var person = new Object()
person.name = "Y"
person.age = 18
person.job = "police"person.sayName = function() {alert(this.name)
}

var person = {name = "Y",age = 18,job = "police",sayName = function() {alert(this.name)}
}

1.2 工厂模式 (返回对象)

缺点: 没有解决对象识别的问题:怎样知道一个对象的类型;
特点: 内部创建对象,并返回

function createPerson(name, age, job) {var o = new Object()o.name = nameo.age = ageo.job = jobo.sayName = function () { alert(this.name)}return o
}

1.3 构造函数模式

缺点: 每个方法都要在每个实例上重新创建一遍!不同实例上的同名函数是不相等的,然而,创建2个完成同样任务的Function实例的确没有必要。
特点
没有显示创建对象;
没有return;
将方法属性赋值给this对象;
首字母大写;
构造函数创建的实例标识为一种特定的类型

1.3.1 理解面试题

调用构造函数创建对象,实际会经历以下4个步骤:

  1. 创建一个新对象;
  2. 将构造函数的作用域赋值给新对象(this指向这个新对象)
  3. 执行构造函数代码(为这个新对象添加属性方法)
  4. 返回新对象
function Person(name, age, job) {this.name = namethis.age = agethis.job = jobthis.sayName = function () { // 每定义一个函数,就是实例化一个对象alert(this.name)}
}
var p1 = new Person("Y",18,"police")
var p2 = new Person("H",8,"teacher")
// p1.constructor == Person
// p2.constructor == Person// ( p1 instanceOf Object  )  true
//  ( p1 instanceOf Person  )  true
// ( p2 instanceOf Object  )  true
//  ( p2 instanceOf Person  )  true
  • 在全局作用域调用函数,this总是指向GLOBAL对象
function person(name, age, job) {this.name = namethis.age = agethis.job = jobthis.sayName = function () { alert(this.name)}
}
person('Leo', 16, 'doctor')
window.sayName() //leo

1.3.2 将构造函数当做函数

任何函数,只要通过new操作符来调用,便可以作为构造函数;若不用,即与普通函数无异。this会指向Global对象(在浏览器中就是window)

1.3.3 将方法定义到构造函数外部

缺点: 在全局作用域上定义的函数,若只能被某个对象调用,不合理;并且,如果对象需要定义很多方法,则需要定义很多个全局函数,对于这个自定义的引用类型就丝毫没有封装性可言。

function Person(name, age, job) {this.name = namethis.age = agethis.job = job
}
function sayName() {alert(this.name)
}

1.4 原型模式

1.4.1 理解原型模式

function Person() {}
Person.prototype.name = "Y"
Person.prototype.age = 18
Person.prototype.job = "police" Person.prototype.sayName = function () {alert(this.name)
}
  1. 使用原型对象的好处:让所有的对象实例共享它所包含的属性和方法;
  2. 只要创建了一个新函数,就会为该函数创建一个prototype属性,指向函数的原型对象
  3. 原型对象会自动获得constructor属性,该属性包含一个指向prototype属性所在函数的指针(constructor属性指向构造函数);
  4. 对象的constructor属性最初是用来表示对象类型的;
  5. 构造函数创建的实例,实例内部包含一个指针,指向构造函数的原型对象
  6. Person.prototype.isPrototypeOf(p1) // true
  7. Object.getPrototypeOf(p1) == Person.prototype // true
  8. 代码读取某个对象某个属性时,先搜索对象实例,若无再搜索原型对象;
  9. 若实例中添加的属性和原型属性同名,会屏蔽原型中的属性(因为实例只能访问原型中的值,而不能重写);
  10. 若将实例中的同名属性设为null,并不能恢复与原型的连接,需要使用delete操作符完全删除实例属性;
  11. p1.hasOwnProperty("name")// true hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型,若来自实例则返回true

1.4.2 in操作符

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

"name" in p1 // true

1.4.3 确认属性存在于原型

function hasPrototypeProperty(object,name) {return !object.hasOwnProperty(name) && (name in object)
}

1.4.4 更简单的原型语法

缺点: constructor属性不再指向Person,切断了实例和原型对象的联系;对包含引用类型值的属性,被实例共享会造成问题。
特点: 减少不必要的输入(每添加一个属性/方法就要多敲一遍Person.prototype)

将Person.prototype设置为一个以对象字面量形式创建的新对象,本质上重写了prototype对象(创建函数时自动创建的原型对象),导致constructor属性指向Object构造函数,尽管instanceof还能返回正确的结果。

function Person() {}
Person.prototype = {name : "Y",age : 18,job : "police",sayName: function () {alert(this.name)}
}
p1 instanceof Object // true
p1 instanceof Person // true
p1.constructor == Person // false
p1.constructor == Object // true

增加constructor属性,确保该属性能访问到适当的值。

function Person() {}
Person.prototype = {constructor : Person,name : "Y",age : 18,job : "police",sayName: function () {alert(this.name)}
}

1.4.5 原生对象的问题

function Person() {}
Person.prototype = {constructor : Person,friends:["Yoona","Jessica"], // 数组,引用类型name : "Y",age : 18,job : "police",sayName: function () {alert(this.name)}
}
p1.friends.push("Krystal")
p1.friends == p2.friends

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

构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。(实例属性中的引用类型互不干扰)

function Person(name, age, job) {this.name = namethis.age = agethis.job = jobthis.friends = ["Yoona","Jessica"]
}Person.prototype = {constructor : Person,sayName: function () {alert(this.name)}
}

1.4.7 原生对象的原型

通过原生对象的原型,不仅可以取得所有默认方法的引用,也可以定义新方法。但不推荐在产品化的程序中修改原生对象的原型:
如果因为某个实现中缺少某个方法,就在原始对象的原型中添加,那么当在另一个支持该方法的实现中运行代码时,就可能会导致命名冲突,而且这样做也可能会意外地重写原生方法。

1.5 梳理

1.6 修改原生对象的原型

String.prototype.startsWith = function(){}

在当前环境中,所有字符串都可以调用startsWith,但不推荐,可能会产生命名冲突,也可能会意外地重写原生方法。

String.prototype.
toString = function () {console.log('修改原生对象默认方法')
}'str'.toString() // 修改原生对象默认方法

将原生对象原型指向空,没效果

String.prototype = null
console.log('str'.toString()) // str

2. 属性类型 P139

2.1 数据属性

  1. [[Configurable]]:能否通过delete删除属性,默认为true
  2. [[Enumerable]]:能否通过for-in循环返回属性,默认为true
  3. [[Writeable]]:能否修改属性的值,默认为true
  4. [[Value]]:属性值,默认为undefined
  • 一旦把属性定义为不可配置的,就不能再把它变回可配置了;
  • 要修改属性默认的特性,必须使用Object.defineProperty(),3个参数:对象、属性名、描述符对象(属性必须是数据属性),若不指定数据属性,则默认为false;

2.2 访问器属性

  1. 包含一对getter和setter函数(都不是必须的),有4个特性:
    1) [[Configurable]]
    2) [[Enum而able]]
    3) [[Get]]:读取属性时默认调用的函数,默认值undefined
    4) [[Set]]:写入属性时默认调用的函数,默认值undefined
  • 属性 _year 前面的下划线用于表示只能通过对象方法访问的属性;
  • 使用访问器属性的常见方式:设置一个属性的值会导致其他属性发生变化;

2.3 读取属性

Object.getOwnPropertyDescriptor(),2个参数:对象、属性

var descriptor = Object.getOwnPropertyDescriptor(person,"age")
alert(age.value)
alert(age.enumerable)
alert(age.configurable)
alert(age.get)

方法集合

Object.defineProperty() // 修改属性默认值
Object.getOwnPropertyDescriptor() //读取属性的描述符
谁谁的原型对象.isPrototypeOf(实例) // 参数是实例,判断实例内部是否有指向构造函数原型对象的指针
hasOwnProperty() // 检测属性来自实例(返回true)还是原型

3. 继承(子类继承父类的特征和行为)

3.1 原型链

原型链的问题

  1. P166 原型链虽然很强大,可以用它来实现继承,但它也存在一些问题,其中最主要的问题来自包含引用类型值的原型。包含引用类型值的原型属性会被所有实例共享,因此要在构造函数,而不是原型对象中定义属性。
  2. 在创建子类型的实例时,不能向超类型的构造函数中传递参数。(没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数)

让原型对象等于另一个类型的实例。

SubType.prototype = new SuperType()

SubType的实例指向SubType的原型,进而又指向SuperType的原型

3.2 默认的原型

所有引用类型默认都继承了Object,所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype,这也正是所有自定义类型都会继承toString()、valueOf()等默认方法的根本原因。完整的原型链如下:

instance instanceof Object // true
instance instanceof SuperType // true
instance instanceof SubType // trueObject.prototype.isPrototypeOf(instance) // true
SuperType.prototype.isPrototypeOf(instance) // true
SubType.prototype.isPrototypeOf(instance) // true
function Fun() {}console.log(Fun.prototype.__proto__==Object.prototype) // true

3.3 组合继承

  1. 父构造函数内有引用类型属性值
  2. 子构造函数内使用call(保证了实例不会都指向同一个引用类型)
  3. 子构造函数原型指向父构造函数原型(Object.create
  4. 子构造函数原型里的构造器指向自己(知晓实例由谁创建)

4. 方法整理

  • A.isPrototypeOf(a)
    // 实例a的__proto__指向A的原型
    // 判断原型对象A是否是实例a的原型,是则返回true
  • a.hasOwnProperty(‘name’) 判断属性是否存在于实例中(实例属性),是则返回true
    Object.keys() 获得对象上所有可枚举的属性
  • ‘name’ in a 无论原型/实例,只要是能访问得到的属性,in操作符返回true(包括constructor)'name’字符串
    for-in循环,返回所有能通过对象访问的、可枚举的属性 ,(遍历一个实例对象,原型上的属性也会打印、要只打印实例属性,需要配合hasOwnProperty)
  • Object.getOwnPropertyNames(),得到所有实例属性,包括constructor
function Test(name) {this.name = name
}
Test.prototype.name = 'hhh'
let tObj = new Test('yyy')
console.log('name' in tObj) // true
console.log('constructor' in tObj) // true
for(var prop in tObj){console.log('for-in', prop) // name
}

重学《JavaScript 高级程序设计》笔记 第6章对象相关推荐

  1. JavaScript高级程序设计笔记01 | 第一章到第四章 | 关键字与保留字 | 数据类型 | 操作符 | 作用域

    观前提示:大部分都是书上的内容,个人理解的部分的较少,看我的笔记还不如去看书 第二章 async:可选.表示应该立即下载脚本,但不应妨碍页面中的其他操作,比如下载其他资源或 等待加载其他脚本.只对外部 ...

  2. JavaScript高级程序设计笔记 - 第四章 变量 作用域 内存问题

    4.1 基本类型和引用类型的值 基本类型: 简单的数据段 引用类型: 指那些可能有多个值构成的对象, 指保存在内存中的对象 4.1.2 复制变量值 除了保存的方式不同之外,在从一个变量向另一个变量复制 ...

  3. javascript高级程序设计--笔记01

    概述 JavaScript的实现包含三个部分: 1  核心(ECMAScript)   提供核心语言功能 2  文档对象模型(DOM)  一套提供了访问以及操作网页内容的API 3  浏览器对象模型( ...

  4. 《javascript高级程序设计》第六章 读书笔记 之 javascript对象的几种创建方式

    本文首发于https://segmentfault.com/a/1190000017776314 一.工厂模式 工厂模式:使用字面量和object构造函数会有很多重复代码,在此基础上改进 解决了多个相 ...

  5. javascript高级程序设计笔记

    1.要讲一个值转换成其对应的Boolean类型 ,可以调用转型函数Boolean(). var message="hello world!"; var messageAsBoole ...

  6. 笔记《javascript高级程序设计》 第12章 DOM2和DOM3

    DOM2 级核心:在 1 级基础上构建,为节点添加更多方法和属性 DOM2 级视图:为文档定义了基于样式信息的不同视图 DOM2 级事件:说明了如何使用事件和DOM文档交互 DOM2 级样式:如何以编 ...

  7. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body><div> click me!</div> < ...

  8. 读书笔记-《JavaScript高级程序设计》-第2章 在HTML中使用JavaScript

    <script>元素 带有src属性的标签之间再有js的代码,只会下载和执行外部脚本文件,忽略潜入的代码 <script src="./test.js">a ...

  9. 《javascript高级程序设计》第六章 读书笔记 之 javascript继承的6种方法

    本文首发于https://segmentfault.com/a/1190000017840651 ECMAScript只支持实现继承,主要依靠原型链来实现.与实现继承对应的是接口继承,由于script ...

  10. 《JavaScript高级程序设计》第8-9章

    第八章 BOM 1.window对象:既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象 1)全局作用域:所有在全局作用域中声明的变量.函数都会变成w ...

最新文章

  1. 用它调试线上bug,真得劲!
  2. 利用策略模式结合alibaba/alpha框架优化你的图片上传功能
  3. RedHat企业版的安装(一)
  4. php 循环curl,php中使用foreach curl多个URL及多线程请求多个URL
  5. python语言的实验心得体会_国产编程语言木兰被质疑换皮Python:当事人承认夸大、道歉...
  6. 64位Ubuntu kylin 16.04安装wine QQ
  7. 基于OIDC(OpenID Connect)的SSO(纯JS客户端)
  8. json最大长度限制_api接口返回动态的json格式?我太难了,尝试一下 linq to json
  9. AI顶会,正在使用AI来审阅AI论文
  10. 作为面试官的一些经历,希望能给找工作的朋友一些参考
  11. android 获取sd卡目录失败_获取sd卡存储路径失败
  12. 深入理解Flex布局以及计算
  13. RocksDB 6.0.1 发布,Facebook 推出的存储系统
  14. Flask第十八篇 Flask-Migrate
  15. SCI 论文免费下载地址
  16. Airbnb创始人:屌丝的逆袭之路
  17. 先有史记还是先有资治通鉴?司马迁、司马光和司马懿三人什么关系?
  18. 我国智能变电站建设到什么程度了
  19. 基于自学习的机器人决策系统(达闼科技赵开勇)
  20. python中rgb,python - 图像的RGB矩阵

热门文章

  1. 只能计算机论文,谈计算机及人工智能技术发展-人工智能论文-计算机论文.docx...
  2. 迪信通机器人_迪信通要做机器人 玩票还是另有深意?
  3. nx set 怎么实现的原子性_正确地使用Redis的SETNX实现锁机制
  4. LeetCode695. 岛屿的最大面积(C#)
  5. 判别模型的玻尔兹曼机论文源码解读
  6. 人工神经网络——笔记摘抄1
  7. matlab调用Java程序时出现 Java.lang.OutOfMemoryErrot: GC overhead limit exceeded
  8. Java生鲜电商平台-深入订单拆单架构与实战
  9. SVN_06导入项目文档
  10. 【NOIP2018】DAY2T2——填数游戏(轮廓线状压的dp?搜索打表)