javascript语言精粹(蝴蝶书)-笔记

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/51340630

本书作者douglas Crockford是JSON的创立者,一位javascript大师。

1.精华(Good Parts)

javascript好的想法包括函数,弱类型,动态对象和一个富有表现力的对象字面量表示法。坏的想法包括基于全局变量的编程模型

javascript函数是基于词法作用域(lexical scoping)的顶级对象,是第一个成为主流的lamda语言。一个糟糕的选择:javascript依赖于全局变量来进行连接。所有编译单元的所有顶级变量被撮合到一个被称为全局对象的公共命名空间中。

这本书之后的很多例子都与用到一个method方法去定义新方法

Function.prototype.method = function (name,fn) {
    this.prototype[name] = fn;
    return this
}

2.语法(grammar)

  • number类型总是64位浮点数,两个整数相除也可能出现非整数结果,
1 === 1.0 //true
0.1+0.2 != 0.3 //true
  • 6种值会为假(==false),分别是false,null,undefined,’ ‘,0,NaN。字符串’false’为真。

3.对象(Objects)

  • ‘&&’:如果第一个操作数的值为false,那么运算符&&产生它的第一个操作数的值(并且执行短路操作:第一个操作数为false,不对第二个操作数求职)。否则它产生第二个操作数的值,可利用&&运算符避免检索undefined引起的异常
var flight= {};
flight.equipment                                             //undefined
flight.equipment.model                                   //throw"TypeError"
flight.equipment && flight.equipment.model     //undefined
  • ‘||’:如果第一个操作数的值为true,那么运算符||产生它的第一个操作数的值(第一个操作数为true,不对第二个操作数求值)。否则它产生第二个操作数的值。可利用||运算符来填充默认值。
var status = flight.status || '';
  • beget方法创建一个使用原对象作为其原型的新对象
if(typeof Object.beget != 'function') {
    Object.beget = function(o) {
        var F = function () {};
        F.prototype = 0;
        return new F();
    }
}
  • 当我们对某个对象的属性做出改变时,不会触及到该对象的原型。原型链只有在检索值得时候,才会自下至上直到Object.prototype中去寻找,找到就用,然后停止寻找,都没有就返回undefined,这个过程称为委托。hasOwnProperty方法可以检测对象自身拥有的属性。
  • 原型关系是一种动态关系。如果添加一个新的属性到原型中,该属性会立即对所有基于该原型创建的对象可见。
  • delete可以删除对象的属性,不会触及对象原型链中的任何对象。

4.函数(Functions)

函数也是对象(Function Objects)

函数对象连接到Function.prototype(该原型对象本身连接到Object.prototype),它的值是一个拥有constructor属性且值为该函数的对象。

每个函数在创建时附有两个附加的隐藏属性:函数的上下文和实现函数行为的代码。调用一个函数将暂停当前执行,传递控制权和参数给新函数。除了声明时定义的形参,每个函数接收两个附加的参数:this和arguments,arguments.callee(ES5严格模式报错)代表函数自身,通常用于递归。可用命名函数表达式来代替(js高程第七章函数表达式-7.1递归)

var factorial = (function f(num) {
    if(num <= 1) {
        return 1;
    } else {
        return num * f(num-1);
    }
});

调用(Invocation)

函数的实参(arguments)和型参(parameters)的个数不匹配时不会报错,如果实参多了,超出的将被忽略。如果实参过少,缺少的会被传入undefined。 一共四种调用模式:方法调用模式,函数调用模式,构造器调用模式和apply调用模式。

  • 方法调用模式

当一个函数被保存为对象的一个属性时,我们称它为一个方法,一个方法被调用时,this绑定到该对象(只要函数被调用的时候用一个.点或者[subscript]下标表达式),那么它被当做一个方法来调用。

  • 函数调用模式

当一个函数并非一个对象的属性时,那么它被当做一个函数来调用,this被绑定到全局对象。解决内部函数的this被指向全局的设计缺陷时,可以在外部var that=this。如在浏览器中,this == window;在node中,this == global。

  • 构造器调用模式

如果在一个函数前面带上new来调用,那么将创建一个隐藏链接到该函数的prototype成员的新对象,同时this将会被绑定到那个新对象上。

  • apply调用模式

