JavaScript入门

引入

什么是javaScript?

JavaScript是什么?

  • JavaScript是一门语言,其实它既可以做前端也可以做后端

javascript可以用来做什么?

  • 大多数时间在浏览器里做交互式网页
  • 也可以做移动端app、实时联网app、命令行工具 、游戏

JavaScript运行在哪里

  • 最开始被设计成只能运行在浏览器里、所以每个浏览器都有一个JavaScript引擎(火狐SpiderMonkey;Chrome V8)
  • 2009年 Ryan Dahl 将 Chrome V8 开源部分与C++结合 做了Node
  • 所以现在 浏览器或者 Node 都可以作为 运行时环境

简单交互

输出

1、控制台交互,可以直接在控制台写,也可以在script标签写

console.log()

image-20230727084217262

2、弹窗交互

alert("hello")

3、body内输出

document.write("hello")

image-20230727152901835

输入

. 输入语法

prompt("XXX")显示一个对话框,对话框中包含一条文字信息,用来提示用户输入文字

image-20230727153221699

let username = prompt("请输入您的姓名:")

注意:

JavaScript 代码执行顺序:

按HTML文档流顺序执行JavaScript代码

alert() 和 prompt() 它们会跳过页面渲染先被执行

坑: 使用表单、prompt 获取过来的数据默认是字符串类型的

JavaScript 组成

image-20230727150709374

  • JavaScript的语法规范:有很多种,这里学习最常用的 JavaScript ECMAScript

    • 规定了js基础语法核心知识。

      比如:变量、分支语句、循环语句、对象等等

  • Web APIs:

    • DOM 操作文档,比如对页面元素进行移动、大小、添加删除等操作
    • BOM 操作浏览器,比如页面弹窗,检测窗口宽度、存储数据到浏览器等等
  • 权威网站: MDN

搭建JavaScript开发环境

1、下载VSCode 作为 编辑工具

2、下载 Node 作为运行工具

当我们仙剑一个html文件,只输入一个!号,VSCode就会帮我们自动补全代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello World</h1>
</body>
</html>

JavaScript 程序不能独立运行,它需要被嵌入 HTML 中,然后浏览器才能执行 JavaScript 代码。通过 script 标签将 JavaScript 代码引入到 HTML 中.

在vscode中安装 live server

这样右键点击文件,就会从浏览器中加载我们的html文件了

  • 我们可以在 html文件里面的 head标签或者 body标签里面添加 JavaScript脚本(<script>标签)

  • 一般一个好的编程习惯是,将JavaScript 标签放在 body标签的末尾,

    • 1、浏览器解析这个文件是自顶向下的顺序执行的,如果放在head中,如果有很多JavaScript代码,浏览器就会忙于解析JavaScript代码,而不能即使加载页面,用户体验差
    • 2、jsp代码一般需要与许多控件交互,如果需要等许多控件渲染完成才能解析完成,
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello World</h1>
    <script>
        // 在控制台打印 hello hello
        console.log("hello hello")
    </script>
</body>
</html>

image-20230727090552000

其实,我们一般非常希望将JavaScript脚本从页面“剥离出来”

因为 因为 html 页面更多“关注” 静态页面显示的内容,而 JavaScript 更多“关注” 与页面交互时的行为

我们添加一个 相同目录添加一个文件 “XX.js” 将 <script> 标签里面的内容剪切粘贴

在html文件里面引用这个js文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello World</h1>
+    <script src="index.js"> </script>
</body>
</html>

使用Node 运行 JavaScript 代码

在 VScode 里面 用快捷键 ctrl+~ 从vscode中打开终端

image-20230727091457034

JavaScript数据类型

变量与常量

在JavaScript中组要通过三个关键字声明变量和常量,分别是 var、let 和 const

  • var 在JavaScript诞生的时候就有了,但是现在已经很少使用了

    • var是全局作用域的,在一个if条件作用域的内外声明两个同名的变量会导致冲突

    • Ø 可以先使用 在声明 (不合理)

      Ø var 声明过的变量可以重复声明(不合理)

      Ø 比如变量提升、全局变量、没有块级作用域等等

    • var 就是个bug,别迷恋它了,以后声明变量我们统一使用 let

  • let 和 const 都是 ES6 中新加入的 关键字,他们只在时作用域是局部的

    • let 修饰的值可以被修改
    • const 修饰的值不能被修改,但是如果const修饰的变量是数组或者对象时,其内部的元素是可以被改变的
      • const 必须在声明时就初始化数值,否组会报错

