Skip to content

Latest commit

 

History

History
349 lines (309 loc) · 17.6 KB

JavaScript语言精粹——阅读笔记.md

File metadata and controls

349 lines (309 loc) · 17.6 KB

为什么要使用JS

分析JS

好的想法

  • 函数
  • 弱类型
  • 动态对象
  • 对象字面量表示法

坏的想法

  • 全局变量的编程模型

函数

  • JS的函数是(主要)基于词法作用域的顶级对象
  • JS是第一个成为主流的lambda语言。
  • 相对java而言,JavaScriptLispScheme有更多的共同点。它是披着C外衣的Lisp

强弱类型

  • 大部分编程语言中都流行要求强类型。
  • 原理在于强类型允许编译器在编译时检测错误。
  • JS是一门弱类型语言,所以JS的编译器不能检测出类型错误。
  • 事实证明,强类型并不会让你的测试工作轻松。
  • 强类型检查找的的那种错误并不是令人头痛的错误
  • 弱类型是自由的。无需建立复杂的类层次,永远不用做强制造型,不用疲于应付类型系统以得到想要的行为

字面量表示法

  • 通过列出对象的组成部分,他们就能简单的被创建出来。
  • 这种表示法是促使创立流行的数据交换格式——JSON的灵感

原型继承

  • JS有一个无类别的对象系统,在这个系统中,对象直接从其他对象继承属性。

全局变量

  • JS依赖于全局变量来进行连接。
  • 所有编译单元的所有顶级变量被撮合到一个被称为全局对象的公共命名空间中

一些基础

空白

  • 空白可能表现为格式化字符或注释的形式。
  • 空白通常没有意义,但是偶尔需要用它来分割字符序列,否则他们就会被何婷成一个单一的符号。

注释

  • /**/ 来自于一门叫PL/I的语言
  • //
  • 在JS中,字符对也可能出现在正则表达式字面上,所以块注释对于被注释的代码块来说是不安全的
var rm_a = /a*/.match(s)

标识符

  • 由一个字母开头,气候可选择性地加上一个或多个字母,数字或下划线,标识符不鞥呢使用保留字
  • 标识符被用于语句、变量、参数、属性名、运算符和标记。

数字

  • 只有一个单一的数字类型,内部被表示为64位的浮点数,和JAVA的double一样
  • 它没有分理处整数类型,所以11.0是仙童的值
  • 负数可以用前缀运算符-来构成
  • NaN是一个数值,它表示一个不能产生正常结果的运算结果。NaN不等于任何值,包括它自己。可以用isNaN(Number)加测
  • Infinity表示所有大于1.79769313486231570e+308的值
  • Math方法

字符串

  • 字符串字面量可以被包围在单引号或双引号中,他可能包含0个或多个字符
  • \反斜线符号是转义字符
  • JS在创建的时候Unicode是一个16位的字符集,所以JS中的所有字符都是16位的
  • JS没有字符类型,要表示一个字符,只要创建仅包含一个字符的字符串即可 ??? 这句话对吗???
  • 转义字符允许吧那些正常情况下不被允许的字符插入到字符串中,比如反斜线,引号。。。
  • \u约定允许指定用数字表示的字符码位
"A" === "\u0041"
  • 字符串有一个length属性
  • 字符串是不可变的,可以通过+运算符去拼接。
  • 一些方法

语句

  • 一个编译单元包含一组可执行的语句。在web浏览器中,每个script标签都提供一个呗变异且立即执行的编译单元
  • 因为缺少链接器,JS把他们一起泡入一个公共的全局名字空间中
  • var语句被用在函数的内部时,他定义了这个函数的私有变量。
  • switchwhilefordo允许有一个可选的前置标签(label),配合break使用
  • 语句旺旺按照从上到下的顺序被执行
  • JS可以通过条件语句,循环语句,强制跳转语句(break, return throw)函数调用来改变这个执行序列
  • 代码块是包在一对花括号中的一组语句。es6以前的代码块不会创建一个新的作用域,因此变量应该定义在函数的顶端而不是在代码块中。
  • 一些被当做假的值
    1. false
    2. null
    3. undefined
    4. 空字符串
    5. 数字 0
    6. 数字 NaN
  • for等循环语句的介绍

