函数:
1. 使用arguments对象可以获取传入的每个参数的值
function f1() {
//获取的是函数在调用的时候,传入了几个参数
console.log(arguments.length);
//使用arguments对象可以获取传入的每个参数的值
console.log(arguments);
}
//
f1(10,20,30,40,100,200);//调用
2. 函数定义:
*函数声明
function f1(){ }
*函数表达式:
var f1=function (){ };
3. 函数的自调用:声明的同时,直接调用
(function(){console.log("嘎嘎")})();
4. 函数可以作为参数使用,我们说这个参数(函数)可以叫回调函数
function person(fn) {
console.log("胡八一说:");
fn();//fn此时应该是一个函数
}
function SayHi() {
console.log("你好啊胖子");
}
person(SayHi);
5. 函数是可以作为返回值使用的
function f1() {
console.log("这是函数1");
return function () {
console.log("这是函数2");
};
}
var ff=f1();//这是函数1
console.log(ff);//function() {console.log("这是函数2");}
ff();//这是函数2
6. 作用域
1.1 全局作用域
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
1.2 局部作用域
作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
1.3 JS没有块级作用域(在ES6之前)
-
块作用域由 { } 括起来,包括for循环、while循环、if语句等
-
在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用,如下面的Java代码:
ES6开始有了块级作用域:
for(var i=0;i<5;i++){ var number=20; const number2=20; } console.log(number);//20 console.log(number2);//会报错 number is not defined
以上代码会报错,是因为代码中 { } 即一块作用域,其中声明的变量 number,在 “{ }” 之外不能使用;
7.变量的作用域
在JavaScript中,根据作用域的不同,变量可以分为两种:
- 全局变量
- 局部变量
2.1 全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
- 全局变量在代码的任何位置都可以使用
- 在全局作用域下 var 声明的变量 是全局变量
- 特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
2.2 局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
- 局部变量只能在该函数内部使用
- 在函数内部 var 声明的变量是局部变量
- 函数的形参实际上就是局部变量
2.3 全局变量和局部变量的区别
- 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
8. 作用域链
一般情况下,变量取值到 创建 这个变量 的函数所处作用域中取值。但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
案例分析1:
function f1() {
var num = 123;
function f2() {
console.log( num );
}
f2();
}
var num = 456;
f1();//123
案例分析2:
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //4
console.log(b); //22
}
}
}
fn1();
9. 静态作用域和动态作用域
- 静态作用域指的是一段代码,在它执行之前就已经确定了它的作用域,简单来说就是在执行之前就确定了它可以应用哪些地方的作用域(变量)。 JS属于这种
- 动态作用域–函数的作用域是在函数调用的时候才决定的
JavaScript采用的是词法作用域也叫静态作用域;
function f1(){
alert(x);
}
function f2(){
var x = 100;
f1();
}
f2()
function f1(){
var x = 100;
function f2(){
alert(x);
}
f2();
}
f1();
代码一会报错:x is not defined
;代码二:100;
代码一在函数f2里面调用函数f1,输出里面的值x,此时不要看f1在哪里被调用,而是看f1在哪里生成的,f1是全局作用域生成的,查找不到x就报错了;
代码二在函数f1里面调用函数f2,输出里面的值x,此时f2是在函数f1里面生成的,所以从f1的作用域查找x,得到100
可以借鉴JS作用域&作用域链
10. 预解析
就是在解析代码之前,做两件事:
- 变量预解析
把变量的声明提前到当前作用域的最上面,不提升赋值
var name = "张三";
function f1(){
var name = "abc";
return function(){
console.log(name);
console.log(age);
}
var age = 18;
}
var fn = f1();
fn();
//abc
//undefined
执行f1函数,得到的结果是return的返回值,复制给fn,接下来执行fn,name在当前作用域没有,就找创建时所在的作用域,也就是在f1里,获得name=“abc”,同理age会变量预解析,单独提升声明“var
age”,得到undefined
- 函数也会被提前—提前到当前所在的作用域的最上面,不提升调用
- 函数表达式 var fn=function fn(){},只提升var fn
- 函数声明方式 function fn(){}; 提升整个函数体
function f1() {
console.log(num);//undefined
var num=10;
}
f1();
console.log(num);//num is not defined
var num提升到f1里面的最上面,但是不会出去,所以外面获取num是会报错的
3.先提升var,再提升function
f1();//调用
var num=20;//这个变量的声明会提升到变量使用之前
function f1() {
console.log(num);
//var num=10;
}
会变成:
var num;
function f1(){console.log(num)}
f1();//undefined 这里才开始调用
num=20;
预解析例子2:
console.log(a);
function a(){
console.log('aaaa');}
var a = 1;
console.log(a);
var a;
function a(){
console.log('aaaa');
}
console.log(a);//function a(){console.log('aaa')}
a = 1;
console.log(a);//1
4.预解析会分段(在多个script标签中函数重名,预解析的时候都不会冲突)
<script>
function f1() { console.log("哈哈");}
f1();//哈哈
</script>
<script>
f1();//呵呵
function f1() { console.log("呵呵");}
</script>
对象:
var arr = [‘张三疯’, ‘男', 128,154];
缺点:数据只能通过索引值访问,而当数据量庞大时,不可能做到记忆所有数据的索引值,崩溃。
解决:对象用属性名字替代索引,爽
var obj = {
"name":"张三疯",
"sex":"男",
"age":128,
"height":154
}
创建对象的三种方式
1. 使用对象字面量创建对象
var star = {
name : 'pink',
sayHi : function(){
alert('大家好啊~');
}
};
2. 利用 new Object 创建对象
var andy = new Obect();
andy.name = 'pink';
andy.sayHi = function(){
alert('大家好啊~');
}
3. 利用构造函数创建对象
1、普通函数和构造函数的区别;名字是不是大写(构造函数首字母是大写);
2、区分下系统自带的构造函数创建对象new Object();
我们用自定义构造函数创建对象:先自定义一个构造函数:
function Person(name,age) {
this.name=name;
this.age=age;
this.sayHi=function () {
console.log("我叫:"+this.name+",年龄是:"+this.age);
};
}
接下来创建对象:
var obj=new Person("小明",10);
console.log(obj.name);
console.log(obj.age);
obj.sayHi();
3.1自定义构造函数创建对象做了几件事
- 在内存中开辟(内存本来就有空间,只是申请了一块空闲的空间)空间,存储创建的新的对象(看成做了new Object( )的事)
- 把this设置为当前的对象
- 设置对象的属性和方法的值
- 把this这个对象返回(看成做了return的事)
遍历对象
for…in 语句用于对数组或者对象的属性进行循环操作。
其语法如下:
for (var k in obj) {
console.log(k); // 这里的 k 是属性名
console.log(obj[k]); // 这里的 obj[k] 是属性值
}
数组
1. 创建
// 1. 利用new 创建数组
var arr = new Array(); // 创建了一个空的数组
// 2. 利用数组字面量创建数组 []
var arr = []; // 创建了一个空的数组
2. 遍历
var arr = ['red', 'green', 'blue'];
for (var i = 0; i < 3; i++) {
console.log(arr[i]);
}
3.检测是否为数组
-
instanceof 运算符
-
instanceof 可以判断一个对象是否是某个构造函数的实例
var arr = [1, 23]; var obj = {}; console.log(arr instanceof Array); // true console.log(obj instanceof Array); // false
-
-
Array.isArray()
-
Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
var arr = [1, 23]; var obj = {}; console.log(Array.isArray(arr)); // true console.log(Array.isArray(obj)); // false
-
4. 新增数组长度
- 新增数组元素 修改length长度
var arr = ['red', 'green', 'blue'];
console.log(arr.length);//3
arr.length = 5; // 把我们数组的长度修改为了 5 里面应该有5个元素
console.log(arr);//["red", "green", "blue"]
console.log(arr[3]); // undefined
console.log(arr[4]); // undefined
- 新增数组元素 修改索引号 追加数组元素
var arr1 = ['red', 'green', 'blue'];
arr1[3] = 'pink';
console.log(arr1);//["red", "green", "blue", "pink"]
arr1[0] = 'yellow'; // 这里是替换原来的数组元素
console.log(arr1);//["yellow", "green", "blue", "pink"]
arr1 = '数组';
console.log(arr1); //数组 不要直接给 数组名赋值 否则里面的数组元素都没有了
3.练习:将数组大于10 的元素选出来,放入新数组
// 方法1
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
// 新数组索引号应该从0开始 依次递增
newArr[j] = arr[i];
j++;
}
}
console.log(newArr);
// 方法2
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
// 刚开始 newArr.length 就是 0
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
// 每次加在新数组最后一位
newArr[newArr.length] = arr[i];
}
}
console.log(newArr);
4.练习:去重,将数组中的 0 去掉后,形成一个不包含 0 的新数组
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] != 0) {
newArr[newArr.length] = arr[i];
}
}
console.log(newArr);
5.练习:翻转
方法一:
var arr = ['red', 'green', 'blue', 'pink', 'purple'];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
// newArr 是接收方,arr 是输送方
newArr[i] = arr[arr.length - 1- i];
}
console.log(newArr);
方法二:
//先倒序原数组,再依次存入
var arr = ['red', 'green', 'blue', 'pink', 'purple', 'hotpink'];
var newArr = [];
for (var i = arr.length - 1; i >= 0; i--) {
newArr[newArr.length] = arr[i]
}
console.log(newArr);
6.练习:排序,在线动画演示排序算法过程工具
冒泡排序
var arr = [4, 1, 2, 3, 5];
for (var i = 0; i <= arr.length - 1; i++) { // 外层循环管趟数
for (var j = 0; j <= arr.length - 1-i; j++) { // 里面的循环管 每一趟的交换次数-i
// 内部交换2个变量的值 前一个和后面一个数组元素相比较
if (arr[j] < arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log(arr);