JavaScript原生数据类型

主要有 String、Number(js不区分整数和小数)、Boolean、null、undefined

String

  • 用单引号或者双引号修饰
  • const username = 'name'

Number

  • Js定义时不区分小数或者整数
  • let score=98
  • const pi = 3.14

Boolean

  • let flag = true

null

  • let x=null

undefined

  • const y= undefined

  • let z 不指定类型默认 undefined

  • null 和 undefined 区别:

    undefined 表示没有赋值

    null 表示赋值了,但是内容为空,将来有个变量里面存放的是一个对象,但是对象还没创建好,可以先给个null

console.log(typeof XXX)查看变量的数据类型

但是当你用 console.log(typeof x)(上面x被定义为nul类型),打印出来却是object

这是一个历史遗留bug,,,早期设计编程语言时用低位存储变量类型信息,如

  • 000:对象
  • 1:整数
  • 010:浮点数
  • 100:字符串
  • 110:布尔

但有两个类型比较特殊

  • undefined:用 -2^{30} (−2^30)表示。

  • null:对应机器码的 NULL 指针,一般是全零。

有人层提出修复这个bug,但被否决了,现在成为了这门编程语言的feature 😀

字符串

字符串的拼接:

1、加号拼接

2、模板字符串

const username = “Bob”;

const s1=”My name is ${username}”

console.log(s1)

字符串的内置方法

  • 转大写/小写

    str.toUpperCase()

    str.toLowerCase()

  • 截取

    str.substring(0,5) //截取 字符串 索引 0到4

  • 分割

    str.split(‘’)// 返回被分割的字符串数组,当输入为空字符串时,为最小分割

类型转换

隐式转换

+ 号两边只要有一个是字符串,都会把另外一个转成字符串;+号作为正号解析可以转换成数字型

除了+以外的算术运算符 比如 - * / 等都会把数据转成数字类型

显式转换

转换为数字型

1、Number(数据)

转成数字类型

如果字符串内容里有非数字,转换失败时结果为 NaN(Not a Number)即不是一个数字

NaN也是number类型的数据,代表非数字

2、 parseInt(数据)

只保留整数

3、 parseFloat(数据)

可以保留小数

转换为字符形

1、String(数据)

2、变量.toString(进制)

image-20230727155644700

数组

创建数组

  • 构造函数(用的少)

    • const numbers = new Array(1,2,3,4);
  • 直接中括号

    • const hh = ["apples","aranges","pears",10,true]
    • 注意JavaScript数组可以时不同的数据类型

数组增删查改

  • 这里用const申明数组hh可以认为hh的指针不变,只要指针不变,其他关于数组的改变都可以被允许,包括改变数组某个位置的元素,或者新增元素改变了数组的大小

    • hh.push("hh_tail") 末尾加元素, hh.unshift("hh_head")头部加元素

      hh.pop();末尾删去元素,hh.shift() 头部删去元素

    • hh.splice(start,deleteCount), 方法 删除指定元素,以及删除几个元素,deleteCount省略的化默认删到最后

其他

  • Array.isArray(hh)

    hh.indexOf(0)

数组遍历

1、for(let i =0;i<numbers.length();i++)

2、map方法遍历

map 可以处理数据,并且返回新的数组

const arr = ['pink','red','blue']
const newArr = arr.map(function (item,index){
    console.log(item)
    console.log(index)
    return item + '老师'
})
console.log(newArr)

join方法

join() 方法用于把数组中的所有元素转换一个字符串

const arr = ['pink','red','blue']
console.log(arr.join(arr,'')) // 'pinkredblue'

数组元素是通过参数里面指定的分隔符进行分隔的

map+join常用于渲染

渲染模块

(3) 我们使用map方法遍历数组,直接返回 整个tr, 里面包含所有修改后的 tr 标签, 里面更换数据

(4) 但是map方法返回的是一个修改后的数组,怎么办?

我们通过join方法转换为字符串

(5) 把返回的结果, 通过 innerHTML 赋值给 tbody

对象

声明对象,通过大括号声明对象,对象里以键值对(属性 冒号 值)的形式表示属性,属性的值可以是任何类型的变量

