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

第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
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascrip --- 构造函数的继承

两点需要注意的. 第一是在构造函数声明时,会同时创建一个该构造函数的原型对象,而该原型对象是继承自Object的原型对象 // 声明一个构造函数Rectengle function Rectangle(length, width) {this.length length;this.width width; }// 即:看见function 后面函数名是大写,一般…

javascript --- 使用语法糖class定义函数

本文讨论的是通过class声明的函数,有什么特点,或者说是指向了哪里. class A() {} // A是一个类// 要看class声明的函数指向哪里,只需将其[[Prototype]]属性打印到控制台,下面看看A和它的原型对象的指向 // 注:[[Prototype]]属性通过__proto__访问 console.log(A.__proto__…

前端知识点整理收集(不定时更新~)二

目录 require() 加载文件机制 线程和进程 线程 单线程 Nodejs的线程与进程 网络模型 初识 TCP 协议 三次握手 I/O I/O 先修知识 阻塞与非阻塞 I/O 同步与异步 I/O Git 基础命令 分支操作 修改远程仓库地址 远程分支获取最新的版本到本地 拉取远程仓库指定分支…

SpringBoot零基础入门指南--搭建Springboot然后能够在浏览器返回数据

File->new Project 修改默认包名,根据自己的喜好修改 选择初始化需要导入的包,尽量不要一开始就导入很多,特别是数据库,不然启动可能会有问题,创建好的目录如下: 配置文件写在application.properties下&…

JavaScript算法相关

1. 排序 1.1.冒泡排序 每一轮比较&#xff0c;从左至右交换相邻&#xff0c;每轮结束&#xff0c;最后一个为最大下一轮&#xff0c;需要比较的个数 - 1 j < len - i (范围动态缩小)共 len - 1 轮比较 function bubbleSort(arr) {var len arr.length;for (var i 1; i &…

数据结构基础知识

排序 参考&#xff1a;https://www.bilibili.com/video/av38482633/?spm_id_fromtrigger_reload 目录 排序 插入排序 直接插入排序 折半排序 希尔排序 ​ 交换排序 冒泡排序 快速排序 选择排序 堆排序 流量单位计算 什么是计数排序 复杂度分析&#xff1a; 什…

linux中安装软件,查看、卸载已安装软件方法

各种主流Linux发行版都采用了某种形式的包管理系统&#xff08;PMS&#xff09;来控制软件和库的安装。 软件包存储在服务器上&#xff0c;可以利用本地Linux系统上的PMS工具通过互联网访问。这些服务器称为仓库。 由于Linux发行版众多,目前还没有统一的PMS标准工具。 这里分别…

html5 --- 使用javascript脚本控制媒体播放

H5中的标签(<audio…/> 和 <video…/>)对于JS中的HTMLAudioElement对象和HTMLVideoElement对象 对象有以下几个方法: play(): 播放 pause(): 暂停播放 load(): 重新装载音频、视频 canPlayType(type): 判断该元素可播放type类型的音频、视频 下面是一个简单的音乐…

css3 --- 使用媒体查询进行响应式布局

css3引入media,可以根据设备特性进行不同的布局, 本文展示的是根据不同屏幕的宽度进行不同的布局,代码如下: <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title> 针…

node项目正常启动后不能访问(防火墙未放行端口)

今天打开个人站点&#xff0c;发现登陆不了&#xff0c;原以为是pm2的问题&#xff0c;先停了pm2用node app.js的方式运行后端代码&#xff0c;项目能正常启动但是依然不能登陆。 1 检查ecs的安全组规则&#xff0c;node项目端口3000、8888是否放行 2 确认node正常运行 输入…

前端知识点整理(三)不定时更新~

目录 一、移动端跨平台开发方案 Hybrid App React Native Weex Flutter PWA &#xff08;Progressive Web App&#xff09; 小程序 Cordova html5 组件和模块的区别 组件化 模块化 前端代码规范 前端工程化理解 网站性能监测与优化策略 1.网络传输性能优化 页…

前端试题(一)

2020-03-28 金卡智能 *1. 脚手架 vue-cli现在用的什么版本&#xff0c;2版本了解多少&#xff0c;2 3有什么区别 绝对路径与相对路径 ./ 当前路径 …/父路径 / 绝对路径 某文件里引用其他路径下的资源&#xff1a; 判断该文件所在文件夹与其他资源路径间的关系。 什么&#…

html5 --- 利用localStorage进行本地存储

首先做一个提交到本地存储的表单及一个用来显示本地localStorage信息的表格…代码如下: <h2> 本地存储用 </h2>标题: <input id"title" name"title" type"text" size"60" style"margin-left:32px;margin-bottom:…

前端试题(二)

1. 数组方法、reduce()的第二个参数 reduce() MDN文档 accumulator 累计器currentValue 当前值currentIndex 当前索引array 数组 在没有初始值的空数组上调用 reduce 将报错&#xff08;如果有initialValue不报错&#xff09;。回调函数第一次执行时&#xff0c;accumulator…

项目中遇到问题的解决方法合集

以下内容主要是为了方便记录自己在工作中遇到的项目问题搜寻到的解决方法&#xff0c;肯定方法不唯一&#xff0c;这里只是给出解决了我的问题的方法&#xff0c;大家走过路过随便瞧瞧较好啦嘻嘻 1、使用vue/cli 4.x 创建vue项目时使用iconfont 图标无法显示——前者版本问题 …

html5 --- IDBDatabase创建对象存储和索引

代码如下: <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title> CRUD操作 </title><style type"text/css">table{width: 830px;border: 1px …

2019大疆PC软件开发笔试——开关和灯泡两个电路板

题目描述: 小A是一名DIY爱好者&#xff0c;经常制作一些有趣的东西。 今天&#xff0c;小A突然想要来做这样一个东西。小A现在有两块同样大小为nm&#xff0c;有nm块大小为11小电路板拼成的矩形电路板&#xff0c;假设叫做电路板A和电路板B。电路板A上每个小电路板都是一个开关…

2019高校微信小程序开发大赛获奖作品——《brain头脑智序》

目录 前言 交互流程说明图 我的任务 登录授权&#xff08;login&#xff09; 首页&#xff08;tababr分析&#xff09; 房间准备区&#xff08;preparing&#xff09; 便签编辑区 最终方案选择&#xff08;房主权限&#xff09; 会议报告页面&#xff08;report&#…

前端试题(三)

1. js继承的7种方式 回顾&#xff1a; 每个构造函数都有一个原型对象&#xff1b;原型对象都包含一个指向构造函数的指针&#xff1b;实例都包含一个指向原型对象的内部指针&#xff1b;一切皆为对象&#xff0c;只要是对象&#xff0c;就会有 proto 属性&#xff0c;该属性存…