首页 > 代码库 > 7-11随笔

7-11随笔

一、

Ajax中,XMLHttpRequest对象的status属性一般用来返回服务器的HTTP状态码。status为200表示”成功”,status为404代表”页面未找到”。很多书上都是这样写的,一点也不错。

但是,有时候,特别是刚开始学Ajax的时候,可能会将代码直接在本地运行。这样就出现问题了。如果在本地运行(如:C:\\ajax\\ helloworld.htm),那么status属性不管是在”成功”还是”页面未找到”的情况下,都返回的是0,而不是200和404。这个时候如果还用if(xmlHttp.status==200)来判断运行,则会毫无结果。如果要在本地测试,最好写成if(xmlHttp.status== 200 || xmlHttp.status==0)的形式来判断。

就像我前面所说的,这并不是说很多书或文章里写错了。因为这些文章里都写的是从服务器返回状态,而并没有说从本地返回的情况,应该算是漏掉了吧。

 

二、

FORM中的get post方法区别Form中的get和post方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法。二者主要区别如下: 

1、Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。 

2、 Get将表单中数据的按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而各个变量之间使用 “&”连接;Post是将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向URL。 

3、 Get是不安全的,因为在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后 放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。 Post的所有操作对用户来说都是不可见的。 

4、Get传输的数据量小,这主要是因为受URL长度限制;而Post可以传输大量的数据,所以在上传文件只能使用Post(当然还有一个原因,将在后面的提到)。 

5、Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。 

6、Get是Form的默认方法。

 

三、

1、闭包

 function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){

      alert(n);

    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

2、继承

1、原型链继承

 

核心: 将父类的实例作为子类的原型

 

function Cat(){ 

}

Cat.prototype = new Animal();

Cat.prototype.name = ‘cat‘;

 

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.eat(‘fish‘));

console.log(cat.sleep());

console.log(cat instanceof Animal); //true 

console.log(cat instanceof Cat); //true

特点:

 

非常纯粹的继承关系,实例是子类的实例,也是父类的实例

父类新增原型方法/原型属性,子类都能访问到

简单,易于实现

缺点:

 

要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中

无法实现多继承

来自原型对象的引用属性是所有实例共享的(详细请看附录代码: 示例1)

创建子类实例时,无法向父类构造函数传参

推荐指数:★★(3、4两大致命缺陷)

 

2、构造继承

 

核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

 

function Cat(name){

Animal.call(this);

this.name = name || ‘Tom‘;

}

 

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // false

console.log(cat instanceof Cat); // true

特点:

 

解决了1中,子类实例共享父类引用属性的问题

创建子类实例时,可以向父类传递参数

可以实现多继承(call多个父类对象)

缺点:

 

实例并不是父类的实例,只是子类的实例

只能继承父类的实例属性和方法,不能继承原型属性/方法

无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

推荐指数:★★(缺点3)

 

3、实例继承

 

核心:为父类实例添加新特性,作为子类实例返回

 

function Cat(name){

var instance = new Animal();

instance.name = name || ‘Tom‘;

return instance;

}

 

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); // false

特点:

 

不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果

缺点:

 

实例是父类的实例,不是子类的实例

不支持多继承

推荐指数:★★

 

4、拷贝继承

 

function Cat(name){

var animal = new Animal();

for(var p in animal){

Cat.prototype[p] = animal[p];

}

Cat.prototype.name = name || ‘Tom‘;

}

 

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // false

console.log(cat instanceof Cat); // true

特点:

 

支持多继承

缺点:

 

效率较低,内存占用高(因为要拷贝父类的属性)

无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

推荐指数:★(缺点1)

 

5、组合继承

 

核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

 

function Cat(name){

Animal.call(this);

this.name = name || ‘Tom‘;

}

Cat.prototype = new Animal();

 

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); // true

特点:

 

弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法

既是子类的实例,也是父类的实例

不存在引用属性共享问题

可传参

函数可复用

缺点:

 

调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

推荐指数:★★★★(仅仅多消耗了一点内存)

 

6、寄生组合继承

 

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

 

function Cat(name){

Animal.call(this);

this.name = name || ‘Tom‘;

}

(function(){

// 创建一个没有实例方法的类

var Super = function(){};

Super.prototype = Animal.prototype;

//将实例作为子类的原型

Cat.prototype = new Super();

})();

 

// Test Code

var cat = new Cat();

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); //true

特点:

 

堪称完美

缺点:

 

实现较为复杂

推荐指数:★★★★(实现复杂,扣掉一颗星)

 

3.原型

