javascript进阶笔记(1)
学习js已经有一段时间了,大大小小还是能够做出一些东西来。不过觉得可惜的是,还是对js本身这门语言不是很熟悉,总有一点雾里看花的感觉,看得见,但是看不清楚。最近发现有一本关于js的叫做《忍者秘籍》的书刊,听说是jQuery作者写的,可以让初级者进阶,哇啦啦,打怪兽,加经验升级,多好的事情。于是,就有了此篇文章及其后续。闲话休谈,正事要紧!
javascript是一门函数式语言(functional language)。最重要的,在js中,函数是第一型对象(first-class object),也就是说,函数可以共处,可以将其视为其他任意类型的javascript对象。就像普通的js数据类型,函数可以被任意变量进行引用,或声明成对象字面量,甚至可以将其作为函数参数进行传递。
函数的第一型对象体现在:
1、它们可以通过字面量进行创建;
2、它们可以赋值给变量、数组或其他对象的属性;
3、它们可以作为参数传递给函数;
4、它们可以作为函数的返回值进行返回;
5、它们拥有动态创建并赋值的属性。
函数除了以上的功能外,它还包含一个功能,它们可以被调用。千万不要小瞧了函数的调用!因为不同的调用机制会产生不同的功效,特别是针对函数的this关键字。
当我们定义了一个函数,以便其他一些代码在适当的时候回头调用它,我们可以称之为回调。回调是高效利用js必不可少的一部分。
js函数是使用函数字面量(function literal)进行声明从而创建函数值的。例如:
function method(){}
一个函数的创建,由四个部分组成:
1、function 关键字;
2、函数名称,为可选。没有名称的函数称为匿名函数;
3、圆括号包含的一个以逗号分隔的参数列表,该参数列表可以为空,但是圆括号必须存在;
4、大括号包含的函数体。函数体可以为空,但大括号必须存在。
所有的函数都有一个name属性,该name属性值是该函数名称的字符串。没有名称的函数也有name属性,只是该属性值为空字符串。
//该函数的name属性值为Method
function Method(){} //通过匿名函数赋值的情况,该函数的name属性值为空字符串,因为function关键字后面没有函数名称
var method=function(){}; //该函数的name属性值为method,因为该函数声明中,包含了函数名称
var fun=function method(){}
当我们声明一个函数时,我们不仅要关注该函数可用的作用域,还要关注该函数自身所创建的作用域,以及函数内部的声明是如何影响这些作用域的。
js不同于其他面向对象语言,在js中,作用域是由function进行声明的,而不是代码块。或许有的变量或函数声明于代码块,但不终结于该代码块。例如:
function method(value){
//虽然变量i在for代码块中声明,但是变量i的作用域离开了该for代码块也存在,一直到method函数体结尾,下面在if代码块中声明的变量a也是一个道理
for(var i=;i<;i++){ }
alert(i);//10
alert(a);//undefined
a=2;
alert(a);//2
if(true){
var a=;
}
alert(a);//
}
关于变量和函数声明的作用域:
1、变量声明的作用域开始于声明的地方,结束于所在函数的结尾,与代码嵌套无关。值得注意的是,只要在该函数中,变量在其声明之前,还是可以通过对其赋值进行调用,如果不对其进行赋值,那么该变量值为undefined,列子如上面method函数中的变量a;
2、命名函数的作用域是指声明该函数的整个函数范围,与代码嵌套无关。说的就是函数声明提升机制。
3、对于作用域声明,全局上下文就像一个包含页面所有代码的超大型函数。
每个声明项的作用域不仅取决于它的声明,还取决于它是变量还是函数。
在编写js代码时,我们都是称调用js函数,但是,能否应该停下来想一想,函数被调用时,到底发生了什么?
事实证明,函数调用的方式对其函数内部的代码是如何执行的,有着巨大的影响,尤其是针对this参数,这是非常重要的。
实际上,有四种不同的方式可以进行函数调用,每种方式都有它们自己细微的差别:
1、作为一个普通函数进行调用,这是最简单的形式。如:method();
2、作为一个对象的方法进行调用,支持面向对象编程。如:person.setName();
3、作为构造器进行调用,创建一个新对象。如:new Person();
4、通过apply()或call()方法进行调用。如:[].slice.call(argument,0,3)。
在研究函数调用之前,我们先来看函数的参数传递。当一个参数列表作为函数调用的一部分时,这些参数会按照函数声明里的形参声明顺序,将参数值分别赋给这些形参。第一个参数赋值给第一个形参,第二个参数赋值给第二个形参,以此类推。
如果传入的参数与形参的个数不一致,怎么办?别担心,山人自有妙计:
1、如果实际传递的参数数量大于函数声明的形参数量,超出的参数则不会配给形参;
2、如果实际传递的参数数量小于形参数量,则没有对应参数的形参会被赋值为undefined。
在参数传递的时候,有一个非常有趣且非常有用的现象,所有的函数调用都会传递两个隐式参数:arguments和this。所谓的隐式,也就意味着两个参数不会显示在函数签名里,但是它们默默地传递给函数并存在于函数的作用域内。在函数内部,它们可以像其他显示命名的参数一样使用。
arguments参数:这是传递给函数的所有参数的一个集合。该集合拥有length属性,length值为全部参数的个数。我们可以通过for循环遍历出每个参数值,也可以像访问数组一样通过索引去获取其中的某个参数值。例如argument[0]就是获取第一个参数值。在这里,请注意,arguments不是数组!arguments不是数组!arguments不是数组!重要的事情说三遍。它就像一个类数组结构。
this参数:一个函数被调用时,除了传入函数的显示参数外,名为this的隐式参数也被传入了函数。this参数引用了与该函数调用进行隐式关联的一个对象,被称之为函数上下文(function context)。请注意,js中的this依赖于函数的调用方式。
如果一个函数作为普通函数进行调用,也就是例如method()这种,一个函数名称加上圆括号的样式。以这种方式进行调用时,函数的上下文是全局上下文,也就是说隐式传入的this是window对象。
如果将一个函数作为对象的方法进行调用,例如person.setName()这种,则该person对象就变成了setName函数的上下文。也就是说一个方法所属的对象在该方法体内可以以this的形式进行引用。说得通俗一点,传入该对象方法的this是当前调用该方法的对象,也就是person。
注意:相同的函数,其函数上下文(this)会随着函数调用方式的变化而变化,而不是取决于函数是怎样声明的。因为一个函数,可以被当做普通函数调用,也可以赋值给一个对象的方法。
将函数作为一个构造器进行调用,其实它并没有什么特别的地方。只是,构造器函数的声明和其他函数有点不大一样,不同的地方是在于如何调用该函数。将函数作为构造器(constructor)进行调用,我们要在函数名称前使用new关键字,例如:new Person()。
将函数作为构造器进行调用,是js的一个超级特性,因为构造器调用时,会发生如下行为:
1、创建一个新的空对象;
2、将该新的空对象当做this参数传递给构造器函数,从而成为该构造器的函数上下文(this);
3、如果该构造器函数没有显示的返回值,则新创建的对象就会作为构造器的返回值进行返回。
请注意:构造器的目的是要创建一个新对象并对其进行设置,然后将其作为构造器的返回值进行返回。任何干扰或者不存在这种意图的函数,都不适合作为构造器函数。
我们可以用以下代码来测试:
//声明一个构造器函数
function Person(){
this.showSelf=function(){return this;};
} //创建一个对象
var p=new Person(); if(p===p.showSelf())
alert("OK!");
else
alert("Fail!"); //OK! //解析以上代码
//首先声明一个构造器函数Person
//接着,用new调用构造器函数Person,并创建一个对象p
//当构造器函数Person被调用时:
//1.创建一个新的空对象
//2.将新创建的对象当做this参数隐式传递给构造器函数Person。然后在Person内部,this新增了一个方法showSelf
//3.将该新创建的对象当做返回值,并赋值给p变量
//p对象和p.showSelf方法返回的this指向的是同一个对象,因此它们真相等!
由于构造器的编码和使用方式不同于其他函数,除了作为构造器调用之外,通常它们也不是全部都那么有用,因此命名约定的出现是为了区别构造器和其他普通函数的方法。一般函数的命名以动词开头,比如setName、getName之类的。而构造器的名称通常是由一个描述所构造对象的名词来命名,如Person。
在函数调用的时候,js为我们提供了一种方式,就是可以显示指定任何一个对象作为其函数上下文。js中的每个函数都有apply()和call()方法。使用其中一个方法,我们都可以实现这种功能。有的同学会迷惑,为啥函数也有它们自己的方法呢?因为作为第一型对象(透个底,它是由Function()构造器创建的),函数可以像其他任何类型的对象一样,拥有属性和方法。
通过函数的apply()方法来调用函数,我们要给apply()传递两个参数:第一个是函数上下文,也就是this参数,另外一个是作为函数参数所组成的数组。call()方法与此非常类似,唯一不同的就是,给函数传入的参数是一个参数列表,而不是单个数组。如以下代码所示:
function sum(){
var result=;
for(var i=;i<arguments.length;i++)
result+=arguments[i];
this.result=result;
} var obj1={},obj2={};
sum.call(obj1,,,,);
sum.call(obj2,,); alert(obj1.result);//
alert(obj2.result);//11 //其实函数调用apply或call方法,就是显示指定传给函数的this和arguments参数
使用apply()和call()方法,我们可以选择任意对象作为函数的上下文(this)。
我们可以通过apply()或call()方法,给回调函数强制指定函数上下文,也就是this参数。如下代码所示:
//给callback强制指定其this参数为list数组的每个迭代的元素,arguments为当前迭代元素的索引
function forEach(list,callback){
for(var i=;i<list.length;i++)
callback.call(list[i],i);
} var names=['小明','小花','小萌']; //回调函数的this参数就是names数组的单个元素
forEach(names,function(index){
console.log("大家好,我是"+this);
}); //大家好,我是小明
//大家好,我是小花
//大家好,我是小萌
javascript进阶笔记(1)的更多相关文章
- javascript进阶笔记(2)
js是一门函数式语言,因为js的强大威力依赖于是否将其作为函数式语言进行使用.在js中,我们通常要大量使用函数式编程风格.函数式编程专注于:少而精.通常无副作用.将函数作为程序代码的基础构件块. 在函 ...
- javascript进阶笔记(3)
本篇文章我们来学习和讨论一下js中的闭包.闭包是纯函数式编程的一个特性,因为它们能够大大简化复杂的操作.在js中,闭包的重要性不言而喻! 简单的说,闭包(closure)是 一个函数在创建时 允许 该 ...
- #笔记#JavaScript进阶篇一
#JavaScript进阶篇 http://www.imooc.com/learn/10 #认识DOM #window对象 浏览器窗口可视区域监测—— 在不同浏览器(PC)都实用的 JavaScrip ...
- JavaScript学习笔记 - 进阶篇(1)- JS基础语法
前言 JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等) JS进阶篇学习什么? 在JavaS ...
- JavaScript进阶--慕课网学习笔记
JAVASCRIPT—进阶篇 给变量取个名字(变量命名) 变量名字可以任意取,只不过取名字要遵循一些规则: 1.必须以字母.下划线或美元符号开头,后面可以跟字 ...
- 4、JavaScript进阶篇①——基础语法
一.认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面 ...
- JavaScript基础笔记二
一.函数返回值1.什么是函数返回值 函数的执行结果2. 可以没有return // 没有return或者return后面为空则会返回undefined3.一个函数应该只返回一种类型的值 二.可变 ...
- JavaScript基础笔记一
一.真假判断 真的:true.非零数字.非空字符串.非空对象 假的:false.数字零.空字符串.空对象.undefined 例: if(0){ alert(1) }else{ alert(2) } ...
- Java程序猿的JavaScript学习笔记(汇总文件夹)
最终完结了,历时半个月. 内容包含: JavaScript面向对象特性分析,JavaScript高手必经之路. jQuery源代码级解析. jQuery EasyUI源代码级解析. Java程序猿的J ...
随机推荐
- h5游戏引擎有哪些
h5游戏引擎有哪些 一.总结 一句话总结: Layabox Egret Pixi.js Three.js PlayCanvas Cocos2d-js Hilo 1.H5游戏开发语言? Flash_AS ...
- IntelliJ IDEA的这些配置,你值得拥有
一.自动编译开关 二.忽略大小写开关 IDEA默认是匹配大小写,此开关如果未关.你输入字符一定要符合大小写.比如你敲string是不会出现代码提示或智能补充.但是,如果你开了这个开关,你无论输入Str ...
- linux文件管理之bash shell
BASH Shell 对文件进行管理 ========================================================创建.复制.删除.移动.查看.编辑.压缩.查找 内 ...
- piggy.lnk 简析
piggy.lnk 简析 SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; * ...
- 直播 APP 的直播实现流程
直播平台搭建所涉及的事项非常的广泛, 不仅需要直播源码. 直播系统开发. 后台服务 器.专门的运维人员等, 还需要技术团队切实的把控.下面, 小编就给大家确切的说下直播 平台搭建需要用到哪些步骤. 1 ...
- MySQL使用的常见问题
(一)是否启动了服务器 如果没有启动报错:ERROR 2003 (HY000): Can't connect to MySQL server on ‘localhost' (10061) 解决方法:启 ...
- div成圆形分布
1. css3 ul{ width: 200px; height: 200px; background ...
- hdu-3671-tarjin/割点方案
http://acm.hdu.edu.cn/showproblem.php?pid=3671 给出一幅无向图,询问有多少种移除点对的方案使得剩下的连通分量个数大于1. 和上一题差不多的思路直接做n次t ...
- Leetcode 1005. K 次取反后最大化的数组和
1005. K 次取反后最大化的数组和 显示英文描述 我的提交返回竞赛 用户通过次数377 用户尝试次数413 通过次数385 提交次数986 题目难度Easy 给定一个整数数组 A,我们只能用 ...
- laravel响应的发送和程序终止
响应的发送是通过index.php中的$response->send();实现的 vendor\symfony\http-foundation\Response.php public funct ...