表达式

  • 最简单的是字面量值、变量、内置的值、new前导的调用表达式、delete前导的属性存取表达式、圆括号中的表达式、前缀运算符作为前导的表达式
  • 或者表达式后面跟着
    1. 一个插入运算符与另一个表达式
    2. 三元运算符? 后面跟着另一个表达式,然后接一个: 然后街第三个表达式
    3. 一个函数调用
    4. 一个属性存取表达式
  • 运算符优先级

字面量

  • 对象字面量是一种方便指定新对象的表示法
  • 属性名可以是标识符或字符串
  • 这些名字被当做字面量名而不是变量名来对待
  • 所以对象的属性名在编译时才能知道。
  • 属性的值就是表达式

函数

  • 函数字面量定义了函数值
  • 它可以有一个可选的名字,用于递归的调用自己
  • 它可以指定一个参数列表
  • 这些参数将作为变量由调用时传递的实际参数(arguments)初始化。
  • 函数的主体包括变量定义和语句

对象

  • JS的简单类型包括数字、字符串、布尔值(true或false)、null值和undefined
  • 其他所有值都是对象
  • 数字、字符串和布尔值貌似对象,因为他们拥有方法,但他们是不可变的。
  • JS中的独享是可变的键控集合
  • 在JS中,数组是对象,函数是对象,正则表达式是对象,对象自然也是对象。
  • 对象是属性的容器,其中每个属性都拥有名字和值。
  • 属性的名字可以是包括空字符串在内的任意字符串
  • 属性值可以是除undefined之外的任何值 ???
  • JS中的对象是五类别的。它对新属性的名字和值没有约束。
  • 对象适合用于收集和管理数据。
  • 对象可以包含其他对象,所以他们可以容易地表示成树形或图形结构
  • JS包括一个原型链特性,允许对象集成另一对象的属性。
  • 正确的使用它能减少对象初始化的时间和内存消耗。

对象字面量

  • 独享字面量提供了一种非常方便地创建新对象值的表示法。
  • 一个独享字面考量就是包围在一对花括号中的的零或多个名/值对。
  • 对象字面量可以出现在任何允许表达式出现的地方。
  • 属性名可以是包括空字符串在内的任何字符串
  • 在对象字面量中,如果属性名是一个合法的JS标识符且不是保留字,并不强制要求用印好括住属性名
  • 逗号用啦分隔多个名值对

今天偷懒了 放假在家开心

进了新公司用vue写项目 讲实话没有JQ写的熟练 力不从心 哎

更新

  • 对象中的值可以通过赋值语句来更新。
  • 如果属性名已经存在于对象中,那么这个属性的值被替换。
  • 如果对象之前并没有拥有那个属性名,那么该属性就被扩充到该对象中

引用

  • 对象通过引用来传递,他们永远不会被拷贝。

原型

  • 每个对象都链接到一个原型对象,并且他可以从中继承属性。
  • 所有通过对象字面量创建的对象都链接到Object.prototype这个JS中的标准对象
  • 当你创建一个新对象时,你可以选择某个对象作为它的原型。
  • JS提供的实现机制杂乱而复杂,但其实他可以被明显的简化
  • 原型链接在更新时是不起作用的
  • 当我们队某个对象作出改变时,不会触及到该对象的原型
  • 原型链只有在建所致的时候才被用到
  • 如果我们尝试去获取对象的某个属性值,且该对象没有此属性名,那么JS会试着从圆形链中获取属性值
  • 如果那个原型对象没有该属性,那么再从它得原型中寻找,以此类推,知道该过程最后到达终点Object.prototype
  • 如果想要的水性完全不存在与原型里那种,那么结果就是undefined,这个过程称为委托
  • 源性关系是一种动态的关系
  • 如果我我们添加一个新的属性到原型中,改属性会立即对所有基于该原型创建的对象可见

反射

  • 检查对象并确定对象有什么属性是很容易的事情,只要试着去检索该属性并验证取得的值
  • 原型链中的任何属性也会产生一个值
typeof flight.toString // 'function
  • 有两个方法去处理这些不需要的属性
  • 第一个是让你的程序检查并剔除函数值。一般来说,做反射的目标是数据,因此你应该意识到一些值可能回事函数
  • 另一个方法是使用hasOwnProperty方法,如果对象拥有独有的束胸,他将返回true。hasOwnProperty方法不会检查原型链
