javascript语言精粹笔记 1-4章

来源:互联网 发布:月球背面 知乎 编辑:程序博客网 时间:2024/05/02 04:43

之前开发用到过JS,但更多的是用更方便的JQ。随着node.js的迅速普及,js似乎变得如同一种万能语言,它的能力在各种主流平台上都可以大展身手。当然在这之前先要把js掌握好。

简介

JS的优点与缺点同样突出。本书主要介绍的是js的优点。

语法

空格

标识符

数字

不区分整数类型与实数类型。
值NaN是一个数值,但不等于任何值包括本身。表示一个非正常的运算结果
值Infinity表示大于1.79769313486231570e+308的值。

字符串

js中的字符是16位的。
\u允许指定用数字表示的字符码位。 'A'==='\u0041';//true

语句

介绍表达式及控制语句。
for in 类似php中foreach,变量为对象中属性名或键名
通常需要检测object.hasOwnProperty(变量)来确定这个属性名就是该对象的成员,还是从其原形链里找到的。

for (myvar in obj){    if(obj.hasOwnProperty(myvar)){        do something.    }}

throw中的表达式通常是一个对象字面量,包含name和message属性。

表达式

字面量

对象字面量是一种方便指定新对象的表示法。

函数

对象

js类型包括数字、字符串、布尔、null、undefined,其他都是对象。
js中对象是可变的键控集合,数组、函数、正则表达式都是对象。
js对象是属性的容器,属性值可以是undefined之外的任何值。
js对象是无类别的,对象可以包含对象。
js包括一个原型链特性,允许对象继承另一对象的属性,正确使用能减少对象初始化的时间和内存消耗。

对象字面量

对象字面量提供了一种非常方便的创建新对象值的表示法
这种表示法跟json好像啊。。。。
属性名可以不被”“括住。

var obj={    id:'101',    sex:'m',    name:'xiaoming',    attr:{        hp:'100',        mp:'80',        attack:'5'    }}

检索

使用[]或.取得对象中的值 .更常用少打个字符
给默认值 var test = obj.noexist || 'none';
检索undefined会导致typeError异常,可以这样避免
obj.noexist && obj.noexist.test //不会报错,表达式值为undefined

更新

引用

原型

每个对象都连接到一个原型对象,并且它可以从中继承属性。所有通过对象字面量创造的对象都连接到Obeject.prototype这个js中标准的对象。
当你创建一个新对象时,你可以选择某个对象作为它的原型。这句懂 var a=obj;
js提供的实现机制杂乱复杂,其实可以简化。给Object加一个beget方法,创建一个使用原对象作为其原型的新对象。 没明白

if(type Object.beget!=='function'){    Object.beget=function(o){        var F=function(){};        F.prototype=o;        return new F();    };}//这是为了让新对象连接的prototype变成stooge么。var another_stooge=Object.beget(stooge);

原型连接只有在检索值的时候才被用到。
若尝试获取某个不存在属性名的值,js会试着从原型对象中获取,若原型对象也没有,再从它的原型中寻找,直到最后到达终点Object.prototype。要还没有,结果就是undefined。这个过程叫做委托
那么上面的beget方法就是完全为了实现委托才设计的构思了
原型关系是动态的,若添加一个新的属性到原型中,该属性会立即对所有基于该属性的对象可见。相当于祖先父子关系,祖先有的属性,父子能用,父的属性,子能用

反射

确定对象独有的属性 非原型链的
hasOwnProperty的方法 可以用来检查是否对象自己的属性
obj.hasOwnProperty('test');//true or false

枚举

for in用来遍历对象中的所有属性名,包括原型的。通常只操作数据的话,使用hasOwnProperty排除原型的,再用typeof排除函数
使用for in的时候 属性名出现的顺序是随机的,若要以特定顺序出现,应该使用一个数组。

var p=['first','second','third','last'];for(var i=0;i<p.length;i++){    document.writeln(p[i]+':'+stooge[p[i]]);}//对象为stooge

删除

delete 运算符 可以删除属性 但不会触及原型链中的对象
delete obj.name;

