同源策略: 浏览器的策略
+协议相同 +域名相同 +端口相同
触发同源策略 带来的影响
+ 好处:
1. Cookie、LocalStorage 和 IndexDB 无法读取。
2. DOM 无法获得。
3. AJAX 请求在浏览器端有跨域限制
+ 限制:(坏处)
+无法获取 cookie localStorage indexDB
+无法操作 DOM
+ ajax : AJAX 请求在浏览器端有跨域限制
跨域:(解决AJAX 请求在浏览器端有跨域限制)
+ jsonp 主要是前端用来跨域
+ 跨域的解决的方法 + jsonp
+ 原理: script 的src属性 不受同源策略的影响 通过script标签引入的文件 会把他解析成js代码去执行
+ 前后端都要协助 + 只能发送get请求
cors 需要在后端设置响应头
// 允许所有的域名访问
res.setHeader("Access-Control-Allow-Origin", "*");
// 可以设置那些请求头
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild");
// 允许的请求方式
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.setHeader("X-Powered-By", "3.2.1");
res.setHeader("Content-Type", "application/json;charset=utf-8");
**Proxy 代理跨域**
\+ 讲我想发送的请求目标地址
=> 告诉给我同源的服务器
=> 由同源服务器向真实数据服务器发起请求
=> 数据服务器把响应给到同源服务器(代理服务器)
=> 同源服务器再把结果返回给我
1.自执行函数
+ IIFE
+ 不需要调用 自己会执行
+ 执行完以后 就会销毁 不会占用内存
+ 作用:
+ 一般用在功能初始化的页面
+ 可以使代码模块化
+ (function(){})() // 常用
+ (function(){}())
+ !function(){}()
+ ~function(){}()
2.模块化
+ AMD 依赖前置 require.js
+ CMD 按需加载 sea.js
+ ES6 模块化
type = module
在服务端环境下打开
+ 导出
+ export let a = 100
+ export {a,b}
+ export default {a,b}
+ 导入
+ import {a as 别名,b} from '地址' 接收的是 导出在对象里面
+ import 变量名 from '地址' 接收的是 默认导出的
+ import * as 变量名 from '地址' 接收就是默认导出的和对象里面
+ node模块 common.js
3.函数的两个阶段
+ 定义阶段
+ 调用阶段
+ 通过空间地址 找到代码
+ 把代码拿出来
+ 形参赋值
+ 预解析
+ 开辟一个执行空间
+ 把代码放在执行空间执行
+ 销毁执行空间
5.闭包函数
+ 有一个外层函数outer 里层函数inner
+ 外层函数返回里层函数 外部有变量去接收
+ 里面函数 访问着外层函数的变量
+ 特点:
+函数的执行空间不销毁
+ 有一个函数
+ 返回一个复杂数据类型
+ 在外面有一个变量去接收
+ 只要改变这个变量的指向 就能销毁
function fun(n, o) { // 全局的fun
console.log(o) //n=0
const obj = {
fun: function (m) { // obj里面fun
return fun(m, n)
}
}
return obj
}
// var res = fun(0) // 执行全局的fun n=0 // 打印 undefined // res = {fun:function(m){return fun(m.n)}}
// res.fun(1) // obj里面fun //m =1 n没有赋值 fun(m,n) fun(1,0) // 打印 0
// res.fun(2) // obj里面fun // m =2 n fun(m,n) fun(2,0) //
// res.fun(3)
// var b = fun(0) // 执行 全局的fun n = 0 // 打印undefined // b = {fun:function(m){return fun(m.n)}}
// var b = fun(0).fun(1) // 执行 fun(1) // m =1 n =0 fun(1,0) // n=1 o =0 //打印0
// var b = fun(0).fun(1).fun(2) // 执行fun(2) // m =2 n = 1 fun(2,1) // n =2 o =1 // 打印 1
// var b = fun(0).fun(1).fun(2).fun(3) // 执行fun(3) m = 3 n = 2 fun(3,2) // n = 3 o = 2 // 打印2
var c = fun(0).fun(1) // 执行 fun(1) // m =1 n =0 fun(1,0) // n=1 o =0 //打印0
c.fun(2) // 打印1
c.fun(3) //打印1
6.函数的柯理化
+ 把本来该一次传递的参数 分开多次的传递
+ 利用闭包 变量的生命周期被延长 保存上一次收集的参数
function current(fn,...arg){
let _arg = arg
let len =fn.length
return function(...arg){
_arg = [..._arg,...arg]
if(_arg.length>=len){
return fn(..._arg)
}else{
return current(fn,..._arg)
}
}
}
继承
+ 原型继承
+ 借用构造函数继承
+ 组合继承
+ ES6继承
+ extends
+ super 传递参数 必须写在构造器最上面
+ 父类的构造函数体类继承到 子类实例化对象里面
+ 父类的原型对象上 子类的 原型链上面
isArray
hasOwnPoperty
assign
+ 注意: 返回的新的对象的地址 和 第一个参数的地址一样
深浅拷贝:
+ 浅拷贝
+ 简单的赋值
+ 简单的遍历
+ 扩展运算符
+ assign
+ 深拷贝
+ json反序列化
+ JSON.parse(JSON.stringify(obj))
+ 递归遍历
+ lodash
数据劫持
+ 给对象添加成员
Object.defineProperty(对象,key,{
配置项
value:值 可以设置值
writable:布尔值 是否可以修改值 默认false
enumerable:布尔值 是否可以枚举 默认false
get:是一个函数 获取器 可以给当前的key设置值
注意: 不能和value writable 一起使用
set: 是一个函数 设置器 在当前这个属性改变的时候 被触发
函数有一个参数 参数就是你想改变的那个值
})
let obj = {
name: '张三',
age: 18
}
function observer(origin, fn) {
let target = {}
for (let key in origin) {
Object.defineProperty(target, key, {
get() {
//获取时触发
return origin[key]
},
set(val) {
//修改时触发
//想要改变目标对象 要先改变原始对象
origin[key] = val
fn(key)
}
})
}
return target
}
const app = observer(obj, (key) => {
console.log(key + '我被改变了')
})
app.gender = '男'
console.log(app)
Proxy 数据代理 Vue3 的数据双向绑定的原理
+ 内置构造函数 ES6语法
+ new Proxy(对象,{配置项})
+ 返回值: 实例化对象 就是你代理的结果
+ 动态添加的成员也能被监听到
let input = document.querySelector('input')
let p = document.querySelector('p')
let obj = {
name: "张三",
age: 18
}
const result = new Proxy(obj, {
//配置项
// 通过get方法获取
get(origin, poperty) {
// origin 表示原始对象 在这里就是obj
// poperty 表示遍历的每一项的key值 自动帮你遍历的
return origin[poperty]
},
// set 设置
set(origin, poperty, val) {
origin[poperty] = val
console.log(poperty+'被改变了' + val)
// p.innerHTML = `我是${result.name}`+'我今年'+result.age
// 在简单的代理和严格模式下 需要写 return true
return true
}
})
设计模式:用来解决一些特定问题的开发思路
1.工厂模式:只需要你提供名称 就可以给你返回具体实例化对象
function Basketball() {
this.name = '篮球 '
}
Basketball.prototype.play = function () {
console.log('我喜欢打篮球')
}
function Football() {
this.name = '足球 '
}
Football.prototype.play = function () {
console.log('我喜欢踢足球')
}
function Pingpang() {
this.name = '乒乓球 '
}
Pingpang.prototype.play = function () {
console.log('我喜欢打乒乓球')
}
function store(name) {
switch (name) {
case 'Basketball':
return new Basketball()
break;
case 'Football':
return new Football()
break;
case 'Pingpang':
return new Pingpang()
break;
default:
return '没有这个用品'
break;
}
}
let res = store('Pingpang')
console.log(res.name)
res.play()
2.单例模式
核心代码
let instance = null
function singleTon(){
if(!instance) instance = 实例化对象
return instance
}
// let p1 = singleTon() // 第一次调用 instance 是null 会被赋值一个实例化对象a 被返回到外界
// let p2 = singleTon() // 第二次调用 instance 已经是一个实例化对象了 不会再赋值 那么返回给外界的就是第一次赋值的那个实例化对象
//单例模式代码改造
const Person = (function () {
function Person() {
this.name = 'jack'
}
Person.prototype.say = function(){
console.log(123)
}
let instance = null
return function () {
if (!instance) {
instance = new Person()
}
return instance
}
})()
console.log(Person)
let p1 = Person()
console.log(p1)
let p2 = Person()
console.log(p2)
p1.say()
p2.say()
console.log(p1 == p2)
3. 发布订阅者模式
<script>
class Lesson{
constructor(){
this.message = {}
}
add(type, fn){
if(!this.message[type]){
this.message[type] = []
}
this.message[type].push(fn)
}
remove(type, fn){
this.message[type] = this.message[type].filter(item=>{return item!=fn})
}
emit(type, notice){
this.message[type].forEach(item=>{item(notice)})
}
}
let less1 = new Lesson()
less1.add('H5', fn1)
less1.add('H5', fn2)
less1.add('H5', fn3)
// 取消课程订阅
less1.remove('H5', fn2)
function fn1(notice){
console.log('张三:'+notice)
}
function fn2(notice){
console.log('李四:'+notice)
}
function fn3(notice){
console.log('王五:'+notice)
}
less1.emit('H5', '11月11号要开课了,赶紧来吧!')
垃圾回收机制
+ 就是js语言本身给咱们做的内存分配和管理的机制
+ 会每隔一段时间会自动扫描咱们的代码,看那些变量没有在使用了,进行统计然后统一回收,释放占有的空间
+ 回收的形式
=> 标记法,当它扫描确定你这个变量没有用处了,会自动给它进行标记,然后统一把做了标记的变量进行回收
=> 引用计数,当咱们开辟了一块空间,会自动把计数器自增,当一个东西没有用的时候,自动把计数器减一(了解)
模板引擎
<!--模板输出语法,是一个表达式-->
{{title}}
<!--注意点:前面加@符号就可以解析字符串中的标记-->
{{@title}}
<hr/>
<!--判断-->
<!-- {{if price>1000}}
<p>你好!</p>
{{/if}} -->
<!-- {{if price>1000}}
<p>你好!</p>
{{else}}
<p>hello!</p>
{{/if}} -->
<!-- {{if price>=1200}}
<p>1200</p>
{{else if price>=1000}}
<p>1000</p>
{{else}}
<p>{{price}}</p>
{{/if}} -->
<!--遍历-->
<ul>
<!--注意点:这里默认是target,而target表示的是你需要遍历的数据-->
<!--默认给咱们提供的是下标是$index,值是$value-->
<!-- {{each list}}
<li>{{$index}}, {{$value}}</li>
{{/each}}-->
<!--注意点:咱们自己修改的,不需要加$,主要是为了做区分-->
{{each list item key}}
<li> {{key}},{{item}}</li>
{{/each}}
</ul>
+ art-temple
+ 之前原生js渲染数据,把html结构都是放在js代码逻辑当中,这样导致逻辑显得特别乱,而且渲染特别麻烦
+ 模板引擎可以解决这些问题
=> 可以让咱们的渲染结构和js逻辑分离
=> 运行速度特别快
=> 会有自己简化的语法
SPA 单页面模式
single page application
+ 主要应用在移动端 或者pc端管理系统
+ 切换依赖
+ 形式1: 根据hash值改变(锚点)
+ 形式2: 根据浏览器历史记录history
+ 前端开发
+ 面向过程 函数式编程 面向对象
+ 组件化开发:包含一整套 html css js
单页面应用
+ 名称:spa
+ 指的是切换标签页的时候,只是内容改变了,网页不进行跳转操作
+ 类似tab选项卡
+ 单页面应用其实是使用锚点来实现的
onhashchange
+ hash指的是哈希值,就是锚点后面那一截 /video
+ 当咱们改变了锚点时触发