const person ={
    firstName : "John",
    lastName : "Deo",
    age : 30,
    hobbies:['music','moive'],
    address:{
        country:"china",
        city:"beijing",
        street:"xitucheng"
    }
}

// 通过new Object 创建
const o = new Object({name:"佩奇"})

可以通过点+属性名的方式获取任何一个属性 ,或者对象[‘属性名’]

person.firstname
person['firstname']
// 第二种方式功能更强大 适用于非正常属性,但必须加引号,否则退化成第一种

可以从或如下方式从对象中“抽取”对应变量名的变量值

const {firstName,lastName}=person;

const{firstName,address:{city}} =person;

console.log(city);

js里面的对象感觉并不像真正的对象,他随时可以添加/删除或者更新属性

如添加/更改属性

person.email='122@gmail.com'

删除对象属性

delete person.email

对象数组和json

const todos = [
    {
        id:1
        text: "清理垃圾"
    }
    {
        id:2
        text: "写代码"
    }
    {
        id:3
        text: "找工作"
    }
]

console.log(todos[1].text)

json是一种数据格式

json有两种格式

  • 对象格式
  • 对象数组格式

严格来说,数组对象以及对象与json还是有去别的:

  • json 属性名(键)必须加引号!

对于JavaScript来说怎么将数组对象/数组转换为json格式(字符串)呢?

const todosJson = JSON.stringify(todos);
console.log(todoJson)

构造函数

function Pig(name,age){
    this.name = name
    this.age=age
}

// 创建对象
const Peiqi = new Pig("佩奇",10)

const date = new Date('2022-4-8')

构造函数在技术上是常规函数。

不过有两个约定:

  1. 它们的命名以大写字母开头。
  2. 它们只能由 “new” 操作符来执行。

说明:

  1. 使用 new 关键字调用函数的行为被称为实例化
  2. 实例化构造函数时没有参数时可以省略 ()
  3. 构造函数内部无需写return,返回值即为新创建的对象
  4. 构造函数内部的 return 返回的值无效,所以不要写return
  5. new Object() new Date() 也是实例化构造函数

实例成员和静态成员

function Pig(name,age){
    // 实例成员 实例函数 定义部分
    this.name = name
    this.age=age
    this.sayHello = function{
        console.log("hello")
        console.log(this) //输出 object
    }
}

// 静态成员 静态函数定义部分
Pig.numsOfLeg=4
Pig.say=function(){
    console.log("嗝~") 
    console.log(this) //输出 Pig(name,age){...}
}

静态成员方法中的 this(如果有) 指向构造函数本身

prototype

对于js来说。每一个实例方法,每一个实例都会创建一个实例方法,按理说实例方法其实应该是公用的,如果每一个实例都创建会极大的浪费内存

用什么来解决呢?

JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象

这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存

我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。 构造函数和原型对象中的this 都指向 实例化的对象

function Star(uname,age){
    this.name= uname;
    this.age = age
}
Star.prototype.sing=fucntion(){
    console.log("唱")
}
const ldh = new Star('刘德华', 18)
const zxy = new Star('张学友', 19)
console.log(ldh.sing === zxy.sing)  // true ,如果直接在构造函数里面的是 false 
constructor(属于 prototype)
function Star(name){
    this.name = name
}
Star.prototype = {
    sing: function() {}
    dance: function() {}
}
console.log(Star.prototype.constructor) //指向Object
function Star(name){
    this.name = name
}
Star.prototype = {
    constructor: Star
    sing: function() {}
    dance: function() {}
}
console.log(Star.prototype.constructor) //指向 Star
__proto__

对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype

原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在

 <img src="https://differencer.oss-cn-beijing.aliyuncs.com/img/image-20230812112647114.png" alt="image-20230812112647114" style="zoom:67%;" />
ldh.__prototype__ === Star.prototype  // true
ldh.__prototype__.constructor == Star

image-20230812113152199

简单记忆:

  • 构造函数 Star相当于 父亲
  • prototype__proto__相当于 兄弟之间的关系?

image-20230812114319393

继承

原型继承
const People = {
    head : 1,
    eyes : 2,
    legs : 2,
    say: function(){}
}
function Man(){}
Man.prototype = People
Man.prototype.constructor = Man
const man1 = new Man()

问题:如果我们给男人添加了一个吸烟的方法,发现女人自动也添加这个方法

原因:男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响

image-20230812172223730

需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法

答案:构造函数

上面改为

// 构造函数
function Man(){}

Man.prototype = new People()
Man.prototype.constructor = Man
Man.prototype.smoke = function(){ console.log("smoke")}

原型链

image-20230812174255321

原型链-查找规则

① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。

② 如果没有就查找它的原型(也就是 proto指向的 prototype 原型对象)

③ 如果还没有就查找原型对象的原型(Object的原型对象)

④ 依此类推一直找到 Object 为止(null)

proto对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

如 Array的 的map 方法,

他其实是 不是 Array构造函数里面的方法,他是 protoype里面的方法

基本数据类型/引用数据类型

简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型

值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型

引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等

堆栈空间分配区别:

1、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;

值类型变量的数据直接存放在变量(栈空间)中

2、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。

引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中

流程控制

if条件语句/ == 和 ===

const x = 10
const y = "10"
const o1={
    num1 : x,
}
const o2 ={
    num1 : y,
}

if(x==y){
    console.log("10==\"10\"")
}
if(x===y){

    console.log("10===\"10\"")
}

if(o1==o2){
    console.log("o1==o2")
}
o2.num1=x;
if(o1==o2){
    console.log("o1==o2")
}
if(o1===o2){
    console.log("o1===\"o2\"")
}

上述语句只会打印 10=="10"

switch语句 (略)

for while

for(let i=0;i<10;i++){
	console.log(i)
}

let j=0
while(j<10){
	console.log(j)
	j++;
}

逻辑中断

function getSun(x,y){
	x = x || 0
    y = y || 0
    console.log(x+y)
}
                     
getSum(1,2)  // 输出3
getSum() // 输出 0
// 起作用类似于 参数默认值

原理,x = x || 0 这一句,x 输入 非0 非 undefined 非 null 等值全作为真来看待,就不执行后面了,如果输入不满足前面的就认为是真,真则不看后面的值了

PS:

  • ‘’ 、0、undefined、null、false、NaN 转换为布尔值后都是false, 其余则为 true
  • 有字符串的加法 “” + 1 ,结果是 “1”
  • 减法 - (像大多数数学运算一样)只能用于数字,它会使空字符串 “” 转换为 0
  • null 经过数字转换之后会变为 0
  • undefined 经过数字转换之后会变为 NaN

image-20230728132937017

image-20230728133000444

运算符 && 与此类似 (&& 、 || 也叫短路与、 短路 或)

函数

普通函数

// 声明
function 函数名(参数列表){
    函数体
    (return 返回值)
}
// 调用
let x = 函数名(参数值列表)

如果参数列表不给值,会怎么样?默认传undefined,如果对undefined进行运算会得到NaN的结果

为了避免不传参报错的情况,可以再定义函数参数时设置默认值(每个参数加等号和值)

匿名函数

匿名函数:将匿名函数赋值给一个变量,并且通过变量名称进行调用 我们将这个称为函数表达式

// 声明时将函数值给一个变量
let yy = function(参数列表){
    
}

// 调用
let y =yy(参数值列表);

立即执行函数

场景介绍: 避免全局变量之间的污染

//方式1
(function (){ console.log(11) })();

//方式2
(function(){console.log(11)}());

// 注意: 多个立即执行函数要用 ; 隔开,要不然会报错

对象

对象函数

之前介绍对象时,只介绍了它通过键值对的方式存储属性,其实它还可以通过键值对(方法名:函数)的方式存储行为

image-20230728134034828

遍历对象(属性)

let obj = {
	uname : 'andy',
    age : 18,
    sex : '男'
}

// 遍历
for(let k in obj){
    console.log(k) // 打印属性名
    console.log(obj[k]) // 打印属性值
}

注意通过增强for 循环获取时,变量为对象的属性名,所以通过中括号获取属性值

内置对象

我们使用的console 以及 document 其实就是内置对象

内置对象-Math

  • Math.random()
    • 随机数函数, 返回一个0 - 1之间,并且包括0不包括1的随机小数 [0, 1)
    • 如何生成5-12的随机数?
    • Math.floor(Math.random()*(7+1))+5
  • Math.ceil() 向上取整
  • Math.floor() 向下取整
  • Math.max()
  • Math.min()
  • Math.pow()
  • Math.abs()