减少全局变量污染

js可以随意定义全局变量,但正因为这样削弱了程序的灵活性,应该避免。
最小化使用全局变量的一个方法是在应用中只创建唯一一个全局变量,并把它作为应用的容器。

var myapp={};myapp.stooge={    first:'joe',    last:'mike'};

只要把用到的都放在这个变量里,那这就形成了一个封闭的黑箱,并且不会对其他模块冲突。

函数

js最好的特性就是对函数的实现

函数对象

js中,函数就是对象,它连接到Function.prototype(该原型连接到Object.prototype)。
每个函数在创建时附有两个隐藏属性:函数的上下文和实现函数行为的代码。
还有一个prototype属性,它的值是一个拥有constructor属性且值为该函数的对象,这和Function.prototype完全不同。看不懂,但提示在下个章节揭开。

书中译注:js创建一个函数对象时,会给该对象设置一个“调用“属性,当js调用一个函数时,可以理解为调用此函数的“调用“属性。

函数字面量

我习惯这样定义函数

function test(a){    return a;}

但js里可以这样 因为函数是对象

var test = function(a){    return a;}

函数字面量可以出现在任何允许表达式出现的地方,也可以被定义在其他函数中。
一个函数能访问自己及上层函数至全局的参数和变量。
通过函数字面量创建的函数对象包含一个连到外部上下文的连接,这被称为闭包
这是js强大表现力的根基。

调用

调用函数时将暂停父函数执行,传参时除了形参还会接受两个隐藏参数:this和arguments.
this的值取决于调用模式,有4种情况:
1. 方法调用模式
当一个函数被保存为对象的一个属性时,叫做一个方法。方法被调用时,this代表该对象。
通过this可取得他们所属对象的上下文的方法称为公共方法
2. 函数调用方式
当函数不是一个对象的属性,则当作一个函数来调用。
这种方式调用时,this被绑定到全局对象。书中称这是语言设计上的一个错误。
让它能调用父级对象的办法是,给父级对象定义一个变量 赋值为this,函数使用这个变量即可。如果它父级也仅作为一个函数而不是方法,那就不行了 - -
3. 构造器调用模式
js是基于原型继承的语言,而语言的主流是基于类,但js对自己这套也没信心,所以也提供了类似的对象构建语法。
在函数前面带上new来调用,会创建一个隐藏连接到该函数的prototype成员的新对象,同时this会被绑定到那个新对象上。
书中不推荐这种形式的构造器函数,并且下一章提出解决方案
4. Apply调用模式
apply方法让我们构建一个参数数组并用其调用函数。
apply方法接受两个参数,1是被绑定给this的值,2是一个参数数组。
没看懂

参数

每个函数被调用都有一个arguments参数,这是一个包含所有实参的数组。
书中称arguments并非真正的数组,只是类似数组的对象。也是语言设计错误所在。

返回

return或到最后}位置返回。
没有指定返回值,则返回undefined.
若new函数,并且返回值不是一个对象,则返回this(该新对象).不懂

异常

throw 主动抛出
try
catch 捕获

给类型增加方法

js允许给基本类型增加方法,3章中已经实现给Object.prototype添加方法给所有对象使用。
这种方式对函数、数组、字符串、数字、正则表达式、布尔同样适用。
例:

Number.prototype.int=function(){    return Math[this<0?'ceil':'floor'](this);}document.writeln(10/3).int()//3

可能是版本或其他原因书中代码测试并未成功,根据原理改写为以上代码成功

递归

放一个汉诺塔的例子

