javascript语言精粹——笔记

看书过程中,简单的记录一下重点,回顾起来更方便。

第二章

数字

javascript只有一个数字类型,在内部被标识为64位的浮点数

标识符

标识符必须以字母,下划线或者美元符号开头,其他字符可以是字母,下划线,美元符号或者数字

字符串

javascript的String类型是由零个或者多个16位Unicode字符组成的字符序列,即字符串。

字符串不可变。通过+连接得到的是一个新的字符串。

js的原始类型的值都是不可变的,操作得到的是一个新的值(其他地方看到的)

语句

for...in语句可以枚举一个对象的所有属性

Object.hasOwnProperty()当属性存在于对象实例中时,返回true。in操作符只要能够找到属性,就会返回true。

typeof运算符,如果运算数是数组或者null,那么结果是Object。

+可以做加法操作,也可以链接字符串。如果想要进行数字加法,确保操作数都是数字

 如果第一个运算数是假,运算符&&产生的第一个运算数的值。否则,产生第二个运算数的值

 如果第一个运算数是真,运算符||产生的第一个运算数的值。否则,产生第二个运算数的值

表达式

js中%不是通常数学意义上的模板运算,而实际上是求余运算。两个运算数都是正数时,求模运算和求余运算值是相同的。两个运算数中存在负数时,求模运算和求余运算的值则不相同。(具体查询请看这里)(求余运算和求模运算,对于不同的语言,不同的系统,可能会有不同的标准,有些规定余数要大于0,有些规定余数绝对值尽量小,由此可能得出不同的运算结果)

第三章: 对象

js中除了简单类型数字,字符串,布尔值,null和undefined之外,都是对象。

数组也是对象,函数也是对象,正则表达式也是对象。

 对象是属性的容器,属性包含名字和值。名字可以是包含空字符串在内的任何字符串。值可以是除undefined之外的任何值。

 字面量

如果是合法的标识符作为对象的属性名称,可以省略引号。(可以养成写标识符的良好习惯)

检索

如果检索一个不存在的属性,返回undefined

如果检索一个undefined属性的值,TypeError

 引用

对象通过引用来传递。它们永远不会被复制。

原型

每个对象都连接到一个原型对象,并从中继承属性。

 创建一个新的对象时,可以选择一个对象作为原型。下面是实现object.create

if(typeof Object.create !== function){
  Object.create = function(o){
    var F = function(){}
    F.prototype = o
    return new F()
  }
}

 原型连接在更新时不起作用。对对象作出改变,不会影响到对象的原型。

原型链接只有在检索值得时候才被用到。如果在对象中没有找到,会试着从原型对象中获取属性值,直到终点Object.prototype。这个过程称为委托。

 原型关系是动态的关系,如果添加属性到原型中,立即对基于该原型创建的对象可见。

反射

hasOwnPrototype方法只检查对象中所有的属性,不会检查到原型链上。

 枚举

for in遍历一个对象时,遍历对象中所有的属性名。包含函数以及原型中的属性。可以使用typeof function和hasOwnproperty方法来过滤。

删除

删除操作也不会触及原型链中的任何对象

 减少全局变量污染

为你的应用创建一个唯一的全局变量。另一种方法是闭包

第四章:函数

函数对象

js函数就是对象。函数对象连接到Function.prototype(该原型对象本身连接到Object.prototype)。

每个函数在创建时会附加两个隐藏属性:函数的上下文和实现函数行为的代码(js在创建一个函数时,会给该对象设置一个“调用”属性)。

函数是对象,可以像其他任何的值一样被使用。可以保存在变量、对象和数组中。可以当做参数传递给其他函数,函数也可以返回函数。函数也可以拥有方法。

 函数字面量

函数参数将被定义为函数中的变量。在函数被调用时初始化为实际提供的参数的值

内部函数可以访问自己的变量和参数,也可以自由访问嵌套在其中的父函数的参数和变量。通过函数字面量创建的函数对象包含一个连到外部上下文的连接,被称为闭包(closure)

 调用

调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每个函数还接收两个附加的参数:this和arguments。(this和arguments在函数调用时才绑定)

this的值取决于调用的模式。

js中有四种调用模式:方法调用模式,函数调用模式,构造器调用模式和apply调用模式。

方法调用模式

函数被保存在对象的一个属性时,称它为一个方法。

方法被调用时,this绑定到该对象。

this绑定发生在调用时。

通过this可取得所属对象的上下文的方法称为公共方法(??用来干什么呢)

函数调用模式

当一个函数并非一个对象的属性时,被当作一个函数来调用。

this绑定到全局对象(严格模式下undefined)。这是一个语言设计上的错误,正确设计的情况下,内部函数被调用时,this应该绑定到外部函数的this变量。解决方案:该方法定义一个变量并给它赋值为this,内部函数可以通过访问那个变量访问到this。一般使用that变量名。

 构造器调用模式

如果一个函数前面带上new来调用,背地里将会创建一个连接到该函数的prototype成员的新对象,this绑定到该新对象上。

Aplly调用模式

使用函数的方法apply,选择传递一个this给该函数

参数

函数被调用时,会得到一个免费配送的参数,arguments数组(类数组,有length属性)。

 返回

函数执行完毕,会把控制权交还给调用该函数的程序。

遇到有大括号或者return语句,函数执行完毕

递归

经典“汉诺塔”问题。

深度递归可能会因为堆栈溢出而运行失败。(ES6增加了尾递归优化,可以解决溢出问题)

 作用域