var decimalDigits = 2,

tax = 5;

 

function add(x, y) {

return x + y;

}

 

function subtract(x, y) {

return x - y;

}

 

//alert(add(1, 3));

但是,这个并不能体现OOP思想,看了原型与原型链之后觉得OOP一目了然:

 

var Calculator = function (decimalDigits, tax) {

this.decimalDigits = decimalDigits;

this.tax = tax;

};

然后给Calculator的prototype属性赋值对象字面量来设定Calculator对象的原型。(个人觉得这里的原型就如同C#中类的概念,prototype则是用来给类添加属性,方法的)

 

复制代码

Calculator.prototype = {

add: function (x, y) {

return x + y;

},

 

subtract: function (x, y) {

return x - y;

}

};

//alert((new Calculator()).add(1, 3));

这样,通过new 一个对象就可以调用里面的公开的方法,属性。

 

原型链

 

function Foo() {

this.value = http://www.mamicode.com/42;

}

Foo.prototype = {

method: function() {}

};

 

function Bar() {}

 

// 设置Bar的prototype属性为Foo的实例对象

Bar.prototype = new Foo();

Bar.prototype.foo = ‘Hello World‘;

 

// 修正Bar.prototype.constructor为Bar本身

Bar.prototype.constructor = Bar;

 

var test = new Bar() // 创建Bar的一个新实例

 

// 原型链

test [Bar的实例]

Bar.prototype [Foo的实例] 

{ foo: ‘Hello World‘ }

Foo.prototype

{method: ...};

Object.prototype

{toString: ... /* etc. */};

 

上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此,它能访问 Foo 的

原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。需要注意的是 

new Bar() 不会创造出一个新的 Foo 实例,而是重复使用它原型上的那个实例;因此,所有的 Bar 

实例都会共享相同的 value 属性。

 

四、

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。

所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页

面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本

(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协

会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )

共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。

 

五、

在JavaScript中,arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。arguments非常类似Array,但实际上又不是一个Array实例。可以通过如下代码得以证实(当然,实际上,在函数funcArg中,调用arguments是不必要写成funcArg.arguments,直接写arguments即可)。

 

Array.prototype.testArg = "test";

function funcArg() {

alert(funcArg.arguments.testArg); 

alert(funcArg.arguments[0]);

}

 

alert(new Array().testArg); // result: "test"

funcArg(10); // result: "undefined" "10"

 

2、arguments对象的长度是由实参个数而不是形参个数决定的。形参是函数内部重新开辟内存空间存储的变量,但是其与arguments对象内存空间并不重叠。对于arguments和值都存在的情况下,两者值是同步的,但是针对其中一个无值的情况下,对于此无值的情形值不会得以同步。如下代码可以得以验证。

 

function f(a, b, c){

alert(arguments.length); // result: "2"

a = 100;

alert(arguments[0]); // result: "100"

arguments[0] = "qqyumidi";

alert(a); // result: "qqyumidi"

alert(c); // result: "undefined"

c = 2012;

alert(arguments[2]); // result: "undefined"

}

 

f(1, 2);

 

3、由JavaScript中函数的声明和调用特性,可以看出JavaScript中函数是不能重载的。

 

根据其他语言中重载的依据:"函数返回值不同或形参个数不同",我们可以得出上述结论:

 

第一:Javascript函数的声明是没有返回值类型这一说法的;

 

第二:JavaScript中形参的个数严格意义上来讲只是为了方便在函数中的变量操作,实际上实参已经存储在arguments对象中了。

 

另外,从JavaScript函数本身深入理解为什么JavaScript中函数是不能重载的:在JavaScript中,函数其

实也是对象,函数名是关于函数的引用,或者说函数名本身就是变量。对于如下所示的函数声明与函数

表达式,其实含以上是一样的(在不考虑函数声明与函数表达式区别的前提下),非常有利于我们理解

JavaScript中函数是不能重载的这一特性。

function f(a){

return a + 10;

}

 

function f(a){

return a - 10;

}

 

// 在不考虑函数声明与函数表达式区别的前提下,其等价于如下

 

var f = function(a){

return a + 10;

}

 

var f = function(a){

return a - 10;

}

 

4、arguments对象中有一个非常有用的属性:callee。arguments.callee返回此arguments对象所在的当前函数引用。在使用函数递归调用时推荐使用arguments.callee代替函数名本身。

 

如下:

function count(a){

if(a==1){

return 1;

return a + arguments.callee(--a);

}

 

var mm = count(10);

alert(mm);

7-11随笔