来到第四章。javascript
函数:前面说过,函数就是对象,特色就是还可以被调用。前端
<!-- lang: js --> var add = function (a,b) { return a + b; }
当一个函数为对象的一个属性时,咱们称之为方法。当方法被调用时,this绑定到该对象。java
<!-- lang: js --> var myObject = { value : 0, increment : function (inc) { this.value += typeof inc === 'number' ? inc : 1; } }; myObject.increment(); // 1 document.writeln(myObject.value); myObject.increment(2); // 3 document.writeln(myObject.value);
当一个函数并不是一个对象的属性时,那么它就是被看成一个函数来调用。它仅仅是一个函数而已。node
<!-- lang: js --> var sum = add(3,4);
注意:这样调用函数,this 被绑定到全局对象。一个解决方案是:若是该方法定义一个变量并把它赋值为this,那么内部函数就能够经过那个变量访问到this,按照约定,那个变量命名为that。面试
<!-- lang: js --> myObject.double = function () { var that = this; var helper = function () { that.value = add(that.value. that.value); }; helper();// 以函数形式调用helper } //以方法的形式调用double myObject.double(); document.writeln(myObject.value);
若是在一个函数前面加上new来调用,那么背地里会建立一个连接到该函数的prototype成员的新对象,同时this会绑定到那个新对象上。ajax
<!-- lang: js --> //建立一个名为Quo的构造器函数。它构造一个带有status属性的对象 var Quo = function (string) { this.status = string; } //给Quo的全部实例提供一个名为get_status的公共方法 Quo.prototype.get_status = function () { return this.status; } //构建一个Quo实例 var myQuo = new Quo("confused"); document.writeln(myQuo.get_status());
apply方法让咱们构建一个参数数组传递给调用函数。接收两个参数,第一个是要绑定给this的值,第二个就是一个参数数组。
实际就是把一个本来不是属于本身的方法或函数用在本身身上,这就是apply的意思。正则表达式
<!-- lang: js --> var array = [3,4]; var sum = add.apply(null,array);//7,用了上面定义的add函数,用数组传递参数 //构造一个包含status成员的对象 var statusObject = { status : "A-OK" }; //statusObject 并无继承自Quo.prototype,但咱们能够在statusObject上调用get_status方法,尽管statusObject并无 var status = Quo.prototype.get_status.apply(statusObject);//A-OK
当函数被调用时,会获得一个"免费"配送的参数,那就是arguments数组。数组包括传递给形参的参数,也包括没有分配形式参数的多余参数。也就是说传递给形参的参数能够经过两种途径在函数中取得。算法
<!-- lang: js --> var sum = function (){ var sum = 0; for(var i = 0; i < arguments.length; i += 1){ sum += arguments[i]; } return sum; } document.writeln(sum(1,2,3,4));//10
(感受本身很没注意差错控制检验这方面的事情TT) 这一部分跟C++差很少,有throw就要有对应的catch。catch到的error要对应throw出来的东西。例子跑出的是一个对象,则catch的参数对应一个对象,而后把对应的信息输出来。
书上例子先理解下。数组
<!-- lang: js --> var add = function (a,b) { if (typeof a !== 'number' || typeof b !== 'number') { throw { name : 'TypeError', message : 'add needs number' }; } return a + b; } var try_it = function () { try { add("seven"); } catch (e) { document.writeln(e.name + ': ' + e.message); } } try_it();
js可以给语言的基本类型扩充功能。第三章对象的时候,咱们能够经过给Object.prototype添加方法,可让该方法对全部对象均可用。这样的方式对函数,数组,字符串,数字,正则表达式和布尔值都适用。
下面这个扩充在后面会常常用到的喔!闭包
<!-- lang: js --> Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; }
经过给Function.prototype增长方法来是的该方法对全部函数可用。咱们下次给对象增长方法时就不用键入prototype这几个字符,省掉一点麻烦(不是很懂。。实际上是不是看起来帅点,优雅一点呢)
由于基本类型的原型是公用结构,因此在类库混用时务必当心。一个保险的作法是指在肯定没有该方法时才添加它。
<!-- lang: js --> Function.prototype.method = function (name, func) { if (!this.prototype[name]) { this.prototype[name] = func; } return this; }
递归就是那意思,调用函数自身去解决它的子问题。 很少说,以为里面一个遍历DOM树的函数写的不错。
<!-- lang: js --> var walk_the_DOM = function walk(node, func) { func(node); node = node.firstChild; while (node) { walk(node,func); node = node.nextSibling; } }
这一方面好像以前看过的几道前端面试题目就有这个的内容,基础要掌握啊!!
从新找回之前的一篇博文来看,才发现之前都没怎么理解,此次看了几个钟,有些收获。墙裂建议看看:http://blog.csdn.net/rommel1/article/details/7804973
总结一下就是,像javascript这样的解释型语言,基本分为两个阶段,编译期与运行期。在预编译阶段,它是用函数来划分做用域,而后逐层为其以 var 声明的变量与函数定义开辟内存空间,再而后对var变量进行特殊处理,通通赋初始值为undefined。 在研究上文的过程当中,又看到类属性和实例属性的概念,又找了一篇文章,感受说的还比较全面。最重要的一点:动态共有属性优于原型属性。即:若是两者都定义了同一属性,则最终的属性值以动态公有属性为准。附连接:http://evanwukong.blog.163.com/blog/static/134836495201141752910780/
闭包的好处是内部函数能够访问定义他们的外部函数的参数和变量(除了this和arguments) 以前的Quo构造器没什么意义,能够直接访问到的属性为何要用一个getter方法去访问呢? 因此下面的方式比较推荐。
<!-- lang: js --> var quo = function (status) { return { get_status : function () { return status; } }; }; //构造一个quo实例 var myQuo = quo("amazed"); document.writeln(myQuo.get_status());
这个quo无需在前面加new,即便quo已经返回,但get_status仍能够访问到quo对象的status属性。
下面是一个设置DOM节点为黄色,而后把它渐变为白色的函数。
<!-- lang: js --> var fade = function (node) { var level = 1; var step = function () { var hex = level.toString(16); node.style.backgroundColor = '#FFFF' + hex + hex; if (level < 15) { level += 1; setTimeout(step, 100); } }; //书中是setTimeout(step, 100);我以为下面也能够 step(); }; fade(document.body);
一个糟糕的例子,
<!-- lang: js --> var add_the_handleers = function (nodes) { var i; for (i = 0; i < nodes.length; i += 1) { alert(i); } };
这个例子的本意是想每个节点alert出不一样的值,,可是因为绑定的数是变量i自己,而不是函数在构造时变量i的值。 改良一下,
<!-- lang: js --> var add_the_handlers = function (nodes) { var helper = function (i) { return function (e) { alert(i); }; }; var i; for (var i = 0; i < nodes.length; i += 1) { nodes[i].onclick = helper(i); }; }
利用函数包装成模块,提供接口却隐藏状态与实现的函数或对象。 咱们想给String增长deentityify方法,用来寻找字符窜中的HTML字符实体并把他们替换为对应的字符。这就须要保存字符实体及其对应字符。咱们不能在全局变量中保存,保存在函数内部又会带来运行时的内耗,觉得每次执行该函数时该字面量都会被求值一次。理想方法就是放进闭包里。
<!-- lang: js --> String.method('deentityify', function () { var entity = { quot : '"', lt : '<', gt : '>' }; return function () { return this.replace(/&([^&;]+);/g, function (a,b) { var r = entity[b]; return typeof r === 'string' ? r : a; } ); }; }()); document.writeln('<">'.deentityify());//<">
注意最后一行的括号,用()运算法马上调用咱们刚刚构造出来的函数。由于返回的是函数,要让调用deentityfy函数执行代码,因此要加括号。 模块模式的通常形式是:一个定义了私有变量和函数的函数,利用闭包建立能够访问私有变量和函数的特权函数,最后返回这个特权函数,或者把他们保存到一个可访问到的地方。
这个要根据具体状况来作,好比把一些后面须要用到的结果保存在一个数组,后面用到直接取值,就不用再去计算了。