JavaScript方法重载(一)

最近在读中文版一书,其中79页(代码清单4.15)有一个函数重载的例子,感觉有点难懂.

1
function addMethod(object, name, fn) {
  var old = object[name];
  object[name] = function(){
    if (fn.length == arguments.length)
      return fn.apply(this, arguments);
    else if (typeof old == 'function')
      return old.apply(this, arguments);
  };
}

var ninjas = {
  values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"]
};

addMethod(ninjas, "find", function(){
  return this.values;
});        //#0

addMethod(ninjas, "find", function(name){
  var ret = [];
  for (var i = 0; i < this.values.length; i++)
    if (this.values[i].indexOf(name) == 0)
      ret.push(this.values[i]);
  return ret;
});             //#1

addMethod(ninjas, "find", function(first, last){
  var ret = [];
  for (var i = 0; i < this.values.length; i++)
    if (this.values[i] == (first + " " + last))
      ret.push(this.values[i]);
  return ret;
});           //#2

assert(ninjas.find().length == 3,
       "Found all ninjas");//#3
assert(ninjas.find("Sam").length == 1,
       "Found ninja by first name");//#4
assert(ninjas.find("Dean", "Edwards").length == 1,
       "Found ninja by first and last name");//#5
assert(ninjas.find("Alex", "Russell", "Jr") == null,
       "Found nothing");//#6

按我的理解,应该是这个例子创建了三个闭包,每个闭包里能访问的是old和fn.
如下图所示,每当调用ninjas.find时都会顺着箭头网上找相应参数个数的函数.
#3 中的调用将会从2个参数的函数开始->1个参数的函数->0个参数的函数
#4 中的调用将会从2个参数的函数开始->1个参数的函数
#5 中的调用将会从2个参数的函数开始
#6 中的调用将会从2个参数的函数开始->1个参数的函数->0个参数的函数->old不是函数
所以这种写法虽然实现了不同参数个数的重载,但是没有判断参数的类型,而且也会使调用变慢.

JavaScript在new一个对象的时候具体发生了什么

我们经常使用new去调用的一个构造器函数, 但是new之后到底做了什么呢?

如:

1
var Person = function (name) {
  this.name = name;
}
var p = new Person("Boring");

以上代码在调用时,会变成如下

1
var p = (Person (name) {
  var _newObj = { //#0
    constructor: Person; // #1
    __proto__: Person.prototype; //#2
  };
  _newObj.constructor(name); //#3
  return _newObj; //#4
})();

解析:
#0 创建一个新的对象,_newObj;
#1 将对象的constructor赋值为Person,即构造器函数;
#2 将对象的__proto__属性赋值为Person.prototype,即原型链的概念;
#3 使用构造器函数的方法设置name属性this.name = name;可以转成_newObj.constructor.call(_newObj, name),此时的this就是指向_newObj,由于call的原因;
#4 返回改对象给p变量.

一个关于javascript闭包和this的题目

##1.

1
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function(){
    return this.name;
  }
}

问:object.getNameFuc()的返回值是什么?
答:”My Object”

##2.

1
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function(){
    return function(){
      return name;
    }
  }
}

问:object.getNameFuc()()的返回值是什么?
答:”The Window”,因为根据函数的作用域链(闭包本身->然后是闭包外面的函数->window)找name,但是object.getNameFunc中并没有name变量,所以只能找到window中的name,不要被object.name中的name迷惑了.

##3.

1
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function(){
    return function(){
      return this.name;
    }
  }
}

问:object.getNameFuc()()的返回值是什么?
答:还是”The Window”,因为闭包的调用者或者是执行者永远都是window,所以this也就是window了.

以前的记录整理

设计模式的六大原则

1.单一职责原则(SRP)
就一个类而言,应该仅有一个引起它变化的原因,也应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。

2.开放封闭原则(OC)
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
因此,开放封闭原则主要体现在两个方面:
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

3.依赖转换原则
a.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
b.抽象不应该依赖于具体,具体应该依赖于抽象。

4.里氏转换原则
子类型必须能够替换掉它们的父类型.

5.迪米特法则–最少知识原则(LoD)
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。

6.合成/聚合复用原则(CARP)
尽量使用合成/聚合,尽量不要使用类继承。这里的聚合指的是各种对象组合.

一些JavaScript的要点

1.javascript中的所有对象都是从Object.prototype对象克隆出来的.

2.对于”对象把请求委托给它自己的原型”这句话,更好的说法是对象把请求委托给它的构造器的原型

比如function Person(){}是一个构造器函数,它有原型Person.prototype,它的实例var p = new Person();并没有p.prototype属性,而是顺着原型链找到Person.prototype

3.一个对象的proto属性指向这个对象的构造器的prototype,即obj.proto –> Obj.prototype

解释:Obj大写,说明是一个构造器函数.和第二点相似

4.原型属性应该指向一个对象,而不是一个函数!!

如Person.prototype = {…some object…};而不能指向Person.prototype = function a();

5.ECMAScript只使用静态(词法)作用域.函数在创建时就确定了作用域

顺便提下,大量介绍JavaScript的文章都认为只有额外创建的函数才是闭包,这种说法是错误的。实践得出,这种方式是最有效的,然而,从理论角度来说,在ECMAScript中所有的函数都是闭包。

6.在ECMAScript中,闭包中的返回语句会将控制流返回给调用上下文(调用者)。

7.闭包的概念
ECMAScript中,闭包指的是:

从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。

从实践角度:以下函数才算是闭包:

即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回,在代码中引用了自由变量

8.JavaScript 中,函数的参数传递方式都是按值传递,没有按引用传递的参数。但是 JavaScript 中有保存引用的对象,比如数组.

9.闭包的调用者或者是执行者永远都是window(在浏览器中)

10.函数声明和函数表达式不同的地方在于函数声明会被提升,而函数表达式不会.

11.所以函数在调用时都会传递两个隐式参数:arguments和this.

Hello World

前言

自买了域名后,就一直被闲置了,于是乎还是重新把博客写起来吧,装装B也是极好的。
接下来应该是做一些老博文的搬迁工作,然后不定时更新一下自己的学习心得、生活琐屑,由于本人十分懒惰,我也不知道什么时候能写第二篇。呵呵(当然也没人会想看~)。

正文 - 感谢录

首先感谢以下作者的博文,让我能快速搭建此博客。

张丹(Conan):blog;email:bsspirit@gmail.com

然后感谢以下作者提供的主题,感觉还是棒棒哒。
黎小腾(Litten): blog

最后感谢一下我自己看到你们的文字。再会。