注:此为分享记录笔记(分享者Jerry),整理为笔者(PokerMe),转载请注明出处。
Javascript能做什么
- 动态交互效果,跑马灯、DOM切换
- HTML5,画布及矢量图形、离线应用、本地接口、移动端类原生应用
- Js框架组件,AngularJs、backbone、extjs、dojoToolkit、jqueryUI
- 基于Node.js的工具类应用,Grunt、bower、nodewebkit
那么Javascript功能这么强大,我们应该做些什么呢?
More and more development energy is being put into new technologies, such as the ones coming out of HTML5 or the new versions of ECMAScript.
But there isn’t any point to diving into new technologies, or using the hottest libraries, if you don’t have a proper understanding of the fundamental characteristics of the JavaScript language.
-John Resig Secrets of the javascript ninja
这是《js忍者秘诀》作者说的两段话,大概意思是说:越来越多的新的开发方式流行起来,例如HTML5或者新版本的ECMAScript特性。但是!,不管多新的技术或者多热门的类库,如果你对基础的Js语法没有真正的理解透的话,这一切都是徒劳。
PS:其实可以看到在工作和学习过程中,我们经常遇到一些初级前端工程师特别热衷于去寻找一些特效特别绚丽的各种体积庞大的插件,只求能够使用,但是对一些基础的概念都模糊不清(比如我^ ^)。
Javascript函数
javascript主要内容可以用下图说明:
javascript-dom-bom
包含宿主(通常指浏览器)的文档对象模型(DOM)和浏览器对象模型(BOM),然后就是核心ECMAScript.本分享将简要对core作一些介绍。
函数的调用方式
The level of the sophistication of all the code you’ll ever write in JavaScript hinges upon this realization.
-John Resig Secrets of the javascript ninja
大概意思是,你代码的优雅程度取决于你对函数的认知深浅。
在javascript中,函数被称作first-class objects,可以说成一等公民,非常重要。
为什么函数为一等公民因为以下特性:
- created via literals(可以通过字面创建)
var array = [];
/*而不是 var array = new Array();*/
- assigned to variables or properties(可以作为参数赋值)
var fun = function(){};
- passed as parameters (可以作为参数传递)
var fun = {
a:function(){},
b:function(){}
}
- returned as function results(返回一个值)
function fun(args){
return function a(){};
}
- possess properties and methods(拥有的属性和方法)
window.height();
/*height就是他的方法*/
那它的调用方式(invoke)有哪些呢?
PS:熟悉调用方式才能对this的指向有较好的理解
- 一般调用
function a(){}
a()/*一般调用*/
- 作为方法调用
var obj = {
a:2,
fun2:function(){}
}
obj.fun2()//作为方法调用
- 作为构造函数调用
var Person = funtion(){
this.name = "PokerMe";
this.age = 24;
}
var persion = new Person();//作为构造函数调用,即实例化
- apply and call(这个比较难理解,可以理解为改变this的指向)
var color = "white";
var colors = {
color:"black";
}
function getColor(a,b,c){
console.log(this.color);
}
getColor();//this指向全局的color,即输出 white
getColor.call(colors,a,b,c)
//this指向对象colors里面的color,即输出black
getColor.apply(colors,arguments);
//apply和call只是在参数列表上不一样,call需列出所有参数,而apply可以传递一个数组或者对象
函数的作用域
通过讲解以上的函数特性
、函数调用invoke
,应该会对this的指向有初步的理解,那么现在就来介绍下作用域(scope)
,下图为其执行的顺序:
在图中可以看到,作用域链是从当前定义的函数往外面找的,从小的找到大作用域。
先来看两段代码:
function JQuery(){
console.log(global);
}
(function(global){
var jQuery = function(){
console.log(global);
};
global.jQuery = jQuery /*块级作用域暴露接口 供外部调用*/
}(this))
第一种代码是没有经过封装的,其global调用全局window属性,可以任意修改,而第二种,添加封装,将this只向其内部,这样写的好处是,避免函数内部变量的污染,可以直接暴露接口,让外部调用。
PS:第二种为匿名函数.常见的插件都会看到这样一段代码:
(function( $ , undefined ) {
//todo....
})( jQuery );
其目的也是为了构建自己的作用域,不受其他代码的影响。而且其函数是立即执行的。
熟悉了基本的函数特性、函数调用方式、函数的作用域。现在有一些零散的笔记分点列出,作为对函数的扩展理解。
闭包
在初级程序员眼中,这或许是一个非常高大上的名词,写程序的过程中不知道它的存在,但是一旦面试....,这个问题就是必问的几个点,我之前也理解不清楚,比较模糊,此次分享之后就比较清晰了。
那什么是闭包(closure)呢?先来看一段代码
//第一个函数
var a = "a";
function fun(){
console.log(a);
}
fun();
//第二个函数
var b = "b";
globalC = null
function fun1(){
var c = "c";
globalC = function(){
console.log(c);
}
}
console.log(c);//undefined
fun1();//赋值globalC
globalC();//输出c
这两个函数中,第一个是输出变量a,第二个在注释中表明了输出结果.fun()和globalC()同为闭包函数。这里有两种理解,什么是闭包。
1.闭包就是能访问局部变量的函数
2.闭包就是带数据的函数(不是很准确)
也就是说如果一个函数,他跟访问相对局部域下的变量,及为闭包。闭包就是一种特殊的函数。
再来看一段出镜率比较高的一段代码:
var i=0,l=10,j=0,funs=[];
for(;i<l;i++){
funs.push(function(){
consolo.log(i);
});
}
//i=?
// 闭包保存数据是什么?
for(;j<l;j++){
funs[j]();
}
先看注释的里面的两个问题,
1.i等于什么当执行到注释这里的时候?分析下过程。for循环中,i被累加10次,为10,。
2.闭包保存的数据是什么?哪个函数是闭包?
function(){
console.log(i);
}
对吧?后面 一个for循环即执行这个闭包函数10次。那结果应该是什么?
执行一下就知道是10个10。因为第一个for循环已经将全局i赋值为10了,再怎么循环调用的都是这个i。
记忆性
函数记忆性,我不得不承认这是一个优化代码效率的非常好的一种手段。你在下面的代码和测试结果中会惊叹其天壤之别的效率问题,也会明白,原来代码优化是如此重要。
分享者用输出Fibonacci数列(什么是Fibonacci数列?1,1,2,3,5,8.... 【就是后者值为前两者值的和】)来讲明该函数特效。代码如下:
// [ 1, 1, 2, 3, 5, 8, 11 ]
// 常规思路函数fibo()
var fibo = function( n ) {
if ( n === 1 || n === 2 ) {
return 1;
} else {
return fibo( n - 1 ) + fibo( n - 2 );
}
};
//可记忆性方法实现 fibo2()
var fibo2 = function( n ) {
var n1, n2;
if ( !fibo2.cache ) {
fibo2.cache = [];
}
if ( n === 1 || n === 2 ) {
return 1;
} else {
n1 = fibo2.cache[ n - 1 ];
if ( !n1 ) {
n1 = fibo2.cache[ n - 1 ] = fibo2( n - 1 );
}
n2 = fibo2.cache[ n - 2 ];
if ( !n2 ) {
n2 = fibo2.cache[ n - 2 ] = fibo2( n - 2 );
}
return n1 + n2;
}
};
console.time( "fibo" );
console.log( fibo(40) );
console.timeEnd( "fibo" );
console.log( "----" );
console.time( "fibo2" );
console.log( fibo2(40) );
console.timeEnd( "fibo2" );
我们用两者输出Fibonacci数列的第40位应该是多少。读者可以复制执行该代码。结果是 第一个函数的执行时间是2289ms,而第二个函数的是1ms,效率上的差别是几千倍!。所以当我们书写代码的时候,考虑优化代码,不仅是算法效率,在浏览器渲染,标签绑定上也都可以通过可记忆性来优化代码,很简单的Jquery事件注册例子:
//每一次都查找
$('.btn').click(...)
$('.btn').toggle(...)
//只查找一次
var clickbtn = $('.btn');
clickbtn.click(...);
clickbtn.toggle(...);
//将查找封装成一个可以记忆的缓存概念。
var util = {
cache: [],
$id: function( id ) {
return cache[ id ] || $( "#" + id );
}
};
$( "button" ).click(function() {
var username = util.$id( "username" ).val();
});
该分享笔记ending~
PS:PokerMe能力有限,如有错误欢迎指出修改~
网友评论