类似有call和bind。apply和call的区别在于第二个参数,apply接收数组对象,call接收任意个参数。 this绑定到第一个参数,即传入对象。 在EcmaScript5中扩展了叫bind的方法(IE6,7,8不支持),使用方法如下

function T(c) {
  this.id = "Object";
  this.dom = document.getElementById("kenny");
}
T.prototype = {
  init: function() {
     //①
    this.dom.onmouseover = function() {
      console.log("Over-->"+this.id);//'kenny'
    }
     //②
    this.dom.onmouseout = function() {
      console.log("Out -->"+this.id);//'Object'
    } .bind(this)
  }
};
(new T()).init();

bind与call很相似,,例如,可接受的参数都分为两部分,且第一个参数都是作为执行时函数上下文中的this的对象。 不同点有两个: 1.bind的返回值是函数,(类似事件绑定,改变this指向,执行需在调用一次)。 bind改变上下文this并返回(return)函数,call是 改变上下文this并执行(excute)函数

2.后面的参数的使用也有区别

function f(a,b,c){
    console.log(a,b,c);
}

var f_Extend = f.bind(null,"extend_A");

f("A","B","C")  //这里会输出--> A B C

f_Extend("A","B","C")  //这里会输出--> extend_A A B

f_Extend("B","C")  //这里会输出--> extend_A B C

f.call(null,"extend_A") //这里会输出--> extend_A undefined undefined

bind的兼容处理

if (!Function.prototype.bind) {
    Function.prototype.bind = function(obj) {
        var _self = this
            ,args = arguments;
        return function() {
            _self.apply(obj, Array.prototype.slice.call(args, 1));
        }
    }
}

返回(Return)

return语句可以使函数提前返回。当return被执行(不管ture or false),函数立即返回而不再执行余下代码。

一个函数总会返回一个值,没有指定返回值,则返回undefined。如果函数以new方式调用,且返回值不是一个对象,则返回this(该新对象)。

补充:continue中断本次循环,继续下一次循环。break 语句用于跳出循环。jquery中的$.each()用return ture中断本次循环,return false跳出循环。

闭包(Closure)

利用闭包来返回外部函数变量的方式,可以避免一个函数被加上new来使用

//闭包
var quo = function (status){
  return {
       get_status : function () {
              return status ;
            }
       };
      };
var myQuo = quo ("amazed");
myQuo.get_status();
//构造函数
var Quo = function (status){
        this.status =status;
};
var myQuo = new Quo("amazed");

当我们调用myQuo时,它返回包含get_status方法的一个新对象。该对象的一个引用保存在myQuo中。即使quo已经返回了,但get_status方法仍然享有访问quo对象的的status属性的特权。get_status方法并不是访问该参数的一个拷贝,它访问的就是该参数本身。因为该函数可以访问它被创建时所处的上下文环境,这就是闭包。

内部函数能访问外部函数的实际变量而无须复制(闭包是活动对象的一个子对象,包含变量的属性)

回调(Callback)

模拟异步请求,避免客户端被阻塞

  request = prepare_the_request();
  send_request_asynchronously(request,function(response){
        display(response);
};

模块(Module)

通过函数和闭包来构造模块。只暴露可用的public方法,其它私有方法全部隐藏,如果你不需要传参数或者没有一些特殊苛刻的要求的话,我们可以在最后一个}后面加上一个括号,来达到自执行的目的,这样该实例在内存中只会存在一份copy。可通过模块模式来实现单例模式

var theModule = (function(){
       var i = 1;
       return {
          result :function(x) {
                 i++;
                 return x*i;
          }
      };
}());

通过递归记忆函数

var fibonacci = function (n) {
    return n < 2 ? n : a(n-1) + a(n-2);

}
for(let i=0; i<10; i++) {
    console.log(i + ':' + fibonacci(i));
}
// 0:0
// 1:1
// 2:1
// 3:3
// 4:5
// 5:7
// 6:9
// 7:11
// 8:13
// 9:15

这样写fiboacci函数被调用了453次。我们调用了11次。

  var fibonacci = (function () {
        var memo = [0, 1];
        var fib = function (n) {
            var result = memo[n];
            if(typeof result != 'number') {
                result = fib(n-1) + fib(n-2);
                memo[n] = result;
            }
            return result;
        };
        return fib;
  })();
  fibonacci(10) //55