flight.hasOwnProperty('number') // true
flight.hasOwnProperty('constructor') // false

枚举

  • for in 语句可用来遍历一个对象中的所有属性名
  • 该枚举过程将会列出所有的属性——包括函数和你可能不关心的原型中的属性——所以有必要过滤掉那些你不想要的值
  • 最常用的过滤器是hasOwnProperty以及typeof 排除函数
var name;
for( name in another_stooge ){
    if( typeof another_stooge[name] !== 'function' ){
        document.writeln( name + ":" + another_stooge[name] )
    }
}
  • 属性名的出现顺序是不确定的,因此要对任何可能出现的顺序有所准备
  • 如果你想要确保属性以特定的顺序出现,最好的办法就是完全避免使用for in语句,而是创建一个数组,其中以正确的顺序包含属性名
var i;
var propertyes = [
    'first-name',
    'middle-name',
    'last-name',
    'profession'
];
for( i = 0; i < properties.length; i++){
    console.log( another_stooge[ properties[i] ] );
}
  • 通过使用for配合数组,可以得到我们想要的属性,而不用担心可能发掘出原型链中的属性,并且我们按正确的顺序取得了它们的值

删除

  • delete运算符可以用来删除对象的属性.将会移除对象中确定包含的属性,不会触及原型链中的任何对象
  • 删除对象的属性可能会让来自原型链中的相同key的属性浮现出来,继承来的

减少全局变量污染

  • JS可以很随意的定义那些可保存所有应用资源的全局变量。不幸的是,全局变量削弱了程序的灵活性,所以应该避免。
  • 最小化使用全局变量的一个方法是在应用中只创建唯一一个全局变量

函数

函数对象

  • 在JS中,函数就是对象。
  • 对象是"名/值"对的集合并拥有一个连到原型对象的隐藏链接。
  • 对象字面量产生的对象链接到Object.prototype
  • 函数对象链接到Function.prototype(该原型对象本身链接到Object.prototype)
  • 每个函数在创建时附有两个附加的隐藏属性——函数的上下文和实现函数行为的代码
  • 每个函数对象在创建时也随带有一个prototype属性。它的值是一个拥有constructor属性且值即为该函数的对象,这和隐连接接到Function.prototype完全不同。
  • 因为函数是对象,所以他们可以像任何其他的值一样被使用。
  • 函数可以存放在变量、对象和数组中
  • 函数可以作为参数传递给其他函数,函数也可以再返回函数
  • 因为函数是对象,所以函数可以拥有方法
  • 函数的与众不同之处在于他们可以被调用。
  • JS创建一个函数对象时,会给该对象设置一个“调用”属性。
  • 当JS调用一个函数时,可理解为调用此函数的“调用”属性。

函数字面量

  • 函数对象可以通过函数字面量来创建
var add = function( a, b ){
    return a + b;
}
  • 函数字面量包括四个部分,第一个部分是保留字function
  • 第二个部分是函数名,它可以被省略。函数可以用它的名字来递归地调用自己,此名字也能被调试器和开发工具来识别函数。如果没有给函数命名,它会被认为是匿名函数
  • 函数的第三部分是包围在括号中的一组参数。其中每个参数用逗号分隔。这些名称奖杯定义为哦函数中的变量。它们不想普通的变量那样将被初始化为undefined,而是在该函数被调用时初始化为实际提供的参数的值。
  • 第四部分是包围在花括号中的一组语句。这些语句是函数的主体。它们在函数被调用时执行
  • 函数字面量可以出现在任何允许表达式出现的地方。
  • 函数也可以被定义在其它函数中。
  • 一个内部函数自然可以访问自己的参数和变量。同时他也能方便的访问它被嵌套在其中的那个函数的参数与变量。
  • 通过函数字面量创建的函数对象包含一个连到外部上下文的链接。这称为闭包。它是JS强大表现力的根基