作用域控制着变量和参数的可见性以及生命周期。它减少了名称冲突,并且提供了自动内存管理。

js有函数作用域。(ES6的块级作用域,let和const关键字必须)

 闭包

函数可以访问它被创建时所处的上下文环境。这称为闭包。

内部函数能够访问外部函数的实际变量而无须复制。经常遇到的for循环问题,for循环中生命变量var i=0,相当于在外部上下文中声明了一个变量,如果在for循环中创建函数,访问的i是外部环境的i。例子看下面

var add_the_handlers = function(nodes){
  var i
  for(i=0;i<nodes.length;i++){
    nodes[i].onclick = function(e){
      alert(i)
    }
  }
}

避免在for循环中创建函数,它可能会带来无谓的计算,还会引起混淆。

 模块

模块模式的一般形式是:一个定义了私有变量和函数的函数,利用闭包创建可以访问私有变量和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可以访问到的地方。

级联

如果让没有返回值得函数返回this而不是undefined,可以启用级联。

柯里化

柯里化允许我们把函数与传递给它的参数相结合,产生一个新的函数。

function curry(fn) {
  var args = Array.prototype.slice.call(arguments, 1)
  return function () {
    var innerArgs = Array.prototype.slice.call(arguments)
    var finalArgs = args.concat(innerArgs)
    return fn.apply(null,finalArgs)
  }
}

 记忆

函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算。

var memoizer = function (memo, formula) {
  var recur = function(n){
    var result = memo[n]
    if(typeof result !== 'number'){
      result = formula(recur,n)
      memo[n] = result
    }
    return result
  }
  return recur
}

 斐波那契数列

var fabonacci = memoizer([0,1],function (recur,n) {
  return recur(n-1) + recur(n-2)
  })

 

阶乘

var factorial = memoizer([1,1],function(recur,n){
  return n*recur(n-1)
})

 继承

伪类

通过构造函数产生对象。当一个函数被创建时,Function构造器产生的函数对象会运行类似这样的一些代码:this.prototype={constructor:this};新函数对象被赋予一个prototype属性,它的值是一个包含constructor属性且属性值为该函数的对象。

js所有函数都会得到一个prototype对象。

 第六章:数组

javascript的数组本质上是一种类数组的对象。

它把数组下标转变为字符串,用其作为属性。数组的第一个值将获得属性名‘0’,第二个值得属性名为‘1’。

同对象一样,数组可以包含不同类型的元素。

 不同:数组继承自Array.prototype,对象继承自Object.ptototype。所以数组有大量有用的方法。

 长度

javascript的数组的length是没有上限的。

通过改变length,可以删除元素(设置一个新的小的length)

length不一定等于数组中元素的个数。(var a[10]=1,只有一个属性但是length为10)

 枚举

因为数组是对象,for in可以枚举数组的所有属性,但是for in不能保障元素的顺序。

for循环可以按照顺序来访问元素属性。使用下标。

 容易混淆的地方

在javascript编程中,使用数组或者对象,选择可是根据以下规则:如果属性名时小而连续的整数时,应该使用数组。否则,使用对象。

判断一个对象是否为数组:

  Object.prototype.toString.apply(value) === '[Object Array]'

方法

数组其实就是对象,可以直接给数组添加方法。

毒瘤

  1. 全局变量(直接声明的var变量;window添加属性;未声明使用的变量)
  2. 作用域(最好的方式,在开头声明所有变量)
  3. 自动插入分号(规范编码风格,或者使用lint工具帮助规范代码风格)
  4. 保留字(最好的方式,不要使用)
  5. unicode,ES6之前unicode的单个字符被识别为两个字符(使用es6编码,然后babel转换)
  6. typeof,针对null,数组,正则表达式等返回的值并不如意(记住特殊情况)
  7. parstInt遇到非数字就停止(建议:使用时一定要加上基数)
  8. +(如果需要进行数字加法,一定要保证操作数都是数字)
  9. 浮点数,小数运算结果不准确(整数运算正确,小数运算指定精度)
  10. NaN(Number.isNaN()检测)
  11. 伪数组:性能比真正的数组差很多(只能提高引擎了吧)
  12. 假值(空字符串、0,false,null,undefined,NaN)
  13. hasOwnPproperty(作为一个方法,可以容易的被覆盖,一定要注意)
  14. 对象(js的对象并没有真正的空对象,总是从Object继承一些东西。)

糟粕

  1.  ==(请始终使用===和!==)
  2. with(万不得已,不要使用)
  3. eval (没有把握,不要使用)
  4. continue影响代码性能(寻找替代方法)
  5. switch case穿越(没太明白,如果你的代码出现问题,可以特别注意一下)
  6. 缺少{}(尽量不要省略{},压缩后的代码只多了几个字符而已)
  7. ++/--,不谨慎的编码可能造成安全漏洞(还没有意识到会造成什么漏洞)
  8. 位运算:js位运算性能很差,尽量不要使用(其他语言可能更贴近硬件,使用效率比较高)
  9. function声明和function表达式(作者一直使用函数表达式,提升可能会造成一些问题?嗯……)
  10. 类型的包装对象(不要使用new Boolean,new Number,new String)
  11. new运算符经常会被遗忘()

 JSON

使用JSON.parse,而不要使用eval。parse可以在发现危险数据时发出警告,错误。

PS:直接把服务器传来的html给innerHTML是一个危险的行动,如果html中有恶意脚本的话。

 

posted @ 2019-11-14 14:45  Jamie0327  阅读(165)  评论(0编辑  收藏  举报
levels of contents