专栏简介: 前端从入门到进阶
题目来源: leetcode,牛客,剑指offer.
创作目标: 记录学习JavaEE学习历程
希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长.
学历代表过去,能力代表现在,学习能力代表未来!
目录
1. 初始 JavaScript
1.1 JavaScript 是什么?
1.2 JavaScript 能做的事情
1.3 JavaScript 和 HTML 和 CSS 的关系
1.4 JavaScript 运行过程
1.5 JavaScript 的组成
2. 前置知识
2.1 JavaScript 的书写形式
2.2 输入输出
3. 语法概览
3.1 变量的使用
3.2 理解 动态类型
3.3 基本数据类型
3.4 JS 中的数组
3.5 函数
3.6 函数表达式:
3.7 作用域:
3.8 作用域链:
4. 对象
4.1 使用 字面量 创建对象[常用]
4.2 使用 new Object 创建对象
4.3 使用构造函数创建对象
4.4 理解 new 关键字
4.5 JavaScript对象和Java对象的区别
1. 初始 JavaScript
1.1 JavaScript 是什么?
JavaScript 简称 JS
- 是世界上最流行的编程语言之一
- 是一个脚本语言, 通过解释器运行
- 主要在客户端(浏览器) 上运行, 也可以基于 node.js 在服务器端运行.
1.2 JavaScript 能做的事情
- 网页开发(更复杂的特效和用户交互)
- 网页游戏开发
- 服务器开发(node.js)
- 桌面程序开发(Electron, VSCode 就是这么来的)
1.3 JavaScript 和 HTML 和 CSS 的关系
- HTML: 是网页的结构
- CSS: 网页的表皮
- JavaScript: 网页的行为(魂)
1.4 JavaScript 运行过程
- JS 编写的代码保存在文件中, 也就是储存在硬盘上.
- 双击 .html 文件, 浏览器就会读取文件 , 把文件内容加载到内存中(数据流向:硬盘->内存)
- 浏览器会解析用户编写的代码 , 把代码翻译成二进制的 , 能让计算机识别的指令(解释器的工作)
- 得到的二进制指令会被 CPU 加载并执行.(数据流向: 内存->CPU)
浏览器分为 渲染引擎 和 JS引擎
- 渲染引擎: 解析 HTML+CSS , 俗称"内核"
- JS 引擎: 也就是解释器. 典型的就是 Chrome 内核中的V8
Tips: JS 引擎 会逐行读取 JS 代码内容 , 然后解析成二进制指令, 再执行.
1.5 JavaScript 的组成
- ECMAScripe(简称 ES): JavaScript 语法.
- DOM: 页面文档对象模型, 对页面中的元素进行操作.
- BOM: 浏览器对象模型, 对浏览器窗口进行操作.
仅有 JS 语法, 只能写一些基础的逻辑流程, 但要想完成更复杂的任务, 完成和浏览器以及页面的交互, 那么就需要 DOM API 和 BOM API.
ESCMAScript 是一套"标准", 无论是啥样的 JS 引擎都需要遵守这个标准来实现.
2. 前置知识
第一个程序
<script>
alert("你好!")
</script>
- JavaScript 代码可以嵌入到 HTML 的 script 标签中
2.1 JavaScript 的书写形式
1) 行内式
直接嵌入到 html 元素内部
<input type="button" value="点我一下" onclick="alert('hello')">
2) 内嵌式
写到 script 标签中
<script>
alert("你好!")
</script>
3) 外部式
写到单独的 .js 文件中
alert("hello");
<script src="script.js"></script>
Tips: 这种情况下 script 标签内部不能写代码 , 必须空着.
2.2 输入输出
输入: prompt
弹出一个输入框
//弹出一个输入框
prompt('请输入您的姓名:>')
输出: alert
弹出一个警示对话框, 输出结果
//弹出一个输出框
alert("hello")
输出: console.log
在控制台打印一个日志
//向控制台输出日志
console.log('这时一条日志')
需要打开浏览器的开发者工具(F12)=>Console 标签页, 才能看到结果
Tips:
- console 是 js 中的一个"对象"
- . 表示获取对象中的某个属性或方法, 可直观理解为"的"
- console.log 就可以理解成, 使用"控制台" 对象的"log" 方法
3. 语法概览
3.1 变量的使用
基本用法
创建变量(变量定义/变量声明/变量初始化)
var name = 'zhangsan'
var age = 20;
var 是 JS 中的一个关键字, 表示这是一个变量.
代码示例:
弹框提示用户输入信息, 再弹框显示
var name = prompt('请输入姓名:')
var age = prompt('请输入年龄:')
var score = prompt('请输入分数:')
alert('你的姓名是:' + name)
alert('您的年龄是:' + age)
alert('您的分数是' + score)
也可以将三行内容合并一次输出
var name = prompt('请输入姓名:')
var age = prompt('请输入年龄:')
var score = prompt('请输入分数:')
alert('你的姓名是:' + name + "\n" + '您的年龄是:' + age + "\n" + '您的分数是' + score + "\n");
Tips:
- + 表示字符串拼接, 也就是将两个字符串首尾拼接成一个字符串
- \n 表示换行
var 与 let 的区别:
var 定义变量属于老式写法, let 定义变量属于新式写法, let 的语法规范更符合我们常用的主流语言, 类似于一个变量不能重复定义, 变量的作用域限制等...
var a = 10;
var a = 10;
// let则不允许这种写法
{
var a = 10
}
console.log(a);
//let不允许这种写法
3.2 理解 动态类型
1. JS 的变量类型是程序运行过程中才能确定的(运行到 = 语句才会确定类型)
var a = 10;//数字
var name = '张三'//字符串
2. 随着程序的运行, 变量的类型还可能发生变化.
var a = 10;//数字
a = '张三'//字符串
这一点和 C++ Java...这类静态语言差异较大. 静态语言中, 一个变量在创建时类型就确定了, 不能在程序运行时改变, 如果尝试改变直接编译报错.
3.3 基本数据类型
JS 中内置的几种类型
- number: 数字.(不区分整数和小数)
- boolean: true真, false假
- string: 字符串类型
- undefined: 表示未定义的值
- null: 表示空值
Tips: undefined 和 null 都表示取值非法的情况 , 不过侧重点不同.
- null 表示当前值为空 , 有一个空盒子.
- undefined 表示当前变量未定义 , 连一个空盒子都没有.
3.4 JS 中的数组
let arr = [];
let arr1 = [1,2,3,4,5]
let arr2 = [1,true,'hello',[]]
JS 中, 数组的元素类型不要求统一, 可以是任意类型, 实际上动态语言都是如此.
操作数组元素: 访问下标
let arr = [1,true,'hello',[]]
console.log(arr[0])
console.log(arr[1])
console.log(arr[2])
当我们操作主键发现, 将负数或字符串作为下标, 也能正常运行, 那么就可以得出 JS 的数组并不是一个传统意义上的只能按下标来取元素的数组, 而是一个带有键值对性质的东西
let arr = [1,true,'hello']
arr[-1] = 'world'
arr['我是下标:'] = "haha"
console.log(arr)
JS 中数组的遍历:
let arr = ['张三','李四', '王五', '赵六']
for(let i = 0;i < arr.length;i++){
console.log(arr[i]);
}
for(let i in arr){
//此处 i 是数组下标
console.log(arr[i]);
}
for(let elem of arr){
//elem是数组中元素
console.log(elem);
}
给数组添加元素:
- 1. 通过修改 length 新增.
通过在末尾新增元素 , 新增元素是 undefined.
<script>
let a = [1,2,3,4,5];
a.length = 15;
console.log(a);
</script>
- 2. 通过下标新增
如果下标超过元素赋值范围 , 则会给指定位置插入新元素.
<script>
let a = [];
a[3] = 10;
console.log(a);
</script>
之前空余位置为 undefined.
- 3. 使用 push 进行追加元素
代码示例: 给定一个数组 , 把数组中的偶数放入newArray中.
<script>
let a = [1, 2, 3, 4, 5, 6, 7,8 ,9 ,10];
let newArray = [];
for(let elem of a){
if((elem & 1) == 0){
newArray.push(elem);
}
}
console.log(newArray);
</script>
删除数组中的元素:
splice(startIndex, count, 变长参数);
如果只有前两个参数没有变长参数那么就是删除
let arr = ['张三','李四', '王五', '赵六']
arr.splice(2,1);//相当于删除王五
console.log(arr)
如果三个参数都有, count = 1, 相当于替换元素
let arr = ['张三','李四', '王五', '赵六']
arr.splice(2,1,'haha');//相当于将王五替换
console.log(arr)
如果三个元素都有, count = 0, 相当于添加元素
let arr = ['张三','李四', '王五', '赵六']
arr.splice(2,0,'haha');//相当于将王五替换
console.log(arr)
所以 splice 操作非常灵活, 可以同时做到, 删除, 添加, 修改元素.
3.5 函数
语法格式:
//创建函数/函数声明/函数定义
function 函数名 (形参列表){ //不必写形参类型
函数体
return 返回值//不必写返回值类型
}
//函数调用
函数名(实参列表) //不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
代码示例:
function hello(){
console.log('hello')
}
hello();
function add(x, y){
return x + y;
}
console.log(add(1, 3));
对应 JS 这类动态语言, 不需要''重载''这样的概念, 只需通过一个特殊变量 argument, 就可以拿到所有实参.
function add(){
let result = 0;
for(let elem of arguments){
result += elem;
}
return result;
}
console.log(add(1, 2));
console.log(add(1, 2, 3));
console.log(add(1, 2, 3, 4));
3.6 函数表达式:
let add = function (){
let result = 0;
for(let elem of arguments){
result += elem;
}
return result;
}
console.log(add(1, 2));
console.log(add(1, 2, 3));
console.log(add(1, 2, 3, 4));
console.log(typeof(add))
此时形如 function(){ } 这样的写法定义了一个匿名函数, 然后将这个匿名函数用一个变量来表示, 后面就可以通过这个 add 变量来调用函数了.
JS 中函数是一等公民, 可以用变量来保存, 也可以作为其他函数的参数或返回值.
3.7 作用域:
某个标识符在代码中的有效范围, 在 ES6 标准之前, 作用域主要分为两个:
- 全局作用域: 在整个 script 标签中, 或者单独的 js 文件中生效.
- 局部作用域/函数作用域: 在函数内部生效.
//全局变量
let num = 10;
console.log(num);
function test(){
//局部变量
let num = 20;
console.log(num);
}
3.8 作用域链:
背景:
- 函数可以定义在函数内部.
- 内层函数可以访问外层函数的局部变量.
内部函数可以访问外部函数的变量, 采用的是链式查找的方式. 从内到外依次进行查找.
let num = 1;
function test1(){
let num = 10;
function test2(){
let num = 20;
console.log(num);
}
test2();
}
test1();
//执行结果
20
执行 console.log(num)时, 会先在 test2 的作用域中查找 num, 如果没有找到, 则继续去 test1 中查找. 如果还没有找到, 就去全局作用域中查找.
4. 对象
基本概念:
对象指的是一个具体的事物.
在 JS 中, 字符串, 数值, 数组, 函数都是对象
每个对象中包含若干的属性和方法:
- 属性: 事物的特征.
- 方法: 事物的行为.
eg: 你有一个朋友.
她的身高, 体重, 三围这些都是属性.
她的唱, 跳, rap 都是方法.
JavaScript 的对象和 Java 的对象概念上基本一致, 只是具体的语法表达形式差别较大.
4.1 使用 字面量 创建对象[常用]
使用 {} 创建对象.
let a = {};//创建一个空的对象
let student = {
name:'张三',
height:175,
weight:170,
sayhello: function(){
console.log('hello everyone');
}
};
- 使用 {} 创建对象.
- 属性和方法使用键值对的方式来组织.
- 键值对之间使用 , 分割. 最后一个属性后面的 , 可有可无.
- 键和值之间使用 : 分割.
- 方法的值是一个匿名函数.
使用对象的方法和属性:
// 1. 使用 . 成员访问运算符来访问属性 '.' 可以理解为"的"
console.log(student.name);
// 2. 使用 [] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法
student.sayhello();
4.2 使用 new Object 创建对象
let student = new Object();//和创建数组类似
student.name = '张三';
student.height = 175;
student['weight'] = 170;
student.sayHello = function(){
console.log('hello');
}
Tips: 使用 {} 创建的对象也可以使用 student.name = '张三', 这样的方式来新增属性.
4.3 使用构造函数创建对象
之前创建对象的方式只能创建一个对象, 而使用构造函数可以很方便的创建多个对象.
基本语法:
function 构造函数名 (形参){
this.属性 = 值;
this.方法 = function..
}
let obj = new 构造函数名(实参);
Tips:
- 在构造函数内部使用 this 关键字来表示当前正在构建的对象.(this 相当于"我")
- 构造函数无需 return.
- 创建对象时必须使用 new 关键字.
代码示例:
使用构造函数创建 猫咪 对象
使用构造函数可以把相同的属性和方法创建提取出来, 简化开发过程.
function Cat(name, type, sound){
this.name = name;
this.type = type;
this.miao = function(){
console.log(sound);
}
}
let buo = new Cat('咪咪', '布偶猫', '哈海害');
let gudu = new Cat('咕嘟', '中华田园猫', '喵呜');
let ciqiu = new Cat('刺球', '金渐层', '咕噜噜');
4.4 理解 new 关键字
new 关键字的执行过程:
- 1. 先在内存中创建一个空的对象.
- 2. this 指向刚才的空对象(将上一步的对象作为 this 的上下文)
- 3. 执行构造函数的代码, 给对象创建属性和方法.
- 4. 返回这个对象(构造函数本身不需要 return, 由 new 代劳了)
4.5 JavaScript对象和Java对象的区别
1) JavaScript 没有''类''的概念
对象本质上就是"属性" + "方法"
类相当于把一些具有共性的对象的属性和方法单独提取出来, 本质上是用户自定义的类型.
在 JavaScript 中的"构造函数"也能起到类似的效果.
即使不使用 构造函数 , 也可以通过 {} 的方式指定出一些对象.
2) JavaScript 对象不区分 "属性" 和 "方法"
JavaScript 中函数是"一等公民", 和普通变量一样, 存储了函数的变量能够通过() ;来进行调用执行.
3) JavaScript 对象没有访问控制机制, 对象中的属性可以随意被外界访问.
4) JavaScript 对象没有"继承"
继承本质上就是 "让两个对象建立关联", 或者说让一个对象能够重用另一个对象的属性/方法.
JavaScript 中使用 "原型" 机制实现类似的效果.
例如: 创建一个 cat 对象和 dog 对象, 让这两个对象都能使用 animal对象中的 eat 方法.
通过 _proto_ 属性来建立这种关联关系(proto 翻译作: "原型")
let dog = {
name: 'dog',
_proto_: animal
};
let cat = {
name:'cat',
_proto_:animal
};
dog.eat();
cat.eat();
当 eat 方法被调用时, 先在自己的方法列表中寻找, 如果找不到就去原型的方法中找, 如果还找不到就去原型的原型中找....最后在 Object 中还找不到, 那就是未定义.
5) JavaScript 没有"多态"
多态的本质在于 程序员 不必关注具体的类型, 就能使用其中某个方法.
C++/Java 等静态类型的语言对应类型的约束和效验比较严格. 因此通过子类继承父类, 并重写父类的方法的方式来实现多态的效果.
但 JavaScript 中本身就支持动态类型, 程序员在使用某个方法时, 也不需要对对象的类型作出明确区分, 因此无需再语法层面上支持多态.
function add(list ,s){
list.add(s);
}
add 对 list 这个参数本身就没有任何限制, 只需要 list 这个对象有 add 方法即可. 不必像 Java 那样先继承再重写.