调用

  • 调用一个函数将暂停当前函数的执行,传递控制权和参数给新函数。
  • 除了生命时定义的形式参数,每个函数将接受两个附加的参数——thisarguments
  • 参数this在面向对象编程中非常重要,它的值取决于调用的模式
  • 在JS中一共有四种调用模式——方法调用模式、函数调用模式、构造器调用模式和apply调用模式,这些模式在如何初始化关键参数this上存在差异
  • 调用运算符是根在任何产生一个函数值的表达式之后的一对圆括号。
  • 圆括号内可包含领个或多个用逗号隔开的表达式。
  • 每个表达式产生一个参数值。
  • 每个参数值被赋予函数声明时定义的形式参数名。
  • 当实际参数(arguments)的个数与形式参数(parameters)的个数不匹配时不会导致运行时错误。
  • 如果实际参数多了,超出的将被忽略。
  • 如果实际参数值过少,确实的值将会被替换为undefined
  • 对参数值不会进行类型检查:任何类型的值都可以被传递给参数

方法调用模式

  • 当一个函数被保存为对象的一个属性时,我们称它为一个方法。
  • 当一个方法被调用时,this被绑定到该对象。
  • 如果一个调用表达式包含一个属性存取表达式(即一个.点表达式或[subscript]下标表达式),那么他被当做一个方法来调用。
  • 方法可以使用this去访问对象,所以他能从对象中取值或修改该对象
  • this到对象的绑定发生在调用的时候
  • 这个“超级”迟绑定(very late binding)使得函数可以对this高度复用
  • 通过this可取的他们所属对象的上下问的方法称为公共方法

函数调用模式

  • 当一个函数并非一个对象的属性时,那么他被当做一个函数来调用
var sum = add(3, 4)
  • 当函数以此模式调用时,this被绑定到全局对象,这是语言设计上的一个错误,可以在外部用变量保存this,那么内部函数就可以通过那个变量访问this,一般命名为that

构造器调用模式

  • JS是一门基于原型集成的语言,这意味着对象可以直接从其他对象继承属性,该语言是无类别的(无类,基于原型继承)
  • 如果在一个函数前面带上new来调用,那么将创建一个隐藏链接到该函数的prototype成员的新对象,同时this将会被绑定到哪个新对象上
  • new前缀也会改变return语句的行为
var Quo = function( string ){
    this.status = string;
}
Quo.prototype.get_status = function(){
    return this.status
}
var myQuo = new Quo('confused')
  • 结合new前缀调用的函数被称为构造器函数
  • 按照约定,他们保存在以大写格式命名的变量里

Apply调用模式

  • JS是一门函数式的面向对象编程语言,所以函数可以拥有方法
  • apply方法让我们构建一个参数数组并用其去调用函数。
  • 它也允许我们选择this的值
  • apply方法接收两个参数,第一个是将被绑定给this的值, 第二个就是一个参数数组。
var array = [3, 4];
var sum = add.apply( null, array ); // sum为7
var statusObject = {
    status: 'A-OK'
}
// statusObject并没有继承自Quo.prototype,但我们可以再statusObject上调用get_status方法,尽管statusObject并没有一个名为get_status的方法
var status = Quo.prototype.get_status.apply( statusObject )

参数

  • 当参数被调用是时,会得到一个免费奉送的参数,那就是arguments数组
  • 通过它,函数可以访问所有它被调用时传递给它的参数列表,包括哪些没有被分配给函数声明时定义的形式参数的多与参数,这使得编写一个无需指定参数个数的函数成为可能
var sum = function(){
    var i, sum = 0;
    for( i = 0; i < arguments.length; i++ ){
        sum += arguments[i]
    }
    return sum
}
document.writeln( sum(4, 8, 15, 16, 23, 42) )
  • arguments并不是一个真正的数组,它是一个类数组对象。
  • arguments拥有一个length属性,但它缺少所有的数组方法

返回

  • 当一个函数被调用时,它从第一个语句开始执行,并在遇到关闭函数体}时结束。那使得函数把控制权交还给调用该函数的程序部分
  • return语句可用来使函数提前返回
  • 当return被执行时,函数立即返回而不再执行余下的语句
  • 一个函数总是会返回一个值,如果没有指定,返回undefined
  • 如果函数以在前面加上new前缀的方式来调用,且返回值不是一个对象,则返回this(该新对象)

异常

  • JS提供了一套异常处理机制。异常是干扰程序的正常流程的非正常(并非完全出乎意料)的事故
throw {
    name: 'TypeError',
    message: 'add needs numbers
}
  • throw 语句中断函数的执行。
  • try catch
try {

} catch(e){
    console.log(e)
}