chapter 2 JavaScript概览 介绍 js是基于原型,面向对象, 弱类型的的动态脚本语言。
Javascript基础
函数 javascript 中函数最重要。它们都属于一等函数:可以作为引用存储在变量中,随后可以像其他对象一样,进行传递:1 2 var a = function ( ) {}console .log(a);
Javascript 中所有的函数都可以进行命名。有一点很重要,就是要区分函数名和变量名。1 2 3 var a = function a ( ) { 'function' == typeof a; };
调用以下函数时,使用.call 和.apply 方法可以改变this值:1 2 3 4 function a ( ) { this .a == 'b' ; } a.call({a: 'b' });
call 和 apply 区别在于 call 接受参数列表, 而apply接受一个参数数组1 2 3 4 5 6 function a (b, c ) { b == 'first' ; c == 'second' ; }; a.call({a: 'b' }, 'first' , 'second' ); a.apply({a: 'b' }, ['first' , 'second' ]);
函数的参数数量 函数有一个很有意思的属性—参数数量, 该属性指明函数声明时可接受的参数数量。在javascript中,该属性名叫length。1 2 var a = function (a, b, c );a .length == 3; //true
尽管者在浏览器端很少使用, 但是, 他对我们非常重要, 因为一些流行的node框架通过此属性来根据不同的参数个数提供不同功能的。
闭包 在javascript中, 每次函数调用时, 新的作用域就会产生。 在某个作用域中定义的变量只能在该作用域或其内部的作用域(该作用域中定义的作用域)中才能访问到:1 2 3 4 5 6 7 8 9 10 var a = 5 ;function woot ( ) { a == 5 ; var a = 6 ; function test ( ) { a == 6 ; }; test(); }; woot();
自执行函数是一种机制, 通过者中机制声明和调用一个匿名函数, 能够达到仅定义一个新作用域的作用。1 2 3 var a = 3 ;(function ( ) {var a = 5 ;})(); a == 3 ;
自执行函数对声明私有变量很有用的, 这样可以让私有变量不被其他代码所访问。
类 javascript中没有class关键词, 类只能通过函数来定义:
要给所有的Animal的实例定义函数, 可以通过prototype属性来完成:1 2 3 Animal.prototype.eat = function (food ) { };
这里值得一提的时, 在prototype的函数内部, this并非像普通函数那样指向global对象, 而是指向通过该创建的实例对象:1 2 3 4 5 6 7 8 function Animal (name ) { this .name = name; } Animal.prototype.getName(){ return this .name; }; var animal = new Animal('tobi' );a.getName == 'tobi' ;
继承 javascript有基于原型的继承的特定。通常,你可以通过以下方式来模拟类型继承。 定义一个要继承自Animal的构造器。1 2 3 4 5 6 7 8 9 10 11 function Ferret ( ) {};Ferret.prototype = new Animal(); Ferret.prototype.type = 'domestic' ; Ferret.prototype.eat = function (food ) { Animal.prototype.eat.call(this , foot); }
慕课网
1 2 3 4 5 6 var animal = new Animal();animal instanceof Animal animal instanceof Ferret; var ferret = new Ferret();ferret instanceof Animal; ferret instanceof Ferret;
这项技术是同类方案中最好的, 不会改变instanceof操作符的结果。
它的不足: 声明继承的时候创建的对象总要进行初始化(Ferret.prototype=new Animal),这种方式不好。一种解决办法就是在构造器中添加判断条件:1 2 3 4 5 function Animal (a ) { if (false !== a) return ; } Ferret.prototype = new Animal(false );
另外一个办法就是在定义一个新的空的构造器, 并重写它的原型:1 2 3 4 5 6 function Animal ( ) { }; function f ( ) {};f.prototype = Animal.prototype; Ferret.prototype = new f;
v8 提供了更为简洁的解决方案
TRY{} CATCH{} try/catch 允许进行异常捕获。下述代码会抛出异常
var a = 5; a[] 当函数抛出错误时, 代码就停止执行:
1 2 3 4 function ( ) { throw new Error ('hi' ); console .log('hi' ); }
若使用try/catch则可以进行错误处理, 并让代码继续执行下去:1 2 3 4 5 6 7 8 9 function ( ) { var a = 5 ; try { a[]; }catch (e){ e instanceof Error ; } console .log('you get here!' )}
通常会使用如下迭代方式:
通过对键值进行迭代, 可以将它们收集到一个数组中。不过, 如果采用如下方式对prototype进行扩展:1 object.prototype.c = 'd' ;
为了避免迭代中获取c可以用hasOwnProperty来进行检查1 2 3 for (var i in a){ if (a.hasOwnProperty(i)){} }
在v8中, 要获取对象的自由键, 还有更简单的方法:1 2 var a = {a: 'b' , c: 'd' };Object .keys(a);
ARRAY#ISARRAY 对数组使用typeof操作符会返回object, 然而大部分情况下, 我们要检查数组是否真的是数组。1 2 3 4 Array .isArray(new Array ) Array .isArray([]) Array .isArray(null ) Array .isArray(arguments )
数组方法
1 2 3 4 5 6 7 8 9 10 11 12 [1 , 2 , 3 ].forEach(function (v ) { console .log(v); }) [1 , 2 , 3 ].filter(function (v ) { return v < 3 ; }); [1 , 2 ,3 ].map(function (v ) { return v * 2 ; });
字符串方法 要移除字符串首末的空格, 可以使用:
JSON v8 提供了JSON.stringfy 和JSON.parse的方法来对JSON数据进行解码和编码
1 2 var obj = JSON .parse('{"a": "b"}' );obj.a == 'b' ;
FUNCTION#BIND .bind 允许改变this的引用
1 2 3 4 5 function a ( ) { this .hello == "world" ; }; var b = a.bind({hello, "world" });b();
FUNCTION#NAME V8还支持非标准的函数属性名:
1 2 3 4 5 6 7 8 9 10 11 12 var a = function woot ( ) {};a.name == "woot" ; var woot = function ( ) {throw new Error ();};woot(); var woot = function buggy ( ) {throw new Error ();} woot();
PROTO (继承) “proto “使得定义继承链变得更加容易
1 2 3 4 5 function Animal ( ) {}function Ferret ( ) {}Ferret.prototype.__proto__ = Animal.prototype;
存取器 你可以通过调用方法来定义属性, 访问属性就使用defineGetter , 设置属性就使用defineSetter . 比如, 为Date对象定义一个ago属性, 返回以自然语言描述的日期间隔。 很多时候, 特别在软件中, 想用自然语言来描述日期距离某个特定时间点的时间间隔。比如: “某事件发生在三秒前”, 这种表达,要远比“某件事情发生在x年x月x日”, 这种表达更容易理解。
1 2 3 4 5 6 7 8 9 10 11 12 13 Date .prototype.__defineGetter___('ago' , function ( ) { var diff = (new Date ()).getTime() - this .getTime()) / 1000 ) var day_diff = Math .floor(diff / 86400 ); return day_diff == 0 && (diff < 60 && "just now" || diff < 120 && "1 minute ago" || diff < 3600 && Math .floor(diff/60 ) + "minutes ago" || diff<7200 && "1 hour ago" || diff < 86400 && Math .floor((diff/3600 ) + "hours ago" ) || day_diff == 1 && "Yesterday" || day_diff < 7 && "day_diff" + " days ago" || Math .ceil(day_diff/ 7 + "weeks ago" ;});
然后简单的访问ago属性即可
var a = new Date(‘09/18/1991’); a.ago;