var hanoi=function(disc,a,b,c){    if(disc>0){        hanoi(disc-1,a,c,b);        document.writeln('Move disc'+disc+'from'+a+to'+c);        hanoi(disc-1,b,a,c);    }}hanoi(3,'a','b','c');

尾递归:如果一个函数返回自身递归调用的结果,那么调用的过程会被替换为一个循环,可以显著提高速度。
->js**并没提供**尾递归优化。

作用域

大多数C语言语法的语言,都有块级作用域。然而js**并没有**。
js只有函数作用域。

闭包

没怎么看懂,大意是外部函数结束了,但内部函数未结束时,仍可以访问外部函数中的属性、参数等上下文环境。

回调

函数可以让不连续事件的处理变得更容易。js并不会等到一个函数处理完了才处理下一个
例:

var request=data;//准备发送的数据//同步执行方法 在等待服务器返回的时间,客户端是暂停状态-因为display无法执行var response=sendToServer(request);//发送到服务器display(response);//显示结果//异步执行方法 display放到回调函数里,等待时间里客户端继续往下执行其他操作sendToServer(request,function(){    display(response);});

模块

使用函数和闭包来构造模块,模块是一个提供接口,隐藏状态与实现的函数或对象。
例:给string加一个d方法,用来对html特殊字符进行替换。需要保存一个字符与替换字符的对象,这个对象应该放在哪里?
1、全局变量-但全局变量是魔鬼。原话
2、定义在函数本身,但运行时会有损耗,因为该函数每次被执行该字面量都会被求值一次。
3、放入闭包。
例子代码大意为:给string的原型加一个属性函数(比如 叫re)(闭包)(定义的时候就执行了所以加的不是这个函数而是它返回的函数),里面定义字符与替换字符的对象,然后返回一个匿名函数(这个函数才是调用re时的函数因为re函数在定义的时候就执行了)这个函数返回this(这里代表的它的上级对象也就是调用它的string).replace(额 例子中的replace函数没看懂 但意思是使用闭包里的对象来替换)
模块模式利用函数作用域(访问外部函数信息)和闭包(re的生命只有定义时执行了一次,但它虽然挂了可re返回的匿名函数可以继续使用re内定义的对象,并且这个对象是无法被其他函数访问的)来创建绑定对象与私有成员的关联。
模块模式的一般形式:一个定义了私有变量和函数的函数,利用闭包创建可以访问私有变量和函数的特权函数,最后返回这个特权函数,或者把他们保存到一个可访问到的地方。

级联

有的方法(函数)没有返回值(没有return时返回undefined),如果让这样的方法返回this(return this),就可以使用级联。
级联就是在一条语句中依次调用这个对象的很多方法。
比如
getElement('div').width(100).height(20).color('red').fontsize('2em');

套用

套用允许我们将函数与传递给它的参数结合去产生一个新的函数。
没看懂

记忆

函数可以用对象去记住先前操作的结果,从而能避免无谓的运算,这种优化被称为记忆。
计算机领域:记忆是用于加速程序计算的优化技术,它使得函数避免重复计算之前已经被处理的输入,而返回缓存的结果。
例子中以fibonacci数列进行讲解对比(正常 与 使用记忆)看懂了,是使用闭包中的变量存放计算好的数,函数中先查看变量中有没有这个(有就是计算过,无需再计算),没有再去计算。感觉其他语言的话可以用静态变量来实现。然而后面扩展为一般化,编写一个函数来帮我们构造带记忆功能的函数,没看懂

var memoizer=function(memo,fun){    var shell=function(n){        var res=memo[n];        if(typeof(res)!=='number'){            res=fun(shell,n);            memo[n]=res;        }        return res;    };    return shell;}//一般化的通用的能产生其他函数的函数。var fibo=memoizer([0,1],function(shell,n){    return shell(n-1)+shell(n-2);});//fibonacci函数用它实现var fact=memoizer([1,1],function(shell,n){    return n*shell(n-1);});//阶乘for (var i=0;i<11;i++){    document.writeln('<br/>'+i+':'+fibo(i));}//多次调用for (var i=0;i<11;i++){    document.writeln('<br/>'+i+':'+fact(i));}//多次调用

手抄了一遍代码并实际运行后懂了,刚才不懂shell感觉在定义之前就用到了,但实际上shell在shell内部调用目标函数的时候才用到,总之,很绕

这本书几乎句句都是重点,书里的代码也是非常适用。尽管如此还是有不懂的地方,以后还得再读。
0 0