You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionprintArgs(args){if(args.name&&typeofargs.name==="string"){console.log("person's name is"+args.name);returnargs.name;}if(args.age&&typeofargs.age==="number"){console.log("person's age is"+args.age);returnargs.age;}returnnull;}printArgs({name: "Jhon",age: 28})printArgs({name: "Jhon"})
summary_start
《JavaScript高级程序设计》读书笔记
summary_end
1. 目录结构
由于章节较多,只记录本人认为的基础等部分。
2. 什么是JavaScript
诞生于1995年,早期设计只是为了实现表单验证。
发展史
实现
完整的JavaScript实现包含三个不同部分:1. 核心(ECMAScript),2. 文档对象模型(DOM),3. 浏览器对象模型(BOM)。
3. 使用JavaScript
引入:在HTML页面中插入
元素
按照惯例,所有script标签都应该放在页面的
元素里面,但这也意味着必须在所有script加载完毕之后才呈现页面内容,这样无疑会造成很长的窗口空白期,于是可以将script放在body元素当中。
4. 基本概念
4.1 变量
ECMAScript中变量是松散类型,可以用来保存任何类型的数据(这点在TypeScript中有很大改变)。
定义变量时使用var操作符(ES6之后又引入了let,const)。
var:没有块的概念,ES5之前只有全局变量与函数内的局部变量,全局作用域内声明的变量所有作用域内都可以访问,函数内声明的局部变量可以在全局作用域内访问,但不能跨函数访问。
let:ES6之后引入的块的概念,使用let声明的变量只在变量所在的{}块内访问。
const:ES6之后引入的关键字,用来声明常量,声明时必须初始化,且不能改变,只能在常量所在的{}内访问。
4.2 数据类型
ES中包含5种简单数据类型(基本数据类型)与一众复杂数据类型。
简单类型:Undefined(未定义)、Null(空)、Boolean(布尔类型)、Number(数字)、String(字符串),Symbol(后来添加)
复杂类型:Object(对象),Array(数组),Function(函数)
4.3 语句
使用一个或者多个关键字来完成给定任务。
包含:if语句,do-while语句,while语句,for语句,for-in语句,label语句,break/continue语句,with语句,switch语句。
4.4 函数
所有语言的核心概念,通过函数封装任意多条语句,并且可以在任何时候、任何地方调用执行。ES中使用关键字function声明函数。
函数会在执行完return后立即停止并退出。
4.4.1 参数
ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。
因为所有传进来的参数在函数中用一个数组保存,在函数体内,也可以通过argments对象来访问这个参数数组
4.4.2 没有重载
如果定义了两个名字相同的函数,则该名字只属于后定义的函数。
5. 变量、作用域和内存问题
5.1 基本类型与引用类型的值
ES包含两种数据类型值:基本类型值(简单的数据段)和引用类型值(保存在内存中的对象)。
参数传递
ES中所有函数的参数都是按值传递的。
向函数传入基本类型值时,函数会复制该值给一个局部变量(参数),函数内部改变不影响外部变量的值。
向函数传入引用类型值时,函数会将该引用复制给一个局部变量(参数),但是在函数中改变该引用的引用类型值时,会反应在函数的外部,即函数改变了保存在内存中的对象的属性;若在函数内部对参数重新定义一个对象,则该变量的引用会改变,指向内存中新定义的对象,函数后续使用参数进行操作,将不会再体现在函数的外部
5.2 执行环境和作用域
执行环境(简称“环境”),定义了变量或者函数是否有权访问其他数据,决定了他们各自的行为。
5.2.1 延长作用域链
在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。
可以用来延长作用域链的有两种情况:
5.2.2 没有块级作用域
使用var声明的变量,会自动被添加到最接近的环境中。
6. 引用类型
引用类型的值(对象)是引用类型的一个实例。在 ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起,也被称为“类”。
对象是某个特定引用类型的实例
6.1 Object类型
ES中使用最多的引用类型。创建Object实例有两种方式:
var obj = new Object();
==使用对象也是向函数传递大量不定参数的首选方式:==
6.2 Array类型
ES中,Array类型应该是Object之后最常用的类型。
数组的length属性不是只读的
数组检测:ES5中新增了
Array.isArray()
方法。数组常用方法如下:
6.3 RegExp类型
ES通过RegExp来支持正则表达式,使用方式:
var expression = / pattern / flags ;
6.4 Function类型
7. 面向对象程序设计
面向对象的语言都有一个标志:都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。ES中没有类的概念,因此它的对象也与基于类的语言中的对象不同。
对象:无序属性的几个,其属性可以包含基本值、对象挥着函数。
7.1 理解对象
创建自定义对象最简单的方式就是创建一个Object实例,然后再为他添加属性和方法。
属性类型:数据属性、访问器属性
数据属性
数据属性:包含一个数据值的位置,在这个位置可以读取值和写入值。有四个描述其行为的特性。
[[Configerable]]
:表示能否通过delete删除属性从而重新定义属性、能否修改属性的特性,或者能否把属性修改为访问器属性;默认为true。[[Enumerable]]
:表示能否通过for-in循环返回属性;默认为true。[[Value]]
:包含这个属性的数据值;默认为undefined。[[Writeable]]
:表示能否修改属性的值;默认为true。访问器属性
访问器属性不包括数据值:他们包含一对getter和setter函数(不过这两个函数都不是必须的)。读取访问器属性时,调用getter方法,返回有效的值;写入访问器属性时,会调用setter函数并传入新值,setter函数负责如何处理函数。访问器属性也有四个属性描述其属性。
[[Configurable]]
:与数据属性的Configurable属性相同。[[Enumerable]]
:与数据属性的Configurable属性相同。[[Get]]
:读取属性时调用的函数,默认为undefined。[[Set]]
:写入属性时调用的函数,默认为undefined。7.2 创建对象
工厂模式
抽象出具体对象的过程。
构造函数模式
要创建Person的新实例,必须要用new操作符,这种方式调用构造函数会经历一下四个步骤:
缺点:每个方法都要在每个实例上重新创建一遍。
解决方法:将函数定义转移到构造函数之外。
这个例子中,将sayName()函数的定义转移到构造函数Person外部,在构造函数内部,将sayName属性设置成等于全局的sayName()函数,即内部的sayName属性只保存了一个指向全局sayName()函数的指针(引用)。
这种方式带来的问题:1.全局作用域内定义的函数只能被某个对象调用;2.如果对象有多个方法,那么这个自定义的引用类型就没有封装意义。
原型模式
每个Object对象都有
Proto
属性,每个函数都有自己的prototype
(原型)属性,这个属性是一个指针,指向函数对应的原型对象。使用原型对象的好处是可以让所有对象实例共享他的属性和方法。可以通过对象实例访问原型中的值,但是不能重写原型的值和属性如果在实例中添加了一个属性且与原型属性同名,则会屏蔽原型中的值。
当在函数中调用person1这个实例时,首先搜索这个实例,如果没有在搜索原型。当实例中存在这个属性时,即使设置为null也不会恢复指向原型。使用delete可以完全删除这个实例属性。
使用
hasOwnProperty()
方法可以检测一个属性是否存在于实例中。只有给定属性存在于对象实例中时才会返回true
in操作符
in操作符有两种使用方式:单独使用、在for-in循环中使用。
单独使用时,只要能通过对象访问到给定属性即返回true,不管这个属性时在实例总还是在原型中。
for-in循环时,返回所有可被枚举的属性,不管属性是存在于实例中还是原型中(即屏蔽了[[enumerable]]为false的属性)。
简化原型语法
组合模式
函数模式定义属性,原型模式定义方法与共享属性(目前在ES中使用最广泛,认同度最高的一宗自定义类型的方法)。
动态原型模式
在构造函数中插入判断条件,只有在被检测方法不存在时,才会创建新的属性或者方法。
寄生构造函数模式
通常是在前述几种情况都不适用的情况下,可以使用该模式。
基本思想是创建一个函数,但是该函数的作用仅仅是封装创建对象的代码。
稳妥构造函数模式
稳妥对象:没有公共属性,其方法也不能引用this的对象。
稳妥对象适合用在一些安全的环境中(禁止使用this和new),或者在放在数据被其他应用程序改动时使用。
7.3 继承
原型链
ES中描述了原型链的概念,并将原型链作为实现继承的主要方法。
基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。
每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都好汉一个指向原型对象内部的指针。
该代码定义两个类型:SuperType和SubType。每个类型对应一个属性和方法。
SubType继承SuperType,该继承通过创建SuperType实例,并将实例赋值给SubType.prototype实现。本质是重写原型对象,替换厂一个新的类型的实例。
即本来存在于SuperType的实例的所有方法和属性,也存在于SubType.prototype中了。
所有函数的默认原型都是Object实例,因此默认原型中都会包含一个内部指针指向Object.prototype。
第一种方式是使用
instanceof
操作符,第二种是使用isPrototypeOf()
方法。由于原型链的关系,我们可以说instance是Object,SuperType,SubType中任何一个的类型的实例。
子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎样,给原型添加方法的代码一定要放在替换原型的语句之后。
构造函数定义了一个引用类型值属性时,通过原型链继承的新类型创建的实例会共享这一个引用类型的值;在创建子类型的实例时,不能向超类型的构造函数中传递参数。
借用构造函数
为解决原型中包含引用类型值所带来的问题(又叫伪造对象或者经典继承)。
基本思想:在子类型构造函数内部调用超类型构造函数,可以通过call()和apply()方法。
借用沟槽函数可以在子类型构造函数中向超类型构造函数传递参数。
方法都在构造函数中定义,无法实现函数复用,而且超类型的原型中定义的方法对子类型也不可见。
组合继承
也叫伪经典继承,将原型链和借用构造函数的技术组合到一起。
其他继承
The text was updated successfully, but these errors were encountered: