作用域
对象 | 类型 |
---|---|
window | 全局作用域 |
function | 局部作用域(函数作用域) |
{ } | 块状作用域 |
this | 动态作用域 |
全局作用域
全局作用域: 变量在函数外部或者花括号外部定义的变量,即拥有全局作用域(不讨论 没用var在函数内部声明的变量)
//在全局作用域下用var定义abc
var abc = 123 ;
//在全局作用域中可以调用该变量
function test(){
console.log(abc);
//在函数内部(函数作用域)也可调用abc变量
}
test(); //控制台输出123
//第二种情况在函数内部 没用var定义的变量
function test(){
abc=123;
console.log(abc); //输出123
//在函数内部可以调用
}
test(); //输出123
console.log(abc); //输出123
//在全局作用域中可以访问
特别注意
用var在全局作用域中的定义的变量 和在函数内部没用var声明的变量有本质的区别详见下述代码块
var abc = 123;
function test(){
abcd = 321;
}
test();
console.log(abc); //输出123
console.log(abcd); //输出321
delete abc;
delete abcd;
console.log(abc); //输出123
console.log(abcd); //提示: abcd is not defined
//没有用var声明的变量相当于是window下的一个属性,
//可以用delete删除,而用var定义的变量不能被delete删除。
//所以abc可以访问到,abcd会报错 提示abcd没有定义
局部作用域(函数作用域)
局部作用域: 变量在函数内部部或者花括号内部部定义的变量,即拥有局部作用域。从外层作用域是无法访问的 是一个封闭的作用域
function test(){
var abc = 123;
}
console.log(abc); //报错abc未定义
//由于abc在函数内部定义定义的 即在函数作用域下起作用所以在外层作用域中使用该变量时,
//报错提示未定义
若在需要访问内部变量的场景下有两种方法可以使用
第一种 用闭包返回
function test(){
var abc = 123;
function test123(){
return abc
}
return test123
}
console.log(test()()); // 输出123 这就通过闭包的方式在全局作用域下,
//访问到在test函数中定义的abc变量了
第二种 直接return
function test(){
var abc = 123;
return abc
}
console.log(test()); //输出123
return是函数对外交流的窗口
ES6块状作用域 { }
//用var声明的变量除了函数作用域的{ } 其余的{}定义的变量都不是局部作用域
if(true){
var abc = 1;
console.log(abc); // 输出1
}
console.log(abc); //输出1
//用let声明的变量在{ }中就形成块状作用域 只在{}中可以访问到
if(true){
let abc = 1;
console.log(abc); //输出1
}
console.log(abc); //报错 abc未定义
动态作用域 (this)
可以用call bind apply 动态的指定this的指向
window.a = 1;
function test() {
console.log(this.a)
}
test.bind({a:100})() //输出100 用bind改变了this的指向 {a:100}
test() // 输出1 此时的this指向window
区分静态作用域和动态作用域
//在全局中定义一个函数test
function test(){
console.log(abc)
}
// 在全局中定义另一个函数test1
function test1(){
//在局部中定义变量
var abc = 123;
//调用全局中定义的函数
test();
}
var abc = 321;
test1(); //输出321
上述代码,调用test1()输出321说明在test()执行的时候找的abc是全局下的abc,也就是test函数定义的时候所在作用域下的abc。 此时的作用域是全局作用域,是在定义的时候决定的 这就称之为静态作用域。
而javascript默认使用静态作用域
若上述代码采用动态作用域的话 test1的输出则为123,执行过程就是test执行的时候本身没有abc变量 直接往执行地的上层作用域寻找 在test1作用域中找到变量abc值为123 则test1最后结果就为123.
let && const
let
1、用let声明的变量具有块级作用域
//形成了一个代码块 外部访问不到变量abc
{
let abc = 1
}
console.log(abc); //报错
2、用let声明的全局变量不是全局对象window的属性
就是不能通过window来访问
var abc = 1
console.log(window.abc) //输出1 可以用window来访问
-----------------------
let abc = 1
console.log(window.abc) // 显示未定义
3、用let重定义变量会抛出一个语法错误
即用let的定义的变量不能再重新定义
var a = 1;
var a = 2 ;
console.log(a) // 输出为2
---------------------------
let a = 1;
let a = 2 ;
console.log(a) // 报错提示a已经被定义过
4、let声明的变量不会进行变量提升
console.log(a); //由于变量提升此时已经被赋值为undefined
var a = 1 ;
console.log(a); //报错由于用let声明的变量没有变量提升 所以此时还找不到变量a
let a = 1 ;
Const
首先用Const定义的变量都具有let的特性 其次const定义的变量还不能被更改,即定义的是一个常量
const abc = 123;
abc = 12;
console.log(abc);//报错常量变量被赋值 Assignment to constant variable.
数组遍历
首当其冲的就是for循环
const arr = [1,2,3,4,5]
for(let i = 0;i<arr.length;i++){
console.log(i+':'+arr[i])
//输出索引 以及对应的值
}
for循环支持contiune 和break 可以让数组遍历停止
const arr = [1,2,3,4,5]
for(let i = 0;i<arr.length;i++){
if(i === 3){
continue
}else{
console.log(i+':'+arr[i])
//跳过索引为3的那项 继续遍历到结束
}
}
-------------------------------
const arr = [1,2,3,4,5]
for(let i = 0;i<arr.length;i++){
if(i === 3){
break
}else{
console.log(i+':'+arr[i])
//遇到索引为3的项 直接结束遍历
}
}
forEach
不支持continue 和break
const arr = [1,2,3,4,5]
arr.forEach(function(item){
console.log(item) //不需要索引直接输出每一项的值
})
every
可以用return true 和return false(默认是设置为return false)来控制数组遍历的过程
const arr = [1,2,3,4,5]
arr.every(function(item){
console.log(item)
//只会输出1 由于默认设置为return false
})
----------------------------
const arr = [1,2,3,4,5]
arr.every(function(item){
console.log(item)
return true
// 由于设置为return true 则会输出数组中的每一项
})
模拟for循环的contiune 和 break
const arr = [1,2,3,4,5]
arr.every(function(item){
if( item === 2){
}else{
console.log(item)
}
return true
// 跳过了item === 2 的情况 相当于continue
})
--------------------------------
const arr = [1,2,3,4,5]
arr.every(function(item){
if( item === 4){
return false
}else{
console.log(item)
}
return true
// 遇到过了item === 4 的情况直接退出循环
})
for ...in (是为对象设计api 不适用于数组)
支持 continue 和 break
const arr= [1,2,3,4,5]
arr.a = 123
for(key in arr){
console.log(key)
} // 输出 0,1,2,3,4,5,a 并不适用于数组
//而且上述代码的key是为字符串
for...of (可以遍历对象和数组以及不是数组也不是对象的自定义的数据结构 可以自定义遍历的方式)
支持 break continue return
const arr= [1,2,3,4,5]
for(item of arr){
console.log(item)
}
---------------------
const arr= [1,2,3,4,5]
for(item of arr){
if( item === 3){
break
}else{
console.log(item) //输出1,2 遇到3就直接退出循环
}
}
----------------------
const arr= [1,2,3,4,5]
for(item of arr){
if( item === 3){
continue
}else{
console.log(item) //输出1,2,4,5跳过值为3的项
}
}
自定义结构后面补充
伪数组
函数中的arguments 、DOM中的NodeList等。将伪数组转换成数组让其可以使用数组的方法
伪数组特点 1、按索引方式存储数据(或者数据存储为空) 2、具有length属性 如下代码
const arrLike = {
0:"a",
1:"b",
2:"c",
length:3
}
function test(num1,num2,num3,num4,num5,num6){
let args = [].slice.call(arguments);
//let args = Array.prototype.slice.call(arguments); 调用数组对象上的slice并给arguments使用
//用call将数组的api用在新的对象上
console.log(args)
}
test(1,2,3,4,5,6); //args 显示为数组类型
DOM中的NodeList同上所述
Array.from()
再ES6中可以直接用Array.from() 将伪数组转换为数组
Array.from() 也可以用于初始化数组
function test(num1,num2,num3,num4,num5,num6){
let args = Array.from(arguments)
console.log(args)
}
test(1,2,3,4,5,6); //args 显示为数组类型
语法:Array.from(arrayLike,mapFn,thisArg)
参数 | 含义 |
---|---|
arrayLike | 必须参数,伪数组 |
mapFn | 可选参数,转换后的数组中的每个元素会执行该回调函数 |
thisArg | 可选参数,执行回调函数后mapFn时this对象 |
function test(num1,num2,num3,num4,num5,num6){
let args = Array.from(arguments,(item)=>{ return item*2})
console.log(args)
}
test(1,2,3,4,5,6); //args 显示为数组类型 并且每项值都乘2
用Array.from()初始化
ES5方法
let arr = Array(6).join(' ').split('').map(function(){return 1})
console.log(arr);
--------------------------------
ES6
let arr = Array.from({length:5},function(){ return 1});
//这里的伪数组前面的数据为空
console.log(arr);
Array.of
let array = Array(5) //生成长度为5的数组
let array = Array(5,6,7) //生成[5,6,7]
let array = [] //字面量创建数组
----------------------------
let array = Array.of(1,2,3,4,5); //生成[1,2,3,4,5]
let array = Array.of(1); //生成[1] 要区别于Array(1)
参数 | 含义 |
---|---|
elementN | (必选参数) 任意个参数,将按顺序成为返回数组中的元素 |
Array.fill
用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引
//初始化数组
let array = Array(5).fill(8);
//在只有一个参数的情况下 后面两个参数的默认值为0和length
console.log(array); //打印一个长度为5各项值为8的数组 [8,8,8,8,8]
---------------------------
let arr = [1,2,3,4]
arr.fill(0,1,2) //打印[1,0,3,4]
//fill有三个参数 第一个为需要添加的值 第二个为起始位置,第三个是终止索引但替换的时候不包括该索引值
//
参数 | 含义 |
---|---|
value | (必填参数) 用来填充数组元素的值 |
start | (可选参数)起始索引,默认值为0 |
end | (可选参数) 终止索引,默认值为this.length |
查找数组中的元素
ES5中用filter (将数组中所有的符合条件的元素都放在一个数组里返回)
let arr = [1,2,3,4,5]
let find = arr.filter(function(item){
return item === 5
})
console.log(find) //返回 数组[5] 若没有返回空数组
--------------------------------
ES6中的find(将数组中第一个的符合条件的元素返回 关注的侧重点不同)
let arr = [1,2,3,4,5]
let find = arr.find(function(item){
return item > 2
})
console.log(find) //返回3
-----------------------------
ES6中的findIndex(将数组中第一个的符合条件的元素的索引值返回)
let arr = [1,2,3,4,5]
let find = arr.findIndex(function(item){
return item > 2
})
console.log(find) //返回2