JavaScript介绍
JavaScript是解释型语言,是在运行时进行及时解释,并立即执行,像Java、C高级语言都是编译型语言,在代码执行之前进行编译,生成中间代码文件
JavaScript同时也是基于对象的语言
对于面向对象与面向过程的说法,我举个例子:把大象装冰箱分为几步?
分为三步,打开冰箱门 放入大象 然后关上冰箱门,这就是面向过程的思想,它考虑的是实现的步骤或者过程
首先我们把大象当做一个对象,冰箱当做一个对象,当大象的体积属性小于冰箱的体积属性才能放进去,然后考虑大象如何进入冰箱,是自己进去还是冰箱拉它进去,还会有人把大象放进去,而这个人也就是隐藏对象...这就是面向对象的思想,把单个独立的都看做是一个对象,然后分析这些对象的属性 行为等等
浏览器执行 JS
浏览器分成两部分:渲染引擎和 JS 引擎
-
渲染引擎:用来解析HTML与CSs,俗称内核,比如 chrome浏览器的 blink,老版本的 webkit
-
JS引擎:也称为JS解释器。用来读取网页中的 javaScript代码,对其处理后运行,比如 chrome浏览器的V8
JS预解析
JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行
-
预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。
-
代码执行: 从上到下执行JS语句。
预解析有变量预解析与函数预解析,也叫做变量、函数提升:
-
变量预解析,声明会被提升到当前作用域的最上面,变量的赋值不会提升
-
函数的声明会被提升到当前作用域的最上面,但是不会调用函数
for...in 语句用于对数组或者对象的属性进行循环操作
for (变量 in 对象名字) {
// 在此执行代码
}
arguments【伪数组】的使用
当不确定有多少个参数传递的时候,可以用 arguments 来获取,具有 length 属性
fn(2,4);
fn(2,4,6);
fn(2,4,6,8);
function fn(a,b,c) {
console.log(arguments); //获取具体的实际参数
console.log(fn.length); //获取形参的个数
console.log(arguments.length); //获取实参的个数
}
之所以说arguments是伪数组,是因为:arguments可以修改元素,但不能改变数组的长短
fn(2,4);
fn(2,4,6);
fn(2,4,6,8);
function fn(a,b) {
arguments[0] = 99; //将实参的第一个数改为99
arguments.push(8); //此方法不通过,因为无法增加元素
}
伪数组转真数组
var op = {
0:"admin",
1:18,
length:2
}
//ES6提供了一种方式,专门用来伪转真
var arr = Array.from(op)
解释下什么是变量声明提升
JS引擎在运行一份代码的时候,会按照下面的步骤进行工作:
-
首先,对代码进行预解析,并获取声明的所有变量
-
然后,将这些变量的声明语句统一放到代码的最前面
-
最后,开始一行一行运行代码
代码演示:
//转变前
console.log(a)
var a = 1
function b() {
console.log(a)
}
b() // 1
上⾯这段代码的实际执⾏顺序为:
-
JS引擎将 var a = 1 分解为两个部分:变量声明语句 var a = undefined 和变量赋值语句 a = 1
-
JS引擎将 var a = undefined 放到代码的最前面,而 a = 1 保留在原地
//转变后
var a = undefined
console.log(a) // undefined
a = 1
function b() {
console.log(a)
}
b() // 1
JS 的参数是以什么方式进行传递的
基本类型:是值传递!
复杂类型: 传递的是地址! (变量中存的就是地址)
JavaScript垃圾回收
JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。
垃圾回收算法
引用计数,IE采用的引用计数算法, 定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。如果没有任何变量指向它了,说明该对象已经不再需要了。但它却存在一个致命的问题:循环引用。如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄露。
function cycle() {
let o1 = {}
let o2 = {}
o1.a = o2
o2.a = o1
return "Cycle reference!"
}
cycle()
标记清除,现代浏览器通用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的
什么是闭包?
通俗一点的解释是:内层函数, 引用外层函数上的变量, 就可以形成闭包
闭包的主要作用:闭包最大的作用就是用来 **变量私有**
//变量 `name` 只能通过 Person 的实例方法进行访问,外部不能直接通过实例进行访问,形成了一个私有变量
function Person() {
// 以 let 声明一个局部变量,而不是 this.name
// this.name = 'zs' => p.name
let name = 'hm_programmer' // 数据私有
this.getName = function(){
return name
}
this.setName = function(value){
name = value
}
}
// new:
// 1. 创建一个新的对象
// 2. 让构造函数的this指向这个新对象
// 3. 执行构造函数
// 4. 返回实例
const p = new Person()
console.log(p.getName()) // hm_programmer
p.setName('Tom')
console.log(p.getName()) // Tom
p.name // 访问不到 name 变量:undefined
JavaScript中数据类型的隐式转换规则
在if语句、逻辑语句、数学运算逻辑、== 等情况下都可能出现隐式类型转换
![](https://i-blog.csdnimg.cn/blog_migrate/e946ed7e5f29970e019f0df4457387c6.png)
谈谈你对原型链的理解
**原型对象**
在 JavaScript 中,除去一部分内建函数,绝大多数的函数都会包含有一个叫做 `prototype` 的属性,指向原型对象,基于构造函数创建出来的实例, 都可以共享访问原型对象的属性。例如我们的 `hasOwnProperty`, `toString` ⽅法等其实是 Obejct 原型对象的方法,它可以被任何对象当做⾃⼰的⽅法来使⽤。
let person = {
name: "Tom",
age: 18,
job: "student"
}
//`hasOwnProperty` 用于判断, 某个属性, 是不是自己的
console.log(person.hasOwnProperty("name")) // true
console.log(person.hasOwnProperty("hasOwnProperty")) // false
console.log(Object.prototype.hasOwnProperty("hasOwnProperty")) // true
**原型链**
在 JavaScript 中,每个对象中都有一个 `__proto__` 属性,这个属性指向了当前对象的构造函数的原型。对象可以通过自身的 `__proto__`属性与它的构造函数的原型对象连接起来,而因为它的原型对象也有 `__proto__`,因此这样就串联形成一个链式结构,也就是我们称为的原型链。
**构造函数, 原型对象, 实例的三角关系图**
![](https://i-blog.csdnimg.cn/blog_migrate/4ae9e308f0c27483b45ebd930654d55d.png)
谈谈对于继承的理解
代码层面的继承: 继承一些属性和方法
首先要了解静态属性与静态方法 实例属性与实例方法
**es5继承 - 原型继承**
// 1. 定义Person构造函数
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function () {
console.log('人类会说话')
}
// 2. 定义Student构造函数
function Student (name, age, className) {
this.name = name
this.age = age
this.className = className
}
// 3. 原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
// 语法: 子构造函数.prototype = new 父构造函数()
Student.prototype = new Person()
Student.prototype.study = function() {
console.log('学生在学习')
}
let stu = new Student('张三', 18, '80期')
stu.say() //人类会说话
console.log(stu)
**es5继承 - 组合继承**
组合继承有时候也叫伪经典继承,指的是将原型链 和 借用构造函数 call 技术组合到一块,从而发挥二者之长的一种继承模式,其背后的思路:
-
是使用原型链实现对原型属性和方法的继承 (主要是方法),
-
而通过借用构造函数来实现对实例属性构造的继承
// 1. 定义Person构造函数
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function () {
console.log('人类会说话')
}
// 2. 定义Student构造函数
function Student (name, age, className) {
Person.call(this, name, age) // 实现构造属性的继承
this.className = className
}
// 3. 原型继承: 利用原型链, 继承于父级构造函数, 继承原型上的方法
// 语法: 子构造函数.prototype = new 父构造函数()
Student.prototype = new Person()
Student.prototype.study = function() {
console.log('学生在学习')
}
let stu = new Student('张三', 18, '80期')
stu.say()
console.log(stu)
// 方法通过 原型继承
// 属性通过 父构造函数的.call(this, name, age)
**es6 - class 实现继承 extends**
es6通过static来声明静态方法
// 继承关键字 => extends
class Person {
constructor(name, age) {
this.name = name
this.age = age
this._sex = -1
}
get gSex(){
if(this._sex === 1){
return '男'
}else if(this._sex === 0){
return '女'
}else{
return 'error'
}
}
set sSex(val){
if(val === 0 || val === 1){
this._sex = val
}
}
jump() {
console.log('会跳')
}
}
let text = new Person('ac',21)
//通过属性的方式设置与获取
text.sSex = 0
console.log(text.gSex)
class Teacher extends Person {
constructor (name, age, lesson) {
super(name, age) // extends 中, 必须调用 super(), 会触发执行父类的构造函数
this.lesson = lesson
console.log('构造函数执行了')
}
sayHello () {
console.log('会打招呼')
}
}
let teacher1 = new Teacher('zs', 18, '体育')
//继承的子类也可以使用
teacher1.sSex = 0
console.log(teacher1.gSex)
判断是否是数组
使用 `toString` 方法
function isArray(arg) {
return Object.prototype.toString.call(arg) === '[object Array]'
}
let arr = [1,2,3]
isArray(arr) // true
使用 ES6 新增的 `Array.isArray` 方法
let arr = [1,2,3]
Array.isArray(arr) // true
谈谈你对this的理解
-
`this` 是一个在运行时才进行绑定的引用,在不同的情况下它可能会被绑定不同的对象
**默认绑定**
//默认情况下,`this` 会被绑定到全局对象上,比如在浏览器环境中就为`window`对象,在node.js环境下为`global`对象
message = "Hello";
function test () {
console.log(this.message);
}
test() // "Hello"
**隐式绑定**
//如果函数的调用是从对象上发起时,则该函数中的 `this` 会被自动隐式绑定为对象
function test() {
console.log(this.message);
}
let obj = {
message: "hello,world",
test: test
}
obj.test() // "hello,world"
**显式绑定**(又叫做硬绑定) (上下文调用模式, 想让this指向谁, this就指向谁)
-
硬绑定 => call apply bind
function test() {
console.log(this.message);
}
let obj1 = {
message: "你好世界123"
}
let obj2 = {
message: "你好世界456"
}
test.bind(obj1)() // "你好世界123"
test.bind(obj2)() // "你好世界456"
**new 绑定 (构造函数模式)**
-
当使用 `new` 调用构造函数时,会创建一个新的对象并将该对象绑定到构造函数的 `this` 上
function Greeting(message) {
this.message = message;
}
var obj = new Greeting("hello,world")
obj.message // "hello,world"
**测试**
let obj = {
a: {
fn: function () {
console.log(this)
},
b: 10
}
}
obj.a.fn()
let temp = obj.a.fn;
temp()
//=======================================
function Person(theName, theAge){
this.name = theName
this.age = theAge
}
Person.prototype.sayHello = function(){ // 定义函数
console.log(this)
}
let per = new Person("小黑", 18)
per.sayHello()
箭头函数中的this指向什么
箭头函数不同于传统函数,它其实没有属于⾃⼰的 `this`,它所谓的 `this` 是, 捕获其外层 上下⽂的 `this` 值作为⾃⼰的 `this` 值。并且由于箭头函数没有属于⾃⼰的 `this` ,它是不能被 `new` 调⽤的
// 转换前的 ES6 代码
const obj = {
test() {
return () => {
console.log(this === obj)
}
}
}
// 转换后的 ES5 代码
var obj = {
test: function getArrow() {
var that = this
return function () {
console.log(that === obj)
}
}
}
Promise 的静态方法
promise的三个状态: pending(默认) fulfilled(成功) rejected(失败)
-
resolve函数被执行时, 会将promise的状态从 pending 改成 fulfilled 成功
-
reject函数被执行时, 会将promise的状态从pending 改成 rejected 失败
**Promise.all([promise1, promise2, promise3])**
-
等待原则, 是在所有promise都完成后执行, 可以用于处理一些`并发的任务
Promise.all([promise1, promise2, promise3]).then((values) => {
// values 是一个数组, 会收集前面promise的结果 values[0] => promise1的成功的结果
})
宏任务 微任务 是什么
宏任务: 当执行完所有同步代码后,JavaScript 引擎会先执行当前宏任务队列中最先进入队列的任务,然后执行剩余的宏任务
-
setTimeout/setInterval 等定时器任务
-
DOM 操作(addEventListener、setTimeout、setInterval等)
-
事件监听(click、load、error、readystatechange 等)
微任务: 当一个宏任务执行完成后,JavaScript 引擎会按照顺序执行所有微任务队列中的任务,直到队列为空,并且在执行完所有微任务后才会执行下一个宏任务
-
Promise 的 then 方法
-
async/await 函数
执行顺序:
-
先执行当前宏任务里的同步代码
-
执行所有属于当前宏任务的微任务
-
检查是否需要更新渲染(通常是浏览器完成渲染)
-
然后再执行下一个宏任务(从宏任务队列中取出)
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
console.log(3)
//1、3、2
![](https://i-blog.csdnimg.cn/blog_migrate/a8e24ccd362a122ab161473ae0217b9c.png)
**事件循环队列 eventLoop**
![](https://i-blog.csdnimg.cn/blog_migrate/353a166dcf08acf05a77e45f18ac5d4a.png)
//例题1:
console.log(1)
setTimeout(function() {
console.log(2) // 宏任务
}, 0)
const p = new Promise((resolve, reject) => {
resolve(1000)
})
p.then(data => {
console.log(data) // 微任务
})
console.log(3)
// 1 3 1000 2
![](https://i-blog.csdnimg.cn/blog_migrate/63388e04f2f269f74e99cd7bf80d92fd.png)
//例题2:
async function fn () {
console.log(111)
}
fn()
console.log(222)
//111 222
//例题3:
async function fn () {
const res = await 2
console.log(res)
}
fn()
console.log(222)
//222 2
//例题4:
async function fn () {
console.log('嘿嘿')
const res = await fn2()
console.log(res) // 微任务
}
async function fn2 () {
console.log('gaga')
}
fn()
console.log(222)
//嘿嘿 gaga 222
总结:async 函数只有从 await 往下才是异步的开始
![](https://i-blog.csdnimg.cn/blog_migrate/020b515b09b3e3afe6d91f0ba16c9de6.png)
async/await是什么
-
`async` 关键字用于声明⼀个异步函数、`async` 会⾃动将常规函数转换成 Promise,返回值也是⼀个 Promise 对象
-
`await` 只能与 Promise ⼀起使⽤、 `await` 只能在 `async` 函数内部使⽤
相较于 Promise,async/await有何优势
-
同步化代码的阅读体验(Promise 虽然摆脱了回调地狱,但 then 链式调⽤的阅读负担还是存在的)
-
和同步代码更一致的错误处理方式( async/await 可以⽤成熟的 try/catch 做处理,比 Promise 的错误捕获更简洁直观)
深拷贝 浅拷贝
引用类型, 进行赋值时, 赋值的是地址
**浅拷贝**
let obj = {
name: 'zs',
age: 18
}
let obj2 = {
...obj
}
**深拷贝**
let obj = {
name: 'zs',
age: 18,
car: {
brand: '宝马',
price: 100
}
}
//json.stringify()将对象、数组转换成字符串;json.parse()将字符串转成json对象
let obj2 = JSON.parse(JSON.stringify(obj))
console.log(obj2)
HTTP协议
**HTTP有哪些⽅法**
-
HTTP 1.0 标准中,定义了3种请求⽅法:GET、POST、HEAD
-
HTTP 1.1 标准中,新增了请求⽅法:PUT、PATCH、DELETE、OPTIONS、TRACE、CONNECT
**各个HTTP方法的具体作用是什么**
方法 | 功能 |
GET | 通常⽤于请求服务器发送某些资源 |
POST | 发送数据给服务器 |
DELETE | ⽤于删除指定的资源 |
OPTIONS | ⽤于获取⽬的资源所⽀持的通信选项 (跨域请求前, 预检请求, 判断目标是否安全) |
PATCH | ⽤于对资源进⾏部分修改 |
-
GET/DELETE 参数是在地址栏中传递的
-
PUT/PATCH/POST 参数是在请求体传递的
**GET方法和POST方法有何区别**
GET方法 | POST方法 | |
数据传输⽅式 | 通过URL传输数据 (地址栏拼接参数) | 通过请求体传输 |
数据类型 | 只允许 ASCII 字符 | ⽆限制 |
GET⽆害 | 刷新、后退等浏览器操作是⽆害的 | 可能会引起重复提交表单 |
**HTTP请求报文是什么样的**
HTTP 请求报⽂的组成:
-
请求⾏:包含了请求⽅法、URL、HTTP 协议版本,它们之间⽤空格进行分隔
-
请求头、(空⾏):请求头由键值对组成,每⾏⼀对,键值之间⽤英⽂冒号`:`进行分隔
-
请求体:放置请求方法所需要携带的数据
![](https://i-blog.csdnimg.cn/blog_migrate/f95cf5f4758705cfb8ffbb53360bcb0a.png)
**HTTP响应报文是什么样的**
HTTP 响应报⽂的组成:
-
响应⾏:响应行由协议版本、状态码、状态码的原因短语3个内容组成,中间以空格分隔
-
响应头:响应头由键值对组成,每⾏⼀对,键值之间⽤英⽂冒号`:`进行分隔
-
响应体:服务器发送过来的数据
![](https://i-blog.csdnimg.cn/blog_migrate/5759bd66694b56c3326c6269596c5654.png)
**常见HTTP状态码有哪些**
成功(2XX):
200 | 表示从客户端发来的请求在服务器端被正确处理 |
重定向(3XX)
301 | 久性重定向,表示资源已被分配了新的 URL;比如,我们访问 **http**://www.baidu.com 会跳转到 **https**://www.baidu.com |
302 | 临时性重定向,表示资源临时被分配了新的 URL |
304 | 自从上次请求后,请求的网页内容未修改过。服务器返回此响应时,不会返回网页内容。(协商缓存) |
客户端错误(4XX)
400 | 请求报⽂存在语法错误(传参格式不正确) |
404 | 表示在服务器上没有找到请求的资源 |
401 | 权限认证未通过(没有权限) |
服务端错误(5XX)
**HTTP的keep-alive是什么作用**
作用:使客户端到服务器端的连接**持续有效**(长连接),当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接
早期 HTTP/1.0 在每次请求的时候,都要创建⼀个新的连接,⽽创建连接的过程需要消耗资源和时间,
为了减少资源消耗、缩短响应时间,就需要复⽤已有连接。
在后来的 HTTP/1.0 以及 HTTP/1.1 中引⼊了复⽤连接的机制,也就是在请求头中加⼊Connection: keep-alive,
以此告诉对⽅这个请求响应完成后不要关闭连接,下⼀次还⽤这个请求的连接进行后续交流
**keep-alive 的优点**
优点:
-
较少的 CPU 和内存的占⽤(因为要打开的连接数变少了, 复用了连接)
-
减少了后续请求的延迟(⽆需再进⾏握⼿)
缺点:
-
因为在处理的暂停期间,本来可以释放的资源仍旧被占用。请求已经都结束了, 但是还一直连接着也不合适
解决:Keep-Alive: timeout=5, max=100
-
timeout:过期时间5秒(对应httpd.conf里的参数是:KeepAliveTimeout),
-
max是最多一百次请求,强制断掉连接。就是在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉
**为什么需要HTTPS**
HTTPS 是安全版的 HTTP。HTTP 协议在传输数据时采用的是明⽂方式传递,因此,⼀些敏感信息的传输就变得很不安全
**HTTPS是如何保证安全的**
HTTPS 在传输数据的过程中会对数据进行加密处理,保证安全性。目前常见的加密算法可以分成三类,对称加密算法,非对称加密算法和Hash算法
*对称加密*
对称加密的特点是文件加密和解密使用相同的密钥,即加密密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,通信的双⽅都使⽤同⼀个秘钥进⾏加解密。⽐如,两个人事先约定的暗号,就属于对称加密。
- 优点:
-
计算量小、加密速度快、加密效率高。
- 缺点:
-
在数据传送前,发送方和接收方必须商定好秘钥,然后双方保存好秘钥。如果一方的秘钥被泄露,那么加密信息也就不安全了
*⾮对称加密*
而加密和解密其实可以使用不同的规则,只要这两种规则之间存在某种对应关系即可,这样就避免了直接传递密钥。这种新的加密模式被称为"非对称加密算法"。通信的双方使用不同的秘钥进行加密解密,即秘钥对(私钥 + 公钥)。特征: 私钥可以解密公钥加密的内容, 公钥可以解密私钥加密的内容
- 优点:
-
非对称加密与对称加密相比其安全性更好
- 缺点:
-
加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
*数字证书*
*数字签名*
DOM的事件流是什么
⼜称为事件传播,是⻚⾯中接收事件的顺序。DOM2级事件规定的事件流包括了3个阶段:
-
- 事件捕获阶段(capture phase)
-
- 处于⽬标阶段(target phase)
-
- 事件冒泡阶段(bubbling phase)
![](https://i-blog.csdnimg.cn/blog_migrate/fc1fb1462bb801aee634ce8f17e1a0ba.png)
如上图所示,事件流的触发顺序是:
-
事件捕获阶段,为截获事件提供了机会
-
实际的⽬标元素接收到事件
-
事件冒泡阶段,可在这个阶段对事件做出响应
**事件委托**
-
利用了事件冒泡的机制,在较上层位置的元素上添加一个事件监听函数,来管理该元素及其所有子孙元素上的某一类的所有事件
如何实现跨域
-
- JSONP
-
- CORS
-
- 服务器代理(webpack代理, Nginx反向代理)
**JSONP**
这是一种非常经典的跨域方案,它利用了`<script>` 标签不受同源策略的限制的特性,实现跨域效果
// 1. JSONP 发送请求的函数封装
function JSONP({ url, params, callbackKey, callback }) {
// 在参数中指定 callback 名字
params = params || {} params[callbackKey] = 'jsonpCallback'
// 预留 callback
window.jsonpCallback = callback
// 拼接参数字符串
const queryString = Object.keys(params).map(key => `${key}=${params[key]}`).join('&')
// 创建 script 标签
const script = document.createElement('script')
script.setAttribute('src', `${url}?${queryString}`)
// 插⼊ DOM 树
document.body.appendChild(script)
}
// 2. 调用示例
JSONP({
url: 'http://s.weibo.com/ajax/jsonp/suggestion',
params: {
key: 'test'
},
callbackKey: '_cb',
callback(res) {
console.log(res.data)
}
})
**CORS**
⽬前比较主流的跨域解决⽅案,它利用一些额外的 HTTP 响应头来通知浏览器允许访问来自指定 origin 的非同源服务器上的资源
**Nginx反向代理**
目前最方便,最推荐使用的跨域解决方案,Nginx 作为代理服务器,所有客户端的请求都必须先经过 Nginx 的处理,然后再将请求转发给其他后端程序(比如 Node.js 或Java 程序),这样就规避同源策略的影响
# 进程, 可更具 cpu 数量调整
worker_processes 1;
events {
# 连接数
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#连接超时时间,服务器会在这个时间过后关闭连接。
keepalive_timeout 10;
# 开启 Gzip 压缩
gzip on;
# 直接请求nginx也是会报跨域错误的这⾥设置允许跨域
# 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
# srever模块配置是http模块中的⼀个⼦模块,⽤来定义⼀个虚拟访问主机
server {
listen 80;
server_name localhost;
# 根路径指到index.html
location / {
root html;
index index.html index.htm;
}
# 请求转发:
# 例如 http://localhost/api 的请求会被转发到 http://192.168.0.103:8080
location /api {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.0.103:8080;
}
# 重定向错误⻚⾯到/50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
[参考文章:跨域方式实现原理](九种跨域方式实现原理(完整版) - 掘金
JavaScript内置对象
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象
内置对象:JS 语言自带的一些对象,提供了一些常用的或是最基本而必要的功能
Math对象:Math对象不是构造函数,它拥有一些数学常数属性和数学函数方法
Math.floor() //向下取整
Math.ceil() //向上取整
Math.round() //四舍五入版就近取整注意-3.5结果是-3
Math.abs() //绝对值
Math.max() / Math. min() //求最大和最小值
Math.random() //获取范围在[0,1)内的随机值
日期对象:需要自行创建实例对象 new Date()
getFullYear() //获取当年
getMonth() //获取当月(0-11)
getDate() //获取当天日期
getDay() //获取星期几(周日0到周六6)
getHours() //获取当前小时
getMinutes() //获取当前分钟
getSeconds() //获取当前秒钟
数组对象
push(参数) //末尾添加一个或多个元素,注意修改原数组 并返回新的长度
pop() //删除数组最后一个元素,把数组长度减1无参数、修改原数 返回它删除的元素的值
unshift(参数1) //向数组的开头添加一个或更多元素,注意修改原数组 并返回新的长度
shift() //删除数组的第一个元素,数组长度减1无参数、修改原数组 并返回第一个元素的值
reverse() //颠倒数组中元素的顺序无参数,会改变原来的数组,返回新数组
sort() //对数组的元素进行排序,会改变原来的数组,返回新数组
indexof() //数组中查找给定元素的第一个索引,如果存在返回索引号,如果不存在,则返回-1
lastIndexof() //在数组中的最后一个的索引,如果存在返回索引号,如果不存在,则返回-1
tostring() //把数组转换成字符串,逗号分隔;返回一个字符串
join(分隔符) //用于把数组中的所有元素转换为一个字符串;返回一个字符串
concat() //连接两个或多个数组,不影响原数组;返回一个新的数组
slice(begin,end) //数组截取 返回被截取项目的新数组
splice(开始下标,要删除个数,增加的数组) //数组删除,返回被删除项目的新数组;会影响原数组
filter() //方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素
forEach() //方法对数组的每个元素执行一次给定的函数。
字符串对象
indexof() //字符串中查找给定字符的索引,如果存在返回索引号,如果不存在,则返回-1
lastIndexof() //从后往前找,只找第一个匹配的
charAt(index) //返回指定位置的字符 (index字符串的索引号)
charCodeAt(index) //获取指定位置处字符的Ascii码(index索引号)
str[index] //获取指定位置处字符
concat(str1,str 2,str3...) //用于连接两个或多个字符串。拼接字符串,等效于+
substr(start,length) //star位置开始(索引号), length取的个数
slice(start, end) //从 start位置开始,截取到end位置,end取不到(他们俩都是索引号)
substring(start, end) //从 start位置开始,截取到end位置,end取不到;基本和slice相同但是不接受负值
replace(被替换的字符串, 要替换为的字符串) //用于在字符串中用一些字符替换另一些字符
split(“分隔符”) //用于切分字符串,将字符串切分为数组
觉得有用的可以点赞、收藏,防止走丢