作用域
全局变量
在函数外部方法声明的变量
没有加var关键字声明的变量(隐式全局变量)
// 全局变量 可以在局部使用
var str='夜宵想吃啥?';
function fn1(){
// 函数内部,使用全局变量
console.log(str)
}
fn1();
不在任何函数内定义的变量就具有全局作用域。全局变量在任何地方都能调用。
局部变量
函数内部使用var声明的变量
function fn(){
var a = 1;
}
console.log(a); //报错:a is not defined
在函数内部定义的变量,该变量的作用域是整个函数体,在函数体外不可引用该变量,这是局部作用域
区别:
1.函数外部声明的变量,是全局变量,全局变量可以在任何地方使用;
2.函数内部声明的变量,是局部变量,局部变量在函数外部不能使用;
3.函数内部声明变量,没有var,表示隐式声明的全局变量;
声明周期:
1.全局变量–从代码的开始到结束一直运行
2.局部变量–从函数开始被声明,到函数结束销毁
<script>
var num1 = 1; // 创建一个全局变量
num2 = 2; // 相当于 var num2 = 2; 没加var是隐式全局变量
// 创建一个函数/方法
function test1()
{
var num3 = 3; // 创建一个局部变量
num4 = 4; // 没加var是隐式全局变量
console.log(num1); // 输出全部变量num1
console.log(num2); // 输出隐式全局变量num2
console.log(num3); // 输出局部变量num3
console.log(num4); // 输出隐式全局变量num4
}
// 调用自定义函数
test1();
console.log(num1 + '-');// 输出全部变量num1
console.log(num2 + '-'); // 输出隐式变量num1
// console.log(num3); // 在函数体外部输出局部变量
console.log(num4 + '-'); // 输出函数体内局部变量
</script>
不全部使用全局变量的原因:
1.全局变量从代码开始至结束一直存在,占用内存;
2.造成变量污染,使用不方便;
什么时候声明为局部变量?
1.仅仅在函数的内部使用,就声明为局部变量;
2.需要在函数以外的地方使用就声明为全局变量;
Js的编译和执行
Js的代码以一段一段执行的,两段之间互不影响;
在执行一段代码时,会对Js的代码有一个预编译的过程;
预编译:就是声明所有的var的变量初始值为undefined,再解析定义式函数语句;
Js的执行步骤解析:
1.验证变量的执行顺序;
2.执行函数
函数的调用可以放在函数的声明上面
a();
function a() {}
alert('ok');
弹出ok。预编译的时候,解析了定义式函数语句function a() {},顺利执行。
匿名函数必须先声明,在调用
a();
var a = function() {};
alert('ok');
a不是函数,执行报错。预编译的时候,声明了变量a = undefined;
执行到a()时,a还等于undefined,不是函数,所以执行a()会报错。
JS段之间互不影响
<script type="text/javascript">
a();
alert('first block');
</script>
<script type="text/javascript">
alert('second block');
</script>
弹出second block。因为JS是一段一段执行的,第一段执行到a()的时候报错,
整个第一段都不会再执行,第二段正常执行。
变量的查找规则
遵循就近原则:函数内部调用变量时,会优先使用内部的局部变量,就是先在函数内部查找;
有局部变量就使用局部变量,没有局部变量就使用全局变量;
变量的提升
将变量移动到作用域的最前面,在正式声明一个函数或变量之前就能够使用它;
证明变量的提升:
console.log(a);
var a = '哈哈';
结果:应该是报错但输出undefined.
解释: var a = "哈哈" 定义一个变量,js中分成两步.
1 var a 发生在编译阶段, a = '哈哈'发生在执行阶段.
2 var a会被提升到当前作用域的最前面, a = '哈哈'留在原地等待执行阶段
a = '哈哈';
var a;
console.log( a );
//上面这段代码经过编译之后,变成下面这样
var a; //被提升到当前作用域的最前面
a = '哈哈'; //留在原地,等待执行
console.log( a ); //输出 哈哈
函数的提升:
函数的声明会被提升到当前作用域的最前面,因为当前的作用域是在函数中;
但是函数表达式(匿名函数)是不会被提升的;
在了解编译和执行以及变量的提升,是为了更好的了解JS内部执行的顺序,以避免一些常见的错误;
递归函数
写在开头:递归函数一定要有终止条件,否则便是死循环;
递归函数是函数自己调用自己的过程;
事件函数
事件相当于监听器,等待触发,回调函数;
以”on”开头的都是事件,每个事件后面都有相应的”事件处理”,事件处理一般由函数来担当;
事件与函数的关系:
当触发事件的时候,执行相应函数;
常见鼠标事件
名称 作用
onclick 鼠标点击
onmouseover 鼠标移入元素
onmouseout 鼠标移出元素
onmousemove 鼠标移动(在元素上方不断移动)
onmousedown 鼠标按下(不松)
onmouseup 鼠标松开
表单事件:
onblur 元素失去焦点
onfocus 元素获取焦点(点击出现光标)
onreset 重置表单时触发事件,执行对应的JS功能;
onsubmit 提交表单的时候触发事件,执行对应的JS功能;
onchange 表单内容发生改变,且鼠标离开时触发
oninput input框输入时触发
事件的绑定方式
第一种:行内绑定
<input type="text" name="" value="" onfocus="fn2()" id="">
第二种:js绑定
// 1 获取节点
var divObj = document.getElementById('xiao');
// 2 给div节点绑定移入事件
divObj.onmouseover = function(){}
构造函数及对象类型
凡是能被new的都是构造函数
凡是能被构造函数产生的都是对象
var str1 = new String(456);
// console.log(str1);//输出String(456);
// document.write(str1);//输出456;
// console.log(typeof str1);
注:任何两个对象都不相等;
var str = "123”; //字面量方式生成
console.log(str); //123
console.log(typeof str); //string
var str = new String("123”); //构造函数方式生成
console.log(str); //String {"123"}
console.log(typeof str); //object
构造函数只会产生对象,构造函数是用来构造对象的函数
构造函数用来构造对象,对象被用来编程,面向对象向编程
new关键字,用来执行函数,得到当前执行函数的同名对象
但是,当new系统的类型函数时,得到的是对应的数据类型,但是typeof出来的都是object;
扩展
产生指定范围的随机数
// 1-10的随机数
var num = parseInt(Math.random()*10)+1;
// document.write(num);
// 产生0-7的随机数
var num1 = Math.round(Math.random()*7);
// document.write(num1);
// 13-18之间
var num2 = Math.round(Math.random()*(18-13))+13;
document.write(num2)
指定范围的随机数
function ran(min,max){
return Math.round(Math.random()*(max-min))+min;
}
document.write(2,6);
函数的自执行
声明函数之后,自动执行
(function(str){
alert(str);
})('愿你眼里有光,心里有爱');