前端点滴(JS基础)(一)----倾尽所有
js基础
一、js的组成
ECMAScript(ES) : 负责翻译,为js的核心,解释器。
DOM (Document Object Model 文档对象模型):赋予js操作HTML的能力,document。
BOM (Browser Object Modal 浏览器对象模型):赋予js操作浏览器的能力,window,不兼容不建议使用。
二、js放置位置
js放置的位置可以在head中,body中,body外,js文件中。
但是需要考虑js阻塞问题:
除了一些在页面执行前必须加载的js以外,大多数js应该放置在body标签内的尾部。这主要是因为js会阻塞其后内容的加载和呈现,导致白屏。此外,js的执行过程可能作用于dom tree内的元素,如果放置在前面会报错。
为了避免js阻塞其后内容,可以根据具体需求使用参数async或defer,使JS异步加载。
async,加载和渲染后续元素的过程将和js文件的加载与执行并行进行,async的js元素下载完后立刻执行,不同js的先后执行顺序很可能与页面中的出现次序不同。
defer,加载后续文档元素的过程将和js的加载并行进行,但js的执行要等到所有元素解析完成之后,DOMContentLoaded事件触发之前完成。
三、js输出方式
1、document.write(输出的内容); //这种输出的内容会显示在浏览器页面上
2、alert(输出的内容); //这种方法输出的内容会以提示框的形式显示
3、console.log(输出的内容); //输出的内容会显示在浏览器的控制台。(推荐使用)。
四、js语句与表达式
JavaScript程序的执行单位为行(line),也就是一行一行地执行。一般情况下,每一行就是一个语句。
JS语言中,一条语句结束,可以不用写分号,直接用回车即可。但是建议每条语句后面都加分号。
五、js变量
1. 什么是变量
- 什么是变量
变量是计算机内存中存储数据的标识符,根据变量名称可以获取到内存中存储的数据 - 为什么要使用变量
使用变量可以方便的获取或者修改内存中的数据 - 变量分为
全局变量,局部变量(函数中)
注意:修改全局变量可以不用再次声明
例如:
var a = 1;
a = 2;// var a = 2;
console.log(a); //=> 2
- 变量的生命周期
JavaScript 变量的生命期从它们被声明的时间开始。
局部变量会在函数运行以后被删除。
全局变量会在页面关闭后被删除。
2. 如何使用变量
(1)变量的声明
var、let(es6)、const
var:最常用的声明变量关键字。 定义的变量的时候,若没有初始化,不报错,会输出undefined。其值之后可以修改。
var可以用来声明全局变量,也可以声明局部变量,依据它们声明的位置:
- 全局变量:在函数外定义的变量;(注意:若没有使用关键字声明的变量,默认为全局变量。)作用域是整个代码文件。
- 局部变量:在函数内定义的变量。作用域是当前的函数内部。
let:块级作用域 。在块级{}里面用let定义的变量,离开当前的块{}之后,就不能使用(有点像局部变量,但作用域不一样)。
注意:{…}一对花括弧就就是一个特定的代码块,包括直接的{},流程语句的{},函数的{},循环的{}…。函数声明时本身就带有{},也是属于一个代码块。
const:用于声明常量。注意:定义的变量的时候,必须同时初始化,且其值之后不可以修改。
var、let 声明变量的区别
var 声明变量,具有全局作用域
四大特性:
1.全局作用域
2.同级作用域下,可以存在多个var 声明的变量
3.会发生变量提升
4.设置i仅为循环数组,但循环后,残留一个变量i。
let 块级变量,声明的对象具有块级作用域
四大特性:
1.块级作用域:{}下起作用
2.同级作用域下,只能存在一个(let声明的变量不能重复声明)
3.不能变量提升
4.let 在循环中经常被使用(重点),i变量只在for()内有效,不污染其他区域
const 常量声明
特性:常量的作用域,是常量所在的块。(块可以理解为大括号)
(2)变量的赋值
这里的值可以是null,string类型的值,number类型的值,boolean类型的值,object(Function、Array、Object)…
也可以不赋值,当输出后会显示undefined
3. 变量在内存中的形式
let a1 = 0; // 栈内存
let a2 = "this is string" // 栈内存
let a3 = null; // 栈内存
let b = { x: 10 }; // 变量b存在于栈中,{ x: 10 }作为对象存在于堆中
let c = [1, 2, 3]; // 变量c存在于栈中,[1, 2, 3]作为对象存在于堆中
当我们要访问堆内存中的引用数据类型时
- 从栈中获取该对象的地址引用
- 再从堆内存中取得我们需要的数据
详细请参考:https://www.jianshu.com/p/80bb5a01857a
4. 变量相关问题
(1)只声明变量没有赋初值
(2)重新声明变量
(3)变量提升
在同一个作用域{}中,都会发生变量提升,比如函数中。
六、js数据类型
ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
1. 原始类型和引用类型
基本类型和引用类型这里可称为: 原始类型(值类型)和对象类型(引用数据类型)
原始类型、值类型、基本类型:
null: 只包含一个值: null
undefined: 只包含一个值:undefined
boolean: 包含两个值: true和false
number:整数或浮点数,还有一些特殊值(-Infinity、+Infinity、NaN)
string: 一串标识文本值的字符序列
symbol: 一种实例是唯一且不可改变的数据类型(es6新增)
对象类型、引用数据类型:
Object: 除了常用的Object, Array,Function等都属于特殊的对象
继续细分则是:
5种基本类型:null,undefined,boolean,number,string
1种复杂类型:object
5种引用数据类型:Array,Object,Function,Date,RegExp
3种基本包装类型:boolean,number,string
2种单体内置对象:global(全局属性和函数),math
它们可以使用typeof、instanceof 来查看变量类型,一个变量应只存一个类型的数据。
<script type="text/javascript">
console.log(typeof 1) //=> number
console.log(typeof "1") //=> string
console.log(typeof true) //=> boolean
console.log(typeof {}) //=> object
console.log(typeof []) //=> object
console.log(typeof function(){}) //=> function
console.log(typeof Symbol(1)) //=> symbol
var a;
console.log(typeof a); //=> undefined
console.log(typeof undefined) //=> undefined
console.log(typeof null) //=> object
</script>
为了彻底分清数据类型,封装一个判断:
var a = 123;
var b = 3.14;
var c = 'hello';
var d = true;
var e;
var f = null;
var g = [];
var h = {};
function m(){}
function panduan(x){
if(typeof(x) != 'object')
{
return typeof(x);
}
else
{
if(x instanceof Array)
{
return 'array';
}else if(x instanceof Object){
return 'object';
}else{
return 'null';
}
}
}
console.log(panduan(a)); //=> number
console.log(panduan(b)); //=> number
console.log(panduan(c)); //=> string
console.log(panduan(d)); //=> boolean
console.log(panduan(e)); //=> undefined
console.log(panduan(f)); //=> null
console.log(panduan(g)); //=> array
console.log(panduan(h)); //=> object
console.log(panduan(m)); //=> function
引出问题:
1、console.log(null instanceof Object); //=> false
2、console.log(typeof null); //=> object (使用typeof判断得来)
3、console.log(panduan(f)); //=> null (使用instanceof判断得来)
为什么会矛盾?????
看似二者有些矛盾,但null返回object这个其实是最初JavaScript的实现的一个错误,然后被ECMAScript沿用了,成为了现在的标准,不过我们把null可以理解为尚未存在的对象的占位符,这样就不矛盾了 。对于Null类型的值(只有null),规范就是定义返回"object"这个字符串。但是本质上Null和Object不是一个数据类型,null值并不是以Object为原型创建出来的。所以null instanceof Object是false。但从这里也可以看到,null确实是javascript中用来表示空引用的一个特殊值。使得它不是instanceof Ojbect,而typeof null是“object”。在语义上也是可以理解的。
个人理解(道家学说):
无物不属于万物,却似于万物。
详细可以参考:
https://blog.csdn.net/weixin_42049636/article/details/81565461
https://www.jianshu.com/p/659cbcdcebfd
2. 原始类型和引用类型的区分
引用类型指对象,指的是狭义上的对象。数组不应该算引用类型。
区分是否是引用类型,关键看内存图。
对象在内存的栈区只保存它的地址,在堆区保存它的实际内容,这种类型的变量就是引用类型。
引用类型的一些应用:引用类型可以作为函数的参数
例如:
参数是一个数组
var arr = [1,2,3]
function change(arr){
arr.push(4);
console.log(arr);
}
change(arr); //=>[1, 2, 3, 4]
参数是一个对象
var obj = {name:'chenjianer',age:20}
function change(o){
o.name = 'yaodao'
console.log(o);
}
change(obj); //=>{age: 20, name: "yaodao"}
参数是一个函数 function(称为回调函数),后期经常使用
var callback = function(a){
console.log(a);
};
function change(callback){
var a = 2;
callback (a);
}
change(callback);
3. undefined的产生
js中undefined的几种情况:(一变一对象两函数)
1、变量声明且没有赋值;(或者发生变量提升)
2、获取对象中不存在的属性时;
3、函数需要实参,但是调用时没有传值,形参是undefined;
4、函数调用没有返回值或者return后没有数据,接收函数返回的变量是undefined。
4. null的产生
1、作为函数的参数,表示该函数的参数不是对象
2、作为对象原型链的终点
5. undefined与null之间的区别
1、null和undefined的类型不同
console.log(typeof(undefined)); //undefined
console.log(typeof(null)); //object
null是一个具有有效不存在值的对象,并且它是不可变的,而undefined的对象类型是本身未定义的
此外任何具有null值的算术运算都将产生整数值,而任何带有undefined的算术运算都会导致变量值变为NaN
2、转换为原始类型的方式不同
null和undefined之间的主要区别在于它们被转换为原始类型的方式。在null上执行算术转换时,确定的值为0可以使用以下代码片段验证此转换。
var v1= 5+ null;
console.log(v1)
输出结果为5
但是undefined不执行任何此类转换,如果将undefined添加到数字中得出的结果将为NaN
var v2= 5+ undefined;
console.log(v2)
输出结果为NaN
七、js数据类型的转换
1. 转换成字符串(String)类型
- 使用字符串方法toString([进制])转换,但是null和undefined无法转换。
- 使用顶层函数String()可以将任何数据类型转换成字符串,包括null和undefined。
- 在其他数据类型和字符串类型进行连接 (+操作) 操作时,会自动对其他数据类型使用String()强制转换成字符串,然后在相加(连)(隐性转换)
将其他数据类型的值转换成字符串,可以使用toString(),也可以使用String()。区别在于String可以转换任何类型的值为字符串,toString()不能转换undefined和null。区别二是语法不同。
使用语法:
使用toString() : 待转换的变量.toString();
使用String() : String(待转换的变量);
(1)使用toString()转换
(2)使用String()转换
(3)隐性转换
隐式转换:在其他数据类型和字符串类型进行连接(+操作)操作时或者比较(==操作),会自动对其他数据类型使用String()强制转换成字符串,然后在相加(连)。除此之外,还有(-操作),但是此操作会自动对其他数据类型使用parseFloat()强制转换成浮点型,然后再数学相减。
上述的[object Object] 第一个object表示是何种数据类型,第二个Object表示是那种类型的对象
2. 转换成数值(Num)类型
(1)parseInt() 转换成整型
parseInt() 方法首先查看开头位置的字符,判断它是否是个有效数字;如果不是,该方法将返回 NaN(not a number),不再继续执行其他操作。但如果该字符是有效数字,该方法将查看下一位置的字符,进行同样的测试。这一过程将持续到发现非有效数字的字符为止,此时 parseInt() 将把该字符之前的字符串转换成数字。
例如,如果要把字符串 “12345red” 转换成整数,那么 parseInt() 将返回 12345,因为当它检查到字符 r 时,就会停止检测过程。
注意的是:字符串中包含的数字字面量会被正确转换为数字,比如 “0xA” 会被正确转换为数字10。原因parseInt 按照进制数(基数)解析,0x表示16进制,A在16进制下表示10,parseInt 的正确语法是 parseInt(string, radix(进制数))。不过,字符串 “22.5” 将被转换成22,因为对于整数来说,小数点是无效字符。
(2)parseFloat() 转换成浮点型
道理和转换成整型道理一样,只不过浮点型允许有一个小数点出现。
(3)显性转换(Number() 强制转换)
Number() 函数的强制类型转换与 parseInt() 和 parseFloat() 方法的处理方式相似,只是它转换的是整个值,而不是部分值。
用 Number() 进行强制类型转换,“1.2.3” 将返回 NaN,因为整个字符串值不能转换成数字。如果字符串值能被完整地转换,Number() 将判断是调用 parseInt() 方法还是 parseFloat() 方法。
3. 转换成布尔(boolean)类型
显示的转换是使用Boolean()函数,对需要转换的内容进行转换。
以下内容在转换成布尔值时会被转换成false:
- 数值型的 0
- 数值型的 0.0
- 布尔型的 false
- 空字符串 “”
- 非数字 NaN
- undefined
- null
其他所有值都会转换成true,包括 “0”、空数组 [] 和空对象 {} 。
八、js运算符
1. 赋值运算符
给定 x=10 和 y=5
运算符 | 例子 | 等同于 | 运算结果 |
---|---|---|---|
= | x=y | x=y | x=5 |
+= | x+=y | x=x+y | x=15 |
-= | x-=y | x=x-y | x=5 |
*= | x*=y | x=x*y | x=50 |
/= | x/=y | x=x/y | x=2 |
%= | x%=y | x=x%y | x=0 |
2. 比较运算符
3. 算数运算符
+加-减*乘%除(取余)
4. 逻辑运算符
与、或、非
与(&& )关系,先看左边,左边为true,直接等于右边;左边为false,直接等于左边。
或(|| )关系,先看左边,左边为true,则直接等于左边;左边为false,直接等于右边。
非(!)
var a = 1, b = 2, c = 0, d = false;
var e = a||b; // e = a;
console.log(a||b); // 1
console.log(a||c); // 1
console.log(c||a); // 1
console.log(c||d); // false
// || 关系,先看左边,左边为true,则直接等于左边;左边为false,直接等于右边
console.log(a&&b); // 2
console.log(a&&c); // 0
console.log(c&&a); // 0
console.log(c&&d); // 0
// && 关系,先看左边,左边为true,直接等于右边;左边为false,直接等于左边。
console.log(10||20); // 10
/*var x = 10&&20;
console.log(x||30); // 20*/
//console.log(0&&5); // 0
5. 字符串运算符
PHP中用 点(.) 连接两个字符串。
JS中用 加号(+) 连接两个字符串。
如果使用+的是两个数字,则表示加法运算;如果使用+的有一方是字符串,则表示字符串连接。
console.log(2+3); // 5,表示加法运算,因为参与运算的两个值都是数值型
console.log(2+'hello'); // 2hello,表示字符串相连
console.log('hello ' + 'world'); //hello world
6. 条件(三元)运算符
元,表示参与运算的参数个数。三元意思就是参与运算的有三个值。
var a = (b>c) ? x : y;
上述代码整体意思是给a赋值,值可能是x,也可能是y。关键取决于b是否大于c。如果b>c,则将x赋值给a;如果b不大于c,则将y赋值给a。
7. 一元运算符
var a = 2, b = 3;
var c = a++; // var c = a; a = a+1
var d = ++b; // b = b+1; var d=b;
console.log(a, b , c, d); // a=3, b=4, c=2, d=4
九、 js数组
1. 数组的声明
在JS中,数组也是一种特殊的对象。属于 typeof [1,2,3] == object,但实际上[1,2,3] instanceof Object 为 false。因为数组属于 Array 类型。
三种声明方式:
① var arr = [‘apple’, ‘pear’]; // 推荐使用
② var arr = new Array(‘apple’, ‘pear’); // 一般推荐
③ var arr = new Array(3); //表示数组中有三个单元
2. 获取数组的元素
使用“数组[下标]”可以获取到数组中的值。JS中数组的下标一定是数字类型的。
3. 判断下标是否存在
使用 in 来判断下标是否存在。
语法: 下标 in 数组 如果存在返回true,不存在返回false。
4. 清空数组
清空数组的两种方式:
- 使数组 = [];
- 数组.length = 0;
十、 js对象
1. 创建对象
JS中要得到(定义)一个对象有很多种方式:
- 直接量语法得到(定义)对象
- 构造函数方式得到(定义)对象
- 原型对象方式得到(定义)对象
- 混合方式得到(定义)对象(推荐使用)
(1)直接量语法得到对象
语法:
var obj = {}; //空对象
var obj = {成员名:值, 成员名:值};
var obj = {
成员名:值,
成员名:值
};
(2)构造函数得到对象
这种方式的弊端是,会为每一个对象开辟一个内存,比较占空间,好办法是将p1和p2相同部分放到原型对象上
语法:
function people(){
this.name = 'chenjianer';
this.age = 20;
this.say = function(){
console.log('帅哥一枚!');
}
}
var p1 = new people();
console.log(p1);
(3)原型对象方式得到对象
这种方式的弊端是,如果原型对象中有一个引用类型(数组,对象…)的值,则修改其中一个实例对象,另外一个也会修改
function person(){
}
//原型对象
person.prototype.name = 'chenjianer';
person.prototype.age = 20;
person.prototype.sanwei = ['100cm','90cm']
person.prototype.say = function(){
console.log(123);
}
var p1 =new person();
console.log(p1);
(4)混合方式得到对象(推荐使用)
实际开发中,推荐使用这种方式,减少内存的消耗
function person(n,a){
this.name = n;
this.age = a;
this.sanwei = ['100cm','90cm','110cm'];
}
//原型对象(函数类型)
person.prototype.say = function(){
console.log(123);
}
person.prototype.cook = function(){
console.log('能煮一手好饭菜');
}
//实例化得到对象
var p1 = new person('chenjianer',20);
console.log(p1);
2. 获取对象的成员
点语法用于对象调用里面的成员
对象内部的 this 表示对象本身
3. 判断对象中的成员
使用 in 来判断属性是否存在与对象中。
语法:对象成员 in 对象,存在返回true,不存在返回false。
4. 添加对象的成员
使用点语法添加对象成员。
5. 删除对象的成员
使用delete关键字来删除对象的成员。
6. 修改对象成员
还是使用点语法修改对象成员,先找到对象成员再重新赋值(此处省略)。
十一、 js流程控制
1. 顺序结构
js默认的流程结构。按照书写顺序从上至下执行每一条语句。需要注意的是js不存在等待的说法。
2. 分支结构
(1)条件 (if…else…) 语句
if 语句
语法:
if (condition){
当条件为 true 时执行的代码
}
if…else… 语句
语法:
if (condition){
当条件为 true 时执行的代码
}else{
当条件不为 true 时执行的代码
}
if…else if…else 语句
if (condition1){
当条件 1 为 true 时执行的代码
}else if (condition2){
当条件 2 为 true 时执行的代码
}else{
当条件 1 和 条件 2 都不为 true 时执行的代码
}
(2)switch语句
工作原理:首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个 case 的值做比较(比较规则是 n === 条件
,不仅值要相等,类型也要相同)。如果存在匹配,则与该 case 关联的代码块会被执行。请使用 break 来阻止代码自动地向下一个 case 运行。
语法:
var n = ... // switch参数
switch(n){
case 条件1:
执行代码块 1
break;
case 条件2:
执行代码块 2
break;
default:
与 case 条件1 和 case 条件2 不同时执行的代码
}
3. 循环结构
(1)for 循环
for 循坏
循环(遍历)对象:Num数组,String数组,Object数组
语法:
for (语句 1; 语句 2; 语句 3){
被执行的代码块
}
语句 1: (代码块)开始前执行
语句 2: 定义运行循环(代码块)的条件
语句 3: 在循环(代码块)已被执行之后执行
形式一:
for (var i=0; i<5; i++){
被执行的代码块
}
形式二:
var i=0,len=arr.length;
for (; i<len; i++){
被执行的代码块
}
形式三:
var i=0,len=arr.length;
for (; i<len; ){
被执行的代码块
i++; /*在这++*/
}
其中 i 的声明使用的声明方法请看上述的变量声明
for in 循环
语法:
for (var i in arr){
被执行的代码块
}
实例:
var arr = ['关羽', '张飞', '赵云', '马超', '黄忠'];
for(var b in arr){
//b 表示数组的下标
//arr[b] 表示数组中的每个值
console.log(b, arr[b]);
}
(2)while 循环
while 循环
while 循环会在指定条件为真时循环执行代码块。
语法:
while (条件){
需要执行的代码;
条件自增
}
do while循环
该循环会在检查条件是否为真之前执行一次代码块,然后如果条件为真的话,就会重复这个循环。
do{
需要执行的代码
条件自增
}
while (条件);
区别说明:
/*while循环*/
var a = 1;
while(a < 1){
console.log(a); //=> 没有输出
a++;
}
/*do while 循环*/
var a = 1;
do{
console.log(a); //=> 输出为 1
a++
}while(a < 1);
说明 while 是判断后执行,do while 是执行后判断 。
(3)break 和 continue 语句
break 语句用于跳出循环。(终止)
continue 用于跳过循环中的一个迭代。
break 语句
使用break语法的 for 循环
var i=0;
for( ; ; ){
if(i == 10){
//终止循环
break;
}
需要执行的代码;
i++;
}
简写:
var i=0;
for( ; ; ){
if(i == 10) break; //终止循环
需要执行的代码;
i++;
}
continue 语句
var i=0;
for( ; ; ){
if(i == 2){
// 跳过当前迭代
continue;
}
需要执行的代码;
i++;
}
简写:
var i=0;
for( ; ; ){
if(i == 2) continue; // 跳过当前迭代
需要执行的代码;
i++;
}
十二、js函数基础
1. 函数定义与调用
定义语法:
function 函数名(参数列表) {
//函数体
//return xxx;
}
实例:
/**************** 使用function声明函数,并调用 *******************/
//定义函数,参数为一个大于0 的数字n,要求返回1+2+3+....+n 的和
function sum(n){
//定义一个和
var s = 0; //默认是0
for(var i=1; i<=n; i++){
s = s + i; // s += i;
}
//循环结束之后,就得到一个和
return s;
}
//调用函数
console.log(sum(100));
这种方式定义的函数可以先调用,后定义,也就是函数预加载。
2. 函数表达式
将其看做是一个值,并赋值给一个变量。
var a = sum;
console.log(a(100)); //得到的结果相同
既然函数可以看做是变量,那么就可以像定义变量一样来定义函数,这就是函数表达式的形式:
var a = function sum(x){
console.log('总数为'+x);
}
a(5050); // 调用函数
3. 函数的预加载
什么是函数的预加载?
就是先调用,后声明。
函数预加载指的是哪种方式定义的函数呢?
原因:变量的提升
函数预加载指定是在同一个script代码段中,由“function xxx(){}”这种方式定义的函数,可以先调用函数,再声明函数。
注意不要在非函数的代码块中声明函数。
4. 立即调用模式
(1)立即执行函数是什么
立即执行函数就是
- 声明一个匿名函数
- 马上调用这个匿名函数
(2)为什么使用匿名函数
为的就是营造私密环境,使得变量不被污染,变量不丢失
(3)匿名函数的作用
只有一个作用:
创建一个独立的作用域。
这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
以一个著名的面试题为例:
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
liList[i].onclick = function(){
alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5
}
}
为什么 alert 的总是 6 呢,因为 i 是贯穿整个作用域的,而不是给每个 li 分配了一个 i,或者可以这么理解:就是for循环瞬间执行完,函数都还没开始执行 i 就已经丢掉了,因此需要== 用()将 i保存起来== 这是关键,所以如下:
(4)立即调用与回调函数
那么怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可(当然还有其他办法):
方法一:(立即调用模式)
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
(function(j){
liList[j].onclick = function(){
alert(j) // 0、1、2、3、4、5
}
})(i)
}
方法二:(回调函数)
var liList = ul.getElementsByTagName('li');
function callback(i){
liList[i].onclick = function(){
alert(i);
};
};
function click(callback){
for(var i=0; i<6; i++){
callback(i);
};
};
click(callback);
在立即执行函数执行的时候,i 的值被赋值给 j,此后 j的值一直不变。
i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 j 「分别」是 0、1、2、3、4、5,起到了保存作用。
5. 函数中的this指向
<script type="text/javascript">
(function test(){
console.log(this); //=> this指向全局对象
})();
function test(){
this.name = 'chenjianer' //=> this指向本身实例化对象
};
var test = new test(); // 实例化得到对象
console.log(test.name);
</script>
6. 函数的参数
形参:定义函数时,约定的参数
实参:调用函数时,传递给函数的实际值(实际值包括普通值,引用类型中的值)。
JS函数,参数传递非常灵活,定义的形参和实际传入的实参个数可以不一样。
ES5中,函数的参数不可以用默认值。ES6中,函数的参数可以有默认值的。目前IE11只支持部分ES6的内容。
那么在ES5中,如何实现形参有默认值的写法?
7. 函数作用域
1. 作用域分类
作用域指的是变量起作用的范围。
分为全局作用域和局部作用域。其中局部作用域也叫做函数作用域。
2. 作用域规则
(1)规则一:函数可以使用函数以外的变量
(2)规则二:函数内部,优先使用函数内部的变量
函数内部也会发生变量提升:
(3)规则三:函数内部没有用var声明的变量,也是全局变量
3. 作用域链
在内部函数中查找变量的时候,优先从函数内部自身查找,如果没有查到,则向外层查找,如果外层还没有,则继续向上一层查找,一直查询到全局作用域。这种链式的查找方式就是作用域链。
注意:在函数中的var 声明的变量称为局部变量,只能在函数内部访问,全局下是不能被访问的。详细请看:函数内的变量说明
8. 函数内的变量说明
(1)局部 JavaScript 变量
在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。(该变量的作用域是局部的)。
您可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。
只要函数运行完毕,本地变量就会被删除。
(2)全局 JavaScript 变量
在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。
自调用模式下的全局变量声明,网页上的所有脚本和函数都能访问它。
(3)JavaScript 变量的生存期
JavaScript 变量的生命期从它们被声明的时间开始。
局部变量会在函数运行以后被删除。
全局变量会在页面关闭后被删除。
实例:
/*自调用匿名函数---立即调用模式下*/
var name = 'zhangsan';
(function(){
console.log(name)//这里因为变量提升,name === undefined,所以结果是undefined
var name = 'lisi'
console.log(name)//这里执行的是 name = lisi ,所以自然就是lisi了
})();
console.log(name)//函数的作用域,在全局中无法访问,这里结果是张三
var name = 'zhangsan';
(function(){
console.log(name)//函数内部没有name 这个变量,所以像全局查找,全局有一个name,那么结果就是zhangsan
name = 'lisi'
console.log(name)//同理,这里结果是lisi,因为name被赋值成lisi
})()
console.log(name)//lisi