函数
1. 命名函数:(有名字的函数,命名采用动名词结构,动词 + 名词)
实例:
function getName(username) {
return "hello " + username;
}
console.log(getName("小柯"));
2. 匿名函数:没有名字的函数
- 执行方式1: 立即执行:声明 + 执行 2合1,
立即执行函数( IIFE ): 阅后即焚,不会给全局环境带来任何的污染,用来创建临时作用域
实例:(function (username) {
console.log("hello " + username);
})("小柯");
执行方式2: 函数表达式,将匿名函数保存到一个变量中
- 将”函数声明”, 变成”变量声明”, 只不过, 变量的值,是一个函数声明
const getUserName = function (username) {
return "hello" + username;
};
console.log(getUserName("小柯"));
执行方式3: 重点学习,箭头函数 =>
举例:有两个参数的情况
let f1 = function sum(a, b) {
return a + b;
};
console.log(f1(10, 50));
// 使用 箭头函数 来简化匿名函数的声明
// 匿名函数转箭头函数的语法
// 1. 去掉 function ,去掉函数名
// 2. 在参数括号(…) 与 大括号{…} 之间使用 胖箭头 => 连接
// 3.只有一个参数的时候, 参数列表的小括号也可以不要了
// 4.只有一条语句的时候,return和大括号都可以不要了
// 4.只有一条语句的时候,没有参数的情况小括号()必须写上,也可以用”$”或者”_”来代替(特殊情况)
// 6.箭头函数,内部的 this ,是固定的,与它的上下文绑定,不能充当构造函数来创建对象,内部没有 arguments 对象
- 有两个参数的情况简化例如:
f2 = (a, b) => {
return a + b;
};
console.log(f2(10, 50));
- 只有一个参数的情况,例如:
f3 = username => {
return "hello " + username;
};
console.log(f3("小柯"));
- 只有一条语句的时候,例如
// 没有参数的情况小括号必须写上,也可以用”$”或者”_”来代替(特殊情况)f4 = c => c * 10;
console.log(f4(8));
f5 = () => "小柯语录";
console.log(f5());
f6 = _ => "小柯语录2";
console.log(f6());
// ! 使用场景
// 1. 如果函数需要多次调用, 用命名, 函数表达式, 都可以
// 2. 如果代码要求,必须遵循”先声明, 再调用”的规则, 那就必须用”函数表达式”
// 3. 如果只有完成一些特定的,一次性的工作, 不想留下任何痕迹, 用”IIFE”(立即执行函数), 模块
// 4. 如果调用函数时,需要一个函数充当参数,例如:回调, 就可以使用箭头函数来简化 匿名函数的 声明
数据类型
1. 原始类型:也叫简单类型
//基本类型: 一个变量,就存一个值,变量类型完全由这个值来决定的
// * number, string, boolean, undefined, null
// 不可再分, 是构成其它复合类型的基本单元
// 数值类型;
console.log(123456, typeof 123456);
// 字符串类型
console.log("你好", typeof "你好");
//布尔类型
console.log(true, typeof true);
// undefined类型:已声明未赋值变量的默认值
console.log(undefined, typeof undefined);
// 未赋值;
let a;
console.log(a);
// 已赋值
a = 1;
console.log(a);
// 对象类型:null是一个空值。
console.log(null, typeof null);
2. 引用类型
// 引用类型: 类似其它语言中的”复用类型”, 集合类型
// 引用类型的数据,由一个或多个, 相同, 或不同类型的”原始类型”的值构造
// 是一个典型的多值类型,一个变量里面对应的是多个值
// * array, object, function(数组,对象,函数)
// 引用类型, 都是对象, 默认返回 object ,函数除外 function
2.1 数组
// 声明格式:const arr = [数组成员1,数组成员2];
实例1:
const arr = ["笔记本电脑", 99, 9999];
console.log(arr);
// 数组的索引是从0开始递增的正整数, 0, 1, 2
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
console.log(arr[3]);
//超过了就没有值了,越界了
实例2:
// 判断数组类型的正确方法,记牢
console.log(Array.isArray(arr));
// 为了更直观的表达数据之间的关联, 可以将 数字索引 换 有意义 的"字符串",以下举例对象字面量
const arr1 = { name: "笔记本电脑", num: 99, price: 9999 };
console.log(arr1);
const arr2 = { 0: "笔记本电脑", 1: 99, 2: 9999 };
console.log(arr2);
2.2 对象
// 对象 更像一个语义化的数组
// name, num , price叫做属性,类似于变量
实例1:
const obj1 = { name: "笔记本电脑", num: 99, price: 9999 };
console.log(obj1);
//打印单个属性值,就访问那个语义化的属性名称即可,例如下方
console.log(obj1["name"]);
console.log(obj1["num"]);
console.log(obj1["price"]);
// 因为对象的属性名称都是合法的标识符,可以使用点来访问,结果都是一模一样的。例如下方
console.log(obj1.name, obj1.num, obj1.price);
// 当属性名是非常标识符时, 必须使用数组的方式来访问对象的属性,即外面加中括号,里面加双引号包裹,才可以实现正常访问
obj2 = { "my email": "xiaoke@email.cn" };
console.log(obj2["my email"]);
// * 对象最吸引人的,不是数组的语义化封装, 而是对数据操作的封装, 方法(语法与函数是一样的)
// 本质上来说, 对象, 就是变量与函数的封装, 内部, 变量改口叫属性, 函数改口叫方法
// 方法(语法与函数是一样的写在内部)
// total:function(){}
实例2:
obj3 = {
name: "笔记本电脑",
num: 11,
price: 9999,
// 例如做一个数据格式化的输出,使用方法total
total: function () {
let str = obj3.name + " 总计: " + obj3.num * obj3.price + " 元 ";
return str;
},
};
console.log(obj3.total());
//另外的一种写法
obj4 = {
name: "笔记本电脑",
num: 10,
price: 9999,
// 反引号声明的模板字符串, 可以插入变量/表达式, 这叫"插值"
total: function () {
let str = `${obj4.name} 总计 ${obj4.num * obj4.price} 元`;
return str;
},
};
console.log(obj4.total());
obj5 = {
name: "笔记本电脑",
num: 100,
price: 9999,
// 应该是对象内部, 使用 当前对象的一个引用, 这样才独立于外部对象,
//即”obj4“这个改了一个其他的全部都要改太累了,则使用this来进行代替使用,不论现在改成obj5还是其他参数都不影响输出
total: function () {
let str = `${this.name} 总计 ${this.num * this.price} 元`;
// this: 始终与当前对象绑定(执行环境 / 执行上下文 )
// this实际上是 = obj5
return str;
},
};
console.log(obj5.total());
// 判断对象类型的更优雅的方法,记牢
//console.log(obj5 instanceof Object);
// 实际工作中, 而是将数组与对象组合起来一起用
// obj6是一个由三个对象构成的数组,外面是数组里面是三个对象
实例3:
obj6 = [
{ name: "手机", num: 2, price: 5000 },
{ name: "电脑", num: 2, price: 5000 },
{ name: "相机", num: 2, price: 5000 },
];
// 假设这个是购物车,求三个商品的价格总和
let res = obj6.map(item => item.num * item.price).reduce((acc, cur) => acc + cur);
console.log(res);
3. 函数
// 函数是一种数据类型 , 既是函数也是对象
// 判断是否是函数
console.log(typeof function () {});
// 判断是否是对象
console.log(function () {} instanceof Object);
函数是数据类型的好处?
// 可以当成普通值来使用, 例如充当函数的参数,或者函数的返回值
// 这个很重要, 当参数,就是回调函数, 当返回值,可以创建一个闭包
// js中很多高级应用, 都严重依赖这二个功能, 这也是”高阶函数”的基本特征
// 函数是js的一等公民, 就是通过这个体现的(可以当作函数参数,也可以当作函数的返回值)
实例1:
function f7(callback) {
// 参数 callback 是一个函数
console.log(callback());
}
// 调用f1, 匿名函数当成f1的参数
f7(function () {
return "hello 树先生";
});
应用场景2: 函数当成返回值, 这就是闭包
实例2:
function f8() {
let a = 1;
return function () {
//从1 开始就使用a++
return (a = a + 1);
};
}
console.log(f8);
const f = f8();
console.log(f);
console.log(f());
console.log(f());
console.log(f());
console.log(f());
console.log(f());
console.log(f());
console.log(f());
console.log(f());
//* 以上的回调 + 闭包, 都是函数当成"值"来用的经典应用场景
// * 下面是函数当成对象来用
// * 对象有属性和方法, 当然函数也有属性有方法
function xiaoke(a, b) {
return a + b;
}
// 查看函数名
console.log(xiaoke.name);
// 查看函数需要几个参数
console.log(xiaoke.length);
//属性可以添加
xiaoke.email = "840200456@qq.com";
console.log(xiaoke.email);
函数当成对象有啥用呢?
//对象可以被继承,实现代码复用
// 而JS就是基于原型,实现的继承, 而原型,就是在函数上创建一个普通对象而已
// console.log(xiaoke.prototype);查看函数原型,可忽略
// 后面要学到的类class,构造函数, 他们都是基于”函数是对象”这个前提的