基础知识
1、this是在函数运行时生成的一个内部对象:
- 只能在函数内部使用。
- 代表调用函数的那个对象。
- 在构造方法中调用时,指向新生成的对象。
2、由于JS不是面向对象,那么要做到模块化就需要用到一些技巧来实现下面这些目的:
- 不能污染全局变量。
- 不能暴露所有成员,而且模块内部的成员不能被外部的代码修改。
如果是只有一个小文件的话在一个文件中没什么问题,但是在大工程中模块的作用就非常重要了。在CommonJS中,有一个全局的require方法来完成模块的加载(在很多组件中能看到这种用法):
// 第一个参数为所需要的模块数组,第二个参数为回调函数。 require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){ // 回调函数的代码。 });
3、在实现模块化的时候一般会用到立即执行函数,直观上来看应该叫匿名、立即执行的函数,一般有两种写法:
(function () { /* code */ } ()); (function () { /* code */ })();
应该是在括号中的东西被当做是要用的参数,所以才会立即执行吧。
4、闭包
这里是阮一峰老师对闭包的定义:闭包就是能够读取其他函数内部变量的函数。能达到的效果就是让这些变量的值保存在内存中,来看一个例子:
var obj = function () { var a = ''; return { set: function (val) { a = val; }, get: function () { return a; } } }; var b = obj(); b.set('new val'); alert(b.get());// new val
按照正常的情况方法的东西都会在执行完成后被回收掉,但是由于set&get方法中保持了引用,所以此时并不会销毁。这里有另外一个专业解释:
闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。
各种理解之间有点差别。
其他
模块化
在JS定义的方法、变量都将作为全局变量,如果都这么搞的话大家做各种JS包之间的冲突将会非常严重,而且如果想将JS用在后端编程,模块化是必须的。简单地用立即执行函数定义模块如下:
var module1 = (function(){ var _count = 0; var m1 = function(){ /* code */}; var m2 = function(){ /* code */}; return { m1 : m1, m2 : m2 }; })();
模块化除了分离各个部分,还需要考虑如何防止其他人修改模块中的方法和属性,更多可以看这里。在使用模块上面有两个规范:CommonJS和AMD,在CommonJS中有一个全局的require方法来加载模块:
var math = require('math');
math.add(2,3);
这样做最大的问题在于math.add需要在math模块加载完成之后才能执行,在浏览器端显然这是没办法接受的。AMD(Asynchronous Module Definition:异步模块定义)就是应对这种场景产生的,采用异步方式加载模块,模块的加载不影响后面语句的执行,而依赖于此模块的语句放在回调函数中以便模块加载完成之后执行:
require([module], callback);
其中module是要加载的模块,callback则是加载成功之后执行的回调函数。下面来看一个阮一峰老师的例子:
// 在同级目录下新建main.js define(function (){ var add = function (x,y){ return x+y; }; return { add: add }; }); // 在页面上加载模块 require(['./math'], function (math){ alert(math.add(1,1)); });
使用require.js的地址在这里。如果要定义的模块还依赖其他模块,那么define的第一个参数可以用来指定:
define(['myLib'], function(myLib){/* code */ }
另外可以用require.js来加载非规范的模块定义,可以看这里。
PS:太多的JS都是用了模块化,看完了几篇文章有了一点大致的了解了(2015/1/23)。
jQuery
这是目前使用最广泛的一个JavaScript函数库,简化了很多前端开发,而且使得代码的可读性提高了一大截,下面来看简单的用法:
$(document) //选择整个文档对象 $('a:first') //选择网页中第一个a元素 $('div').has('p'); // 选择包含p元素的div元素 $('div').parent(); //选择div元素的父元素 $('div').find('h3').eq(2).html('Hello');// 链式操作 $('h1').html('Hello'); //html()有参数Hello,表示对h1进行赋值 $('div').insertAfter($('p'));// 插入元素 $('<li class="new">new list item</li>');// 创建元素 // 绑定事件 $('input').bind( 'click change', //同时绑定click和change事件 function() { alert('Hello'); } );
另外还可以实现一些特殊效果,这里有jQuery的API文档,虽然jQuery用起来很爽,但是对性能、资源的消耗较大,也要慎重使用(可以参考这里),既然用jQuery对性能有损耗,如果我们做一些简单的功能,那么是不需要用jQuery的,而且jQuery太大的,网络不好的时候有点头疼,解决办法是用一些JavaScript原生的方法来代替jQuery:
function request(type, url, opts, callback) { var xhr = new XMLHttpRequest(); if (typeof opts === 'function') { callback = opts; opts = null; } xhr.open(type, url); var fd = new FormData(); if (type === 'POST' && opts) { for (var key in opts) { fd.append(key, JSON.stringify(opts[key])); } } xhr.onload = function () { callback(JSON.parse(xhr.response)); }; xhr.send(opts ? fd : null); }
这样简单地对原生的请求包装一下也能达到类似Ajax的效果(更多可以看这里),另外还有很多jQuery的替代方法,比如zepto.js。
PS:很多工具用起来都会有副作用,要多思考利弊(2015/1/25)。
------ update ------