抽象的递归记忆函数

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

  var fibonacci = memoizer([0, 1], function (shell, n) {
            return shell(n-1) + shell(n-2);
      });//传递函数

fibonacci(10) //55

5.继承

在伪类模式与模块模式中,尽量选择后者,函数化构造器伪代码模板 “`javascript var constructor = function (spec ,my) { var that, //其他的私有实例变量;

 my = my || {};
//把共享的变量和函数添加到my中;

that = 一个新对象

//添加给that的特权方法 return that; }

  • 给数组增加一个key属性(非数字和length),不会改变该数组的长度

js中的糟粕

  • 全局变量 :越少越好
  • 作用域 :无块级作用域,在每个函数开头部分声明所有变量(let属性)
  • 自动插入分号 :因此大括号风格需使用埃及括号
  • Unicode :javascript字符是16位的,只能覆盖65535个字符
  • parseInt :增加第二个参数,明确进制,parseInt(“08”,10)
  • 浮点数 :二进制浮点数不能正确的处理十进制小数,0.1+0.2不等于0.3,不过整数部分是精确的
  • NaN : typeof NaN === ‘number’ //true; NaN === NaN //false;
  • 对象 :因为原型链的存在,javascript对象永远不会有真的空对象(ES5新增,Object.create)

js中的鸡肋

  • 运算符 ==和!= :会试图强制转化判断值的类型,规则复杂
  • with语句 :可能出现歧义,并影响处理器速度
  • eval :降低安全性,增加阅读复杂性
  • continue :重构移出continue后,性能得到改善
  • ++ – :使代码变得更隐晦
  • 位运算符 :javascript没有整数类型,位操作符将它们的运算数先转换成整数,接着执行运算,然后再转化回去,非常慢
  • function :不在if语句中使用function,尽量用var func = function… 的形式声明
  • new :更好的应对策略是根本不去使用new
  • void :将返回undefined,没有什么用,而且让人困惑

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据挖掘DT机器学习

Python NLTK 处理原始文本

关于处理原始文本部分导入语句: >>> from __future__ import division >>> import nltk,re,pprint ...

2864
来自专栏小樱的经验随笔

【正则表达式学习笔记之一】简单认识正则表达式

一、引言   正则表达式是什么东东?   在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句...

2123
来自专栏你不就像风一样

一文看透Java8新特性:lambda表达式和Stream API

借用引言中的示例,在调用new Thread的含参构造方法时,我们通过匿名内部类的方式实现了Runnable对象,但其实有用的代码只有System.out.pr...

1151
来自专栏Linyb极客之路

JVM 方法内联

调用某个函数实际上将程序执行顺序转移到该函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。

2054
来自专栏老九学堂

干货 | Java 中不得不知的异常和处理详解

简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用...

4027
来自专栏菩提树下的杨过

ActionScript3.0(AS3)中的泛型数组Vector

Adobe官方并没有"泛型数组"的叫法,这是我自己对Vector的叫法(有点标题党),不过Vector在使用上确实跟c#中的泛型数组有些相似之处。 我们知道:A...

2217
来自专栏java学习

java每日一练(2017/8/22)

本期题目 (单选题)1、对于如下代码段可以放入到横线位置,使程序正确编译运行,而且不产生错误的选项是( ) class A{ public A foo()...

2957
来自专栏阮一峰的网络日志

图解 Monad

函数式编程有一个重要概念,叫做Monad。 ? 网上有很多解释(这里和这里),但都很抽象,不容易看懂。我尝试了好多次,还是不明白Monad到底是什么。 ? 昨天...

3354
来自专栏老付的网络博客

如何使用正则表达式

说到正则,可能很多人会很头疼这个东西,除了计算机好像很难快速的读懂这个东西,更不用说如果使用了。下面我们由浅入深来探索下正则表达式:

1422
来自专栏http://www.cnblogs.com

内置函数filter()和匿名函数lambda解析

一.内置函数filter filter()函数是 Python 内置的一个高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是...

32812

扫码关注云+社区

领取腾讯云代金券