JavaScript笔记 – 程序语法设计
一、基础语法设计
JavaScript是可以与HTML标记语言混合、用于网页交互式的解释型脚本语言。由国际标准ECMAScript提供核心语言功能、文档对象模型(DOM)提供访问和操作网页内容的方法和接口、浏览器对象模型(BOM)提供与浏览器交互的方法和接口 三部分组成,基本所有的浏览器支持ECMAScript,但不同的浏览器对于DOM和BOM支持具有很多差别。
1、Script引用语句
在HTML文档中可以在页面的任意位置(建议在<head>标签)定义多个<script>标记,<script>标记定义的方式有 定义js代码段 和 通过src属性引入js文件两种方式。浏览器从上到下、边解释边运行<script>标记,在引用<script>标记中可使用defer属性将其设置为延迟加载(当页面都加载完成后在使用window.onload加载)。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> //使用src引入js脚本文件,其中延迟加载defer=”defer” 只能用于这种方式 <script type="text/javascript" src='./js/HelloWord.js' defer> //引用外部文件,内部代码将不会被执行 window.alert("该语句不会被执行!"); </script>
//定义js代码段,通过不同的对象打印 HelloWord <script type = "text/javascript" > window.alert("浏览器对象打印Hello Word!"); document.write('文档对象打印Hello Word'); console.info('控制台打印Hello Word'); </script>
2、流程控制语句
(1)选择控制结构
//单选择结构 if(逻辑判断条件) 语句块; //双分支选择结构 if(逻辑判断条件) 语句块1; else 语句块2; //条件表达式 (条件表达式1)?表达式2:表达式3 ; //多分支选择结构 if(逻辑判断条件1) 语句块1; else if(逻辑判断条件2) 语句块2; else 语句块3; //switch条件匹配语句 switch(表达式) { case const1: 语句块1; case const2: 语句块2; ..... default: 语句块n; }
(2)循环控制结构
//for循环语句 for(初始化语句;循环判断语句;增量语句) { 语句块; } //while语句 while(循环判断语句){ 语句块; } //do while语句 do{ 语句块; }while(循环判断语句); //特别的: for循环可以不写循环条件表示true,但while循环中不谢循环条件会编译出错。 for(;;){ 语句块; //死循环 }
(3)跳转语句
//break语句跳出当前循环,执行下一条语句 var count = 0; for(var a = 1; a <= 9; a++){ if(a == 3) continue; count++; } alert(count); //循环9次,计数结果为8 //continue语句结束当前某一次循环,执行下一个循环 var count = 0; for(var a = 1; a <= 9; a++){ if(a == 3) break; count++; } alert(count);//计数结果为2 //labe with语句
3、垃圾收集机制
JavaScript是一门具有自动垃圾收集机制的编程语言,开发人员不必担心内存分配和收集的问题。若变量离开作用域且未被使用,则将被自动标记为可回收,可以在垃圾回收期间被删除。垃圾收集算法有标记方法和引用计数法,其中标记清除算法是目前最主流的垃圾收集算法。
function fun(){ var a = 10;//被使用 var b = 20;//被使用 } fun(); //执行完后,a,b被标记为未被使用,等待垃圾收集机制回收
二、Function函数类型
1、函数定义方式
定义函数的方式有function语句形式、函数直接量形式以及Function构造函数形式,Function具有动态性,每new一个就生成一个函数,多用于只用于调用一次的函数;function具有静态特性,多个相同的函数只会编译一次,用于多次调用。执行JavaScript代码时,会优先解析function,再按顺序从上至下执行语句或解析函数。这三张方式区别如下:
(1)函数声明与调用
//方法一:使用function语句 //js 弱类型语言,可不声明就使用 如:参数列表 function 函数名(参数列表) { 语句块; return语句;//返回结果并终止止函数执行 } var result = func1(1,2);//返回3 ,该方式调用可以写在声明前面
var type = typeof (func2);//显示 function 类型
var F = 函数名; //函数赋值
函数名 = null; //函数删除
alert (函数名) //返回函数的定义代码
//方法二:函数直接量形式 //函数是一种引用数据类型,可以直接赋予变量 var func2 = function(){ 语句块; return语句; } //方法三:使用构造函数的方式 var func3 = new Function("a","b","return a+b"); //方法四:作为对象定义
//在js中定义一个对象,等同于定义一个函数,只是对象名大写 function Call(value){ var a=1,b=2; //私有属性,外部无法访问
var dc = function(){ //私有方法,外部无法访问 alert("内部方法"); } alert(a+b); //初始化代码块
this.value = value; //public属性,使用this动态绑定 this.ds = function(){ //public方法 alert("Helloword"); } } var obj =new Call(6); //显示 3 ,类似于函数调用的方式 obj.ds(); //显示 Helloword
obj.value; //返回 6
obj.a; //undefined,无法访问
obj.dc; //error, obj.dc is not a function
//特别的:若将函数作为一个对象,也可以使用对象设置属性的方式设置属性
obj.other = 6; //public属性,使用this绑定
obj ['birthday'] = '2001-02-06'; //public属性,使用this绑定
obj.method = 函数; //public属性,使用this绑定
//嵌套函数定义
function online(){ function inline(){ alert("inline"); } inline();//执行inline函数 } online();
(2)函数的解析顺序
js解析函数时,先解析function,无重载会覆盖,代码从上往下执行。特别的,使用function定义的函数,调用可以写在声明前面。
//① 第一遍 // 函数1被函数4覆盖,自上而下优先解析function // 函数4被函数2覆盖,Function顺序解析 // 函数2被函数3覆盖,直接量顺序解析 //② 第二遍 // 函数4被函数3覆盖,function不会再次解析 // 函数3被函数5覆盖,Function顺序解析 // 函数5被函数6覆盖,直接量顺序解析 function f(){return 1;} alert(f());//4 //函数1 var f = new Function("return 2;"); alert(f());//2 //函数2 var f = function(){return 3;} ; alert(f());//3 //函数3 function f(){return 4;} alert(f());//3 //函数4 var f = new Function("return 5;"); alert(f());//5 //函数5 var f = function(){return 6;} ; alert(f());//6 //函数6
2、函数参数列表
函数参数分为实参和形参,内部是通过一个arguments数组去接收函数的实际参数的,要注意:arguments只能在函数内部访问和使用。
(1)arguments对象
function func(a,b){ //防止形参与实参个数不相等,导致运行错误 if(func.length == arguments.length){ return arguments[0]+arguments[1]; }else{ return "参数不正确"; } }
(2)callee函数
function one(num){ if(num <1) return 1; return num * one(num-1); } alert(one(5));//正确,显示120 //问题描述 var One = one; one = null; // alert(One(5));//错误,因为f已经被置为null,不能进行递归运算 //解决方案 function two(num){ if(num <1) return 1; //返回arguments对象所属函数的引用 return num * arguments.callee(num-1); } var Two = two; two = null; alert(Two(5));//正确,显示120
3、函数作用域
执行环境定义了变量或函数链=有权访问的其他数据,每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在设个对象中,该对象只能由js解析器访问。当代码个环境中执行时,会创建变量对象的一个作用域链(scope chain),用于保证在执行环境中,对有权访问的所有变量和函数可以进行有序访问。
全局执行环境是最外围的一个执行环境,根据ECMScript实现所在的宿主环境不同,表示执行环境的对象也不同。每一个函数都有自己的执行环境,当执行某一函数时,函数的环境就会被推入一个环境栈中,而在环境执行完成之后,栈将其环境弹出,把控制权返回给之前的执行环境。
(1)函数静态作用域
//① 执行环境 window对象(最上层的环境) var n = 1; var k = 4; //每一个函数都有一个执行环境(variable obj) function func() { //② 一级作用域 var k = 3; function func1(){
//③ 三级作用域 alert(n);//低级作用域可以访问上级作用域中的内容 var k = 2; alert(k);//但若有冲突,则以当前作用域中的变量 } var func2 = function(){ //②二级作用域,不可访问3级作用域 alert(k); };
//① Function是一级作用域
var func3 = new Function('alert(k);');
func1();//1,2 func2();//3,alert(k)与写在func()函数内一样 func3();//4,Function是全局作用域 } func();
(2)this动态绑定作用域
this对象是在运行时基于函数执行环境绑定的,其永远指向调用者,在全局函数中,this对象指向window,而当函数被某个对象的方法调用时,this指向那个对象。
var k = 10; function func(){ var k = 20; this.k = 30; } func(); alert(func.k); //undefined,外部无法访问局部变量 alert(k); //30 , this指向的对象是Window
(3)块级作用域
在C、Java等高级语言中,for、if语句具有块级作用域,但在JavaScript中,没有块级作用域的概念,只有函数作用域的概念。
function func(){ for(var i = 1;i<=5;i++){} alert(i); //显示6 (function(){ for(var n = 1;n<=5;n++){}})(); alert(n); //n is not defined } func();
(4)call与apply函数扩展作用域
每一个函数都具有call和apply这两个非继承来的方法,可以在特定的作用域中调用函数,扩展函数的作用域。实际上等于设置函数体内this对象的值。
//call 和 apply函数可以用于传递参数 function sum(x,y){ return x+y; } function func(){ //call和apply用于绑定不同的作用域 var cal = sum.call(this,1,2.2); var apy = sum.apply(this,[1,2]); alert(cal); alert(apy); } func(); //扩展作用域 window.color = 'black'; var obj = {color:'red'}; function showColor(){ alert(this.color); } showColor.call(window);//black showColor.call(obj);//red
//=====================================
//特别的:call方法简单模拟 function mycall(a,b){ return a+b; } //自定义对象 function Obj(x,y){ this.x = x; this.y = y; return x* y; } var obj = new Obj(6,7); obj.call = mycall; Obj(6,7);//返回42 obj.call(obj.x,obj.y);//返回13 delete obj.call;
4、函数回调与闭包
函数也是一种引用数据类型,若函数作为实际参数,则可以与调用函数共用一个作用域(回调函数);若函数作为返回值,则在函数内访问另一个函数的作用域(闭包是运行期中的动态环境)。
(1)回调函数
function recall(fn){ var a=1,b=2; fn(a,b); } recall(function(a,b){ alert(a+b); });
(2)Closure闭包
var name = "外部"; var obj = { name : "内部", getOut:function(){ return function (x) { this.name = this.name+x; return this.name;//动态绑定 } }, getIn:function(){ var o = this;//保存了obj对象 return function (x) { o.name = o.name + x; return o.name ;//参数调用 } } } //函数obj.getOut()中属性是window.name,属于 【动态绑定】 alert(obj.getOut()(4)); //显示 外部4; alert(obj.getOut()(4)); //显示 外部44; //在函数中访问了obj.getIn()函数作用域的变量obj.name,属于 【闭包】 alert(obj.getIn()(5)); //显示 内部"5; alert(obj.getIn()(5)); //显示 内部"55;