《javascript语言精粹》学习笔记(一)
-
数字:
- 1、javascript只有一个数字类型。它在内部表示为64位的浮点数,和java的double类型一样。
- 2、它没有分离出整数类型,所以1 和 1.0的值相同。
- 3、NAN是一个number类型的值,不等于任何值,包括其自身
- 4、Infinity 表示大于1.79769313486231570e+308的值
-
语句:
- js中的代码块不会创建新的作用域,所以变量应该定义在函数头部
-
typeof 的值:
- ’number’、’string’、’boolean’、’undefined’、’function’、’object’
-
假值:
- false、null、undefined、空字符串、0、NAN
-
对象:
- 1、属性名可以是包括空字符串在内的任何字符串。
- 2、如果属性名是一个合法的Javascript标识符且不是保留字,则并不强制要求用引号括住属性名。所以用引号括住 “first-name” 是必需的,但是否括住 first_name 则是可选的。 但是尽量使用安全格式,也就是属性名都用引号括住。
-
for in 、Object.keys 、hasOwnprototype 、in:
-
- for in 和 Object.keys:用来遍历对象的属性的
for in 会遍历原型链 、 Object.keys将自身属性名存入一个数组
- in 和 hasOwnPrototype 用来判断属性是否存在
in 会遍历原型链、hasOwnPrototype只搜索自身属性。
- for in 和 Object.keys:用来遍历对象的属性的
-
减少全局变量的污染
- 1、为你的应用只创建一个唯一的全局变量
- 2、使用闭包进行信息隐藏
-
函数:
- 1、arguments不是一个真正的数组,它是类数组,没有数组的方法
- 2、在用new调用构造函数时,如果函数返回值不是一个对象,则返回新创建的对象,否则,返回函数return的对象。
- 3、给对象原型添加方法:
Function.prototype.method = function( name, func ){
!this.prototype[name] ? this.prototype[name] = func : throw("已经存在同名方法【属性】");
return this;
}
-
递归:
//递归操作某个节点及其后代节点:
var walk_the_DOM = function walk( node, func ){
func( node );
node = node.firstElementChild ? node.firsElementChild:node.firstChild ;
while( node ){
walk( node );
node = node.nextElementSibling ? node.nextElementSibling : node.nextSibling;
}
}
-
闭包:
-
一般的函数在执行后,通常其内部作用域都被销毁,因为我们知道有垃圾回收机制来释放不再使用的空间,但是当闭包函数执行后,其内部作用域却没有被销毁,因为闭包返回的函数或对象还在使用内部作用域。
闭包使得函数可以继续访问定义时的作用域。
var quo = function (status){
return {
get_status: function(){
return status;
}
}
}
//这就是闭包,在此返回了一个可以调用其所属作用域变量和方法的对象。
//外部作用域不可访问内部作用域,内部作用域可以访问外部作用域,所以在其所属作用域内的方法和变量只有返回的对象能够访问到了。
//糟糕的例子:
var add_the_handlers = function( nodes ){
var i;
for( i = 0; i < nodes.length; i += 1 ){
nodes[i].onclick = function (){
alert(i);
}
}
}
var add_the_handlers = function( nodes ){
var helper = function(i){
return function(){
alert(i);
}
};
var i;
for( i = 0; i < nodes.length; i += 1 ){
nodes[i].onclick = helper(i);
}
}
也可以这样写:
var i;
for( i = 0; i < nodes.length; i += 1 ){
(function (i){
function(){
alert(i);
}
})(i);
}
-
模块:
-
模块的一般形式:
一个定义了私有变量和函数的函数;利用闭包创建可以访问私有变量和函数的特权函数或者对象,最后返回这个特权函数或【对象】。
-
模块必须具有的条件:
- 1、必须有外部的封闭函数,该函数必须至少被调用一次。
- 2、封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或修改私有的状态。
var serial_maker = function () {
var prefix = '', seq = 0;
return {
set_prefix: function ( p ){
prefix = String( p );
},
set_seq: function ( s ){
seq = s;
},
gensym: function (){
var result = prefix + seq;
seq += ;
return result;
}
}
}
-
级联:
- 级联就是像jQuery那样可以进行链式操作
- 有些方法没有返回值,例如,一些设置或修改对象的某个状态却不返回任何值的方法就是典型的例子。如果我们可以让这些方法返回this,而不是undefined,就可以启用级联。
getElement('myBoxDiv')
.move(350, 150)
.width(100)
.color('red')
.border('10px outset')
.on('mousedown', function ( ){
...
});
-
柯里化
- 柯里化允许我们把函数与传递给他的参数相结合,产生一个新的函数。
//这里就是一个例子,bar是产生的新的函数
function foo(a, b>{
console.log("a:" + a + ", b:" + b);
}
var bar = foo.bind(null,2);
bar(3);//a:2, b:3
-
记忆
-
函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算,这种优化成为记忆。
- 比如:fibonacci数列
var fibonacci = function(n){
return n > 2 ? fibonacci(n-1) + fibonacci(n-2) : n;
}
//我们尝试调用十一次这个函数
for( var i = 0; i <= 10; i += 1){
document.writeln("//" + i + ":" + fibonacci(n));
}
//我们调用了它11次,而其本身调用了442次去计算可能已经计算过的值。
//增加记忆能力:
var fibonacci = function(){
var memo = [];
var fib = function(n){
var result = memo[n];
if(typeof result !=== 'number'){
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
}
return fib;
}(); //立即执行函数表达式 (这里实现了一个闭包)
//这个函数可以使用memo数组, 当数组中没有第N个值时,递归自身将值计算出来,并存入memo数组,如果已经有了第N个值,就返回此结果。
//我们再次尝试调用十一次这个函数
for( var i = 0; i <= 10; i += 1){
document.writeln("//" + i + ":" + fibonacci(n));
}
//我们调用了它11次,而其只调用了自身18次去取的之前存储过的结果。
//将此技术扩展:编写一个帮我们构造带记忆功能的函数,次函数传入两个参数,一个是已知的初始数组memo,一个是formula函数
var memoizer = function(memo, formula){
var recur = function( n ){
var result = memo[n];
if(typeof result !== 'number'){
result = formula(recur, n);
memo[n] = result;
}
return result;
}
return recur;
}
//用法:
var fibonacci = memoizer( [0, 1], function(recur, n){
return recur(n-1) + recur(n-2);
});
var factorial = memoizer( [1, 1], function(recur, n){
return n * recur(n-1);
});