深入javascript计划一:数据类型深入介绍

02-JavaScript-内部JS、外部JS、数据类型、关键词 内部JS示例");// 在页面加载完成后自动弹出提示框 阅读详情

javascript有几种数据类型?

答:javascript有两种数据类型

基本数据类型:string、boolean、number、null、undefined、symbol

引用数据类型:对象Object(包括普通对象-object、数组对象-array、正则对象-regexp、日期对象-date、数学对象-math、函数对象-function)

小知识:&代表取址、*代表取值,不过JavaScript中是没有的,我们以go来做例子

 

基本数据类型

JavaScript

let a = 'a'
let b = a
let b = 'b'
console.log(a) // a
console.log(b) // b

go

package main

import "fmt"

func main()  {
    a:="a"
    b:=a
    b="b"
    fmt.Println(a, &a) // a 0xc00003e1f0
    fmt.Println(b, &b) // b 0xc00003e200
}

画解思路

所以javascript的基本数据类型,是自动会新建一个指针(内存地址)并把值拷贝过去,因为指针(内存地址)不同,所以例子中的b修改了不会影响到a

 

引用数据类型

正则对象-regexp、日期对象-date、数学对象-math、函数对象-function,JavaScript会自动会新建一个指针(内存地址)并把值拷贝过去,以日期对象-date为例子

let a = new Date()
let b = a
console.log(b) // 2020-06-15T15:18:59.026Z
b = 123
console.log(a) // 2020-06-15T15:18:59.026Z
console.log(b) // 123

主要注意:普通对象-object、数组对象-array

JavaScript

let a = {
    name: 'a',
    age: 13
}
let b = a
b.name = "b"
console.log(a) // { name: 'b', age: 13 }
console.log(b) // { name: 'b', age: 13 }

let a = new Object
a.name = 'a'
a.age = 12
let b = a
b.name = 'b'
console.log(a) // { name: 'b', age: 12 }
console.log(b) // { name: 'b', age: 12 }


// 分割线

let a = [ {name: "a", age: 13} ]
let b = a
b[0].name = 'b'
console.log(a) // [ { name: 'b', age: 13 } ]
console.log(b) // [ { name: 'b', age: 13 } ]

go

package main

import "fmt"

func main()  {
    var a map[string]interface{} // 声明变量不分配内存
    a = make(map[string]interface{}) // 分配内存
    a["name"] = "a"
    a["age"] = 12
    b:=a
    b["name"] = "b"
    fmt.Println(a) // map[age:12 name:b]
    fmt.Printf("%p", a) // 0xc000070330
    fmt.Println(b) // map[age:12 name:b]
    fmt.Printf("%p", b) // 0xc000070330
}

画解思路

所以JavaScript的引用数据类型(普通对象-object、数组对象-array),是指向同一个指针(内存地址),所以例子中的b修改了会影响到a

 

来谈谈深浅拷贝

浅拷贝

let a = [1, 2, 3]
let b = a.slice()
b[0] = 100
console.log(a) // [1, 2, 3]
console.log(b) // [100, 2, 3 ]

当修改b的时候,a的值并不会改变。why? 因为 b和a指向的指针(内存地址)已经不一样了,这就是浅拷贝

同时也是会有问题,看例子

let a = [1, 2, 3, {name: 'a'}]
let b = a.slice()
b[0] = 100
b[3].name = 'b'
console.log(a) // [ 1, 2, 3, { name: 'b' } ]
console.log(b) // [ 100, 2, 3, { name: 'b' } ]

明明指针(内存地址)指向都不一样了,为什么修改b[3].name,a[3].name的值也会跟着改变?

这就是浅拷贝的限制所在了。它只能拷贝一层对象。如果有对象的嵌套,那么浅拷贝将无能为力。所以深拷贝就是为了解决这个问题而生的,它能解决无限极的对象嵌套问题,实现彻底的拷贝。下面会介绍深拷贝,让我们先看看浅拷贝有多少种方法

Object.assign

小知识:object.assign(target, source1, source2, source3.....)方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象

let a = {name: "a", age: 13}
let b = Object.assign({}, a)
b.name = 'b'
b.age = 18
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 18 }

// 分割线

let a = {name: "a", age: 13}
let b = Object.assign({}, a, {name: 'b'})
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 13 }
b.age = 18
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 18 }

// 分割线

let a_name = { name: "a" }
let a_age = { age: 13 }

let b = Object.assign(a_name, a_age)
console.log(a_name) // { name: 'a', age: 13 }
console.log(a_age) // { age: 13 }
console.log(b) // { name: 'a', age: 13 }
b.name = "b"
b.age = 18
console.log(a_name) // { name: 'b', age: 18 }
console.log(a_age) // { age: 13 }
console.log(b) // { name: 'b', age: 18 }

// 分割线

let a_name = { name: "a" }
let a_age = { age: 13 }

let b = Object.assign({}, a_name, a_age)
console.log(a_name) // { name: 'a' }
console.log(a_age) // { age: 13 }
console.log(b) // { name: 'a', age: 13 }
b.name = "b"
b.age = 18
console.log(a_name) // { name: 'a' }
console.log(a_age) // { age: 13 }
console.log(b) // { name: 'b', age: 18 }

concat浅拷贝数组

let a = [1, 2, 3, 4]
let b = a.concat()
b[1] = "22"
console.log(a) // [ 1, 2, 3, 4 ]
console.log(b) // [ 1, '22', 3, 4 ]

slice浅拷贝数组

let a = [1, 2, 3]
let b = a.slice()
b[0] = 100
console.log(a) // [1, 2, 3]
console.log(b) // [100, 2, 3 ]

...展开运算符

let a = [1, 2, 3, 4]
let b = [...a]
b[1] = "22"
console.log(a) // [ 1, 2, 3, 4 ]
console.log(b) // [ 1, '22', 3, 4 ]

// 分割线

let a = { name: 'a', age: 13 }
let b = { ...a }
b.name = 'b'
b.age = 18
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 18 }

手写

function shallowClone (target) {
    if (typeof target === 'object' && target !== null) {
        let cloneTarget = Array.isArray(target) ? [] : {}
        for (let item in target) {
            if (target.hasOwnProperty(item)) {
                cloneTarget[item] = target[item]
            }
        }
        return cloneTarget
    } else {
        return
    }
}

let a = {name: "a", age: 13}
let b = shallowClone(a)
b.name = "b"
b.age = 18
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 18 }

好了,浅拷贝就讲到这里。

深拷贝

json序列化

let a = {
    name: 'a',
    age: 13
}
let b = JSON.parse(JSON.stringify(a))
b.name = "b"
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 13 }

json序列化能覆盖大多数的应用场景,但是实际上,对于一些严格的场景,这个方法是个坑,问题如下:

1.无法拷贝函数

let a = {
    name: "a",
    fn: (msg) => {
        console.log(msg)
    }
}
let b = JSON.parse(JSON.stringify(a));
a.fn("a") // a
b.fn("b") //  b.fn is not a function

2.无法解决循环引用问题

let a = {name: "a"}
a.info = a
console.log(a) // { name: 'a', info: [Circular] }
let b = JSON.parse(JSON.stringify(a)) // RangeError: Maximum call stack size exceeded

 拷贝a会出现系统栈溢出,因为出现了无限递归的情况

3.无法拷贝一些特殊对象,如:正则对象-regexp、日期对象-date等。

手写简易版深拷贝

let a = {
    name: 'a',
    age: 13
}
// 递归拷贝
function deepCopy(target) {
    if (typeof target === 'object' && target !== null) {
        let cloneTarget = Array.isArray(target) ? []: {};
        for (let item in target) {
          if (target.hasOwnProperty(item)) {
              cloneTarget[item] = deepCopy(target[item]);
          }
        }
        return cloneTarget;
    } else {
        return target;
    }
}

let b = deepCopy(a);
b.name = 'b'
console.log(a) // { name: 'a', age: 13 }
console.log(b) // { name: 'b', age: 13 }

这是一个递归拷贝,我们以刚刚发现的三个问题为导向,一步步来完善、优化我们的深拷贝代码

1.无法解决循环引用问题

当 对象a 中的某个属性指向 对象b 或者 对象b 中的某个属性指向 对象a 或者 对象a 中的某个属性指向 对象a,就会出现循环引用问题(当然不止这一种情况,不过原理是一样的)下面通过代码来说明一下。

let a = { name: 'a' }
let b = { b: a }
a.info = b
console.log(a) // { name: 'a', info: { b: [Circular] } }
console.log(b) // { b: { name: 'a', info: [Circular] } }

// 分割线

let a = {name: "a", age:14}
a.info = a
console.log(a) // { name: 'a', age: 14, info: [Circular] }

图。。。大概就这样吧

这时候就谈谈 JS 中垃圾回收策略

标记清除

JavaScript中最常见的垃圾收集方式是标记清除(mark-and-sweep)

当运行addTen()这个函数的时候,就是当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”

function addTen(num){  
     var sum += num // 垃圾收集已将这个变量标记为“进入环境”
     return sum    // 垃圾收集已将这个变量标记为“离开环境”
}
addTen(10) // 输出20

 

可以使用任何方式来标记变量。比如,可以通过翻转某个特殊的位来记录一个变量何时进入环境, 或者使用一个“进入环境的”变量列表及一个“离开环境的”变量列表来跟踪哪个变量发生了变化。说到底,如何标记变量其实并不重要,关键在于采取什么策略。

let user = {name : 'scott', age : '21', gender : 'male'} // 在全局中定义变量,标记变量为“进入环境”
user = null // 最后定义为null,释放内存

 

垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间

引用计数

JavaScript中不太常见的垃圾收集策略叫做引用计数(reference counting)。引用计数的含义是跟踪记录每个值被引用的次数

当声明了一个变量并将一个引用类型值赋值该变量时,则这个值的引用次数就是1.

如果同一个值又被赋给另外一个变量,则该值得引用次数加1。

相反

如果包含对这个值引用的变量又取 得了另外一个值,则这个值的引用次数减 1。

当这个值的引用次数变成 0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。

这样,当垃圾收集器下次再运行时,它就会释放那 些引用次数为零的值所占用的内存。 

问题来了就是循环引用

function test() {
  let a = { name: 'a' }
  a.info = a
  a.info.name = "aa"
  console.log(a) // { name: 'aa', info: [Circular] }
}
test()

 

就用上面代码例子来说,a是引用类型,所以现在a的引用计算值为1,然后a.info又赋值为a,而a是引用类型所以a.info也是引用类型,所以现在a引用计算值为2

采用标记清除策略,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是个问题

采用引用计数策略,当函数执行完毕后,a还将继续存在,因为它们的引用次数永远不会是 0

假如这个函数被重复多次调用,就会导致大量内存得不到回收

小知识:所以要养成习惯,将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收他们占用的内存。

回到 循环引用 那 解决方法有几种?

json序列化

let a = { name: 'a' }
let b = { b: JSON.parse(JSON.stringify(a)) }
a.info = JSON.parse(JSON.stringify(b))
console.log(a) // { name: 'a', info: { b: { name: 'a' } } }
console.log(b) // { b: { name: 'a' } }

// 分割线

let a = {name: "a", age:14}
a.info = JSON.parse(JSON.stringify(a))
console.log(a) // { name: 'a', age: 14, info: { name: 'a', age: 14 } }

还可以使用 json扩展包 JSON.decycle来去除循环引用。

不过我们还是以手写简易版为主,创建一个Map,记录下已经拷贝过的对象,如果说已经拷贝过,那直接返回它行了。

const isObject = (target) => (typeof target === 'object' || typeof target === 'function') && target !== null;
function deepCopy (target, map = new Map()) { 
  if(map.get(target)) return target
  if (isObject(target)) { 
    map.set(target, true)
    const cloneTarget = Array.isArray(target) ? []: {}
    for (let item in target) { 
      if (target.hasOwnProperty(item)) { 
          cloneTarget[item] = deepCopy(target[item],map)
      } 
    } 
    return cloneTarget
  } else { 
    return target
  } 
}
let a = {name: "a", age: 13}
a.info = a
let b = deepCopy(a)
b.name = "b"
b.age = 18
console.log(a) // { name: 'a', age: 13, info: [Circular] }
console.log(b) // { name: 'b', age: 18, info: { name: 'a', age: 13, info: [Circular] } }

好像是没有问题了, 拷贝也完成了。但还是有一个潜在的坑, 就是map 上的 key 和 map 构成了强引用关系,这是相当危险的。我给你解释一下与之相对的弱引用的概念你就明白了:

在计算机程序设计中,弱引用与强引用相对, 是指不能确保其引用的对象不会被垃圾回收器回收的引用。 一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。 --百度百科

说的有一点绕,我用大白话解释一下,被弱引用的对象可以在 任何时候被回收,而对于强引用来说,只要这个强引用还在,那么对象无法被回收拿上面的例子说,map 和 a一直是强引用的关系, 在程序结束之前,a 所占的内存空间一直 不会被释放

怎么解决这个问题?

很简单,让 map 的 key 和 map 构成弱引用即可。ES6给我们提供了这样的数据结构,它的名字叫WeakMap,它是一种特殊的Map,其中的键是弱引用的。其键值必须是对象,而值可以是任意的。

function deepCopy (target, map = new WeakMap()) {
  //...
}

 

2.无法拷贝一些特殊对象

对于特殊的对象,我们使用以下方式来鉴别

Object.prototype.toString.call(obj);

梳理一下对于可遍历对象会有什么结果

["object Map"]
["object Set"]
["object Array"]
["object Object"]
["object Arguments"]

好,以这些不同的字符串为依据,我们就可以成功地鉴别这些对象。

const getType = Object.prototype.toString.call(obj);

const canTraverse = {
  '[object Map]': true,
  '[object Set]': true,
  '[object Array]': true,
  '[object Object]': true,
  '[object Arguments]': true,
};

const deepClone = (target, map = new Map()) => {
  if(!isObject(target)) 
    return target;
  let type = getType(target);
  let cloneTarget;
  if(!canTraverse[type]) {
    // 处理不能遍历的对象
    return;
  }else {
    // 这波操作相当关键,可以保证对象的原型不丢失!
    let ctor = target.prototype;
    cloneTarget = new ctor();
  }

  if(map.get(target)) 
    return target;
  map.put(target, true);

  if(type === mapTag) {
    //处理Map
    target.forEach((item, key) => {
      cloneTarget.set(deepClone(key), deepClone(item));
    })
  }
  
  if(type === setTag) {
    //处理Set
    target.forEach(item => {
      target.add(deepClone(item));
    })
  }

  // 处理数组和对象
  for (let prop in target) {
    if (target.hasOwnProperty(prop)) {
        cloneTarget[prop] = deepClone(target[prop]);
    }
  }
  return cloneTarget;
}

 不可遍历的对象

const boolTag = '[object Boolean]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

对于不可遍历的对象,不同的对象有不同的处理

const handleRegExp = (target) => {
  const { source, flags } = target;
  return new target.constructor(source, flags);
}

const handleFunc = (target) => {
  // 待会的重点部分
}

const handleNotTraverse = (target, tag) => {
  const Ctor = targe.constructor;
  switch(tag) {
    case boolTag:
    case numberTag:
    case stringTag:
    case errorTag: 
    case dateTag:
      return new Ctor(target);
    case regexpTag:
      return handleRegExp(target);
    case funcTag:
      return handleFunc(target);
    default:
      return new Ctor(target);
  }
}

我们连拷贝函数一起写了,直接看总结果

3.无法拷贝函数

提到函数,在JS种有两种函数,一种是普通函数,另一种是箭头函数。每个普通函数都是 Function的实例,而箭头函数不是任何类的实例,每次调用都是不一样的引用。那我们只需要 处理普通函数的情况,箭头函数直接返回它本身就好了

那么如何来区分两者呢?

答案是: 利用原型。箭头函数是不存在原型的。

const handleFunc = (func) => {
  // 箭头函数直接返回自身
  if(!func.prototype) return func;
  const bodyReg = /(?<={)(.|\n)+(?=})/m;
  const paramReg = /(?<=\().+(?=\)\s+{)/;
  const funcString = func.toString();
  // 分别匹配 函数参数 和 函数体
  const param = paramReg.exec(funcString);
  const body = bodyReg.exec(funcString);
  if(!body) return null;
  if (param) {
    const paramArr = param[0].split(',');
    return new Function(...paramArr, body[0]);
  } else {
    return new Function(body[0]);
  }
}

到现在,我们的深拷贝就实现地比较完善了。不过在测试的过程中,我也发现了一个小小的bug

const target = new Boolean(false);
const Ctor = target.constructor;
new Ctor(target); // 结果为 Boolean {true} 而不是 false。

对于这样一个bug,我们可以对 Boolean 拷贝做最简单的修改, 调用valueOf: new target.constructor(target.valueOf())。

但实际上,这种写法是不推荐的。因为在ES6后不推荐使用【new 基本类型()】这 样的语法,所以es6中的新类型 Symbol 是不能直接 new 的,只能通过 new Object(SymbelType)。

因此我们接下来统一一下:

const handleNotTraverse = (target, tag) => {
  const Ctor = targe.constructor;
  switch(tag) {
    case boolTag:
      return new Object(Boolean.prototype.valueOf.call(target));
    case numberTag:
      return new Object(Number.prototype.valueOf.call(target));
    case stringTag:
      return new Object(String.prototype.valueOf.call(target));
    case errorTag: 
    case dateTag:
      return new Ctor(target);
    case regexpTag:
      return handleRegExp(target);
    case funcTag:
      return handleFunc(target);
    default:
      return new Ctor(target);
  }
}

OK!是时候给大家放出完整版的深拷贝啦

const getType = obj => Object.prototype.toString.call(obj);

const isObject = (target) => (typeof target === 'object' || typeof target === 'function') && target !== null;

const canTraverse = {
  '[object Map]': true,
  '[object Set]': true,
  '[object Array]': true,
  '[object Object]': true,
  '[object Arguments]': true,
};
const mapTag = '[object Map]';
const setTag = '[object Set]';
const boolTag = '[object Boolean]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

const handleRegExp = (target) => {
  const { source, flags } = target;
  return new target.constructor(source, flags);
}

const handleFunc = (func) => {
  // 箭头函数直接返回自身
  if(!func.prototype) return func;
  const bodyReg = /(?<={)(.|\n)+(?=})/m;
  const paramReg = /(?<=\().+(?=\)\s+{)/;
  const funcString = func.toString();
  // 分别匹配 函数参数 和 函数体
  const param = paramReg.exec(funcString);
  const body = bodyReg.exec(funcString);
  if(!body) return null;
  if (param) {
    const paramArr = param[0].split(',');
    return new Function(...paramArr, body[0]);
  } else {
    return new Function(body[0]);
  }
}

const handleNotTraverse = (target, tag) => {
  const Ctor = target.constructor;
  switch(tag) {
    case boolTag:
      return new Object(Boolean.prototype.valueOf.call(target));
    case numberTag:
      return new Object(Number.prototype.valueOf.call(target));
    case stringTag:
      return new Object(String.prototype.valueOf.call(target));
    case symbolTag:
      return new Object(Symbol.prototype.valueOf.call(target));
    case errorTag: 
    case dateTag:
      return new Ctor(target);
    case regexpTag:
      return handleRegExp(target);
    case funcTag:
      return handleFunc(target);
    default:
      return new Ctor(target);
  }
}

const deepClone = (target, map = new WeakMap()) => {
  if(!isObject(target)) 
    return target;
  let type = getType(target);
  let cloneTarget;
  if(!canTraverse[type]) {
    // 处理不能遍历的对象
    return handleNotTraverse(target, type);
  }else {
    // 这波操作相当关键,可以保证对象的原型不丢失!
    let ctor = target.constructor;
    cloneTarget = new ctor();
  }

  if(map.get(target)) 
    return target;
  map.set(target, true);

  if(type === mapTag) {
    //处理Map
    target.forEach((item, key) => {
      cloneTarget.set(deepClone(key, map), deepClone(item, map));
    })
  }
  
  if(type === setTag) {
    //处理Set
    target.forEach(item => {
      cloneTarget.add(deepClone(item, map));
    })
  }

  // 处理数组和对象
  for (let prop in target) {
    if (target.hasOwnProperty(prop)) {
        cloneTarget[prop] = deepClone(target[prop], map);
    }
  }
  return cloneTarget;
}

手写深拷贝完毕!

在深入了解一下函数传参,这时候要先了解一下什么是形参、实参?

实参(argument):在调用有参函bai数时,函数名后面括号中的参数为“实际参数”

实参是:常量、变量、表达式、函数等,实参是任何类型的量,当开始在进行函数调用时,都必须有确定的值

形参(parameter):不是实际存在变量,又称虚拟变量

形参是:变量只有在被调用时才分配内存单元,在调用结束时,就会释放出所分配的内存单元。所以,形参只能在函数内部才有效

JavaScript

function test(obj) {
    obj.name = "b";
    return obj;
}
let a = {
    name: "a",
    age: 11
};
let b = test(a);
console.log(a); // { name: 'b', age: 11 }
console.log(b); // { name: 'b', age: 11 }

// 分割线

function test(obj) {
    obj = "b";
    return obj;
}
let a = 'a'
let b = test(a);
console.log(a); // a
console.log(b); // b

在函数传参也是一样。好了深浅拷贝就讲到这里!

 

null是对象吗?为什么?

结论: null不是对象。

解释: 虽然 typeof null 会输出 object,但是这只是 JS 存在的一个悠久 Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object 。

 

'1'.toString()为什么可以调用?

其实在这个语句运行的过程中做了这样几件事情:

var s = new String('1');
s.toString();
s = null;

第一步: 创建String类实例。

第二步: 调用实例方法。

第三步: 执行完方法立即销毁这个实例。

整个过程体现了基本包装类型的性质,而基本包装类型恰恰属于基本数据类型,包括Boolean, Number和String。

参考:《JavaScript高级程序设计(第三版)》P118

 

0.1+0.2为什么不等于0.3?

0.1和0.2在转换成二进制后会无限循环,由于标准位数的限制后面多余的位数会被截掉,此时就已经出现了精度的损失,相加后因浮点数小数位的限制而截断的二进制数字在转换为十进制就会变成0.30000000000000004。

 

参考:

https://juejin.im/post/5dbebbfa51882524c507fddb#heading-59

https://www.cnblogs.com/scottjeremy/p/6870729.html

AI全景之第八章第三节:时间序列分析与预测技术 摘要 时间序列分析与预测技术从传统统计模型发展到深度学习方法。传统方法包括ARIMA模型(处理趋势和季节性)、指数平滑(加权平均预测)和状态空间模型(概率框架分解)。机器学习方法通过特征工程和树模型提升非线性建模能力。深度学习方法中,RNN/LSTM处理序列依赖,TCN利用因果卷积,Transformer通过注意力机制捕获长程依赖。当前研究趋势结合神经符号方法和生成模型,以提高预测精度和可解释性。不同方法各具优势,需根据数据特性和预测需求选择。 阅读详情

相关推荐

Verilog实现SPI通信协议驱动设计

线性序列机实现SPI协议

H19981118的博客 6085

JavaScript数据类型有哪些?

JS数据类型有哪些

u011200562的博客 6340

UE4-(IK)实现人物脚贴合地面解决斜坡上脚无旋转无法贴合地面问题

在斜面上脚陷入模型中,需要设置旋转值对脚的骨骼进行一个旋转。 解决思路:在射线检测中可以获取到检测点的法线方向,根据法线方向来计算出脚应该向哪个方向进行适当的旋转,在斜坡上,人物脚需要旋转的轴为x轴和y轴以便来贴合地面,z轴方向的旋转是不需要进行修改的。 如图所示,我们需要求得水平面与斜坡的夹角用来得出人物在x轴上的脚旋转量,在蓝图中提供反正切函数,反正切 = 锐角的邻边/对边 所以 反正切值(脚x轴值(roll)) = 法线Y轴值/法线Z轴 值。 现在将上图的人物想象成面向屏幕,脚需...

Stone的博客 3317

js 的九大数据类型

javascript有9种数据类型,分别为:字符串(String)、数字(Number)、布尔(Boolean)、Null、Undefined、Symbol、对象(Object)、数组(Array)、函数(Function)。 可检测基本数据类型和function,无法检测引用数据类型 JavaScript数据类型:JavaScript语言的每一个值,都属于某一种数据类型。JavaScript的数据类型,共有9种:值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、

m0_62173626的博客 5145

FANUC机器人有关动作速度倍率的相关系统变量-解释说明

FANUC机器人有关动作速度倍率的相关系统变量-解释说明 1.$SHFTOV_ENB 默认值:0 名称:位移倍率的有效/无效 含义:位移倍率功能,通过按住SHIFT键的同时按下倍率键,将速度倍率更改为5档 设定值:有效1; 无效0. 有SHFIT键:微速–低速–5%–50%–100% 2.MCRGRP[GROUP].MCR_GRP[GROUP].MCRG​RP[GROUP].PRGOVERRIDE 默认值:100 名称:程序倍率 含义:设定程序再生时的、机器人动作速度比率 设定值:0~100(%) 3.S

Robot_PLC_HMI_Automation 9320

手把手教你ensp仿真搭建校园网(含防火墙及无线网络)系列(二)校园网接入层交换机配置

本系列博客将带你从零开始,使用 华为 eNSP(Enterprise Network Simulation Platform) 仿真搭建一个完整的校园网络,涵盖 核心层、汇聚层、接入层、防火墙安全策略、无线AC+AP组网 等实战场景。无论你是网络初学者还是希望深化实战经验的工程师,都能通过本教程掌握企业级网络的规划、配置与排错技巧。

echo的博客 1219

JS基础篇1:数据类型(8种)

最近有很多人说数据类型是 6种。我怎么记得JS的数据类型有8种。最近发现好多人对JS的基础不太了解。很多数据类型都没有搞清楚。不BB,我就按我的理解写一波笔记,每次看一波书我就感觉一次比一次多懂一点。来补下知识点。。。。 JS数据类型:基础概念 请注意:JS的数据类型有8种。 在ES5的时候,我们认知的数据类型确实是 6种:Number、String、Boolean、undefined、o...

1363648943的专栏 17万+

使用C#实现Padim算法的训练和推理:智能缺陷检测的前沿技术

Padim (Patch-based Deep Image Model) 是一种用于无监督异常检测的深度学习算法。它通过提取图像中的局部特征(patch),并在这些特征上构建一个正常样本的分布模型来识别异常。无监督学习:不需要标注数据,适用于缺乏标签的情况。局部特征提取:通过卷积神经网络提取图像的局部特征(patch)。低秩近似:利用低秩近似构建正常样本的协方差矩阵,有效降低计算复杂度。鲁棒性强:能够处理多种类型的缺陷和噪声。

墨夶的博客 1013

js有几种数据类型

js 中数据类型分为原始数据类型与引用数据类型 原始数据类型: number //数值类型:值只能为数字 var a = 12 string //字符串类型:值都是以引号包裹的 var a = '你好' boolean //布尔类型:值只存在真假 var a = true var a = false null //空类型 var a = null undefined //未定义类型: 定义了变量a,但是没有a赋值 var a console.log(a

m0_47796330的博客 951

RT-DETR模型应用过程中的报错处理及疑问解答,涉及环境搭建、模型训练、模块改进、论文写作

本文记录了RT-DETR模型的这一系列过程中可能发生的问题,以及大家非常关心的问题,这里统一做了一个记录和解答。

Limiiiing的博客 1764

瑞芯微RK3588部署YOLOv8模型

写下这篇博客进行记录,以防后面忘了怎么部署。

weixin_45303602的博客 3656

JavaScript 数据类型——八种数据类型总结

JavaScript 有几种数据类型? JavaScript 目前包含八种数据类型,其中可以分成两大类。 基本数据类型(原始值): Number(数值,包含NaN) String(字符串) Boolean(布尔值) Undefined(未定义/未初始化) Null(空对象) Symbol(独一无二的值,ES6引入的新类型) 复杂数据类型(引用值): Object(对象。Array/数组 和 function/函数 也属于对象的一种)

黄凯达的博客 1万+

黑猫带你学UFS协议第12篇:UFS标志(Flags)和属性(Atrributes)详解

UFS中的标志其实就是一些开关,布尔型,非0即1,打开或者关闭。这些标志可以用来使能或者禁止UFS设备的一些功能、模式或者状态。 简单来说,flag和attribute、discriptor一样,都是ufs的寄存器罢了。只不过spec将这些寄存器分类了,分成这三种大的类型了而已。 标志可以被清除、复位、设置、触发、读。 主机也是通过设备管理器的Query Request UPIU来读取或者写标志。

黑猫奥利奥的博客 2083

JavaScript的数据类型详细介绍

JavaScript的数据类型分为俩种,一种是基本数据类型,一种是引用数据类型 基本数据类型包括: Number - - (数字) String - - (字符串) Boolean - - (布尔值) Undefined - - (未定义) Null - - (空的) Symbol - - (符号) 引用数据类型包括: 1.Object - - (对象) 2.Array - - (数组)...

吴小迪的博客 3万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【JavaScript用法】JavaScript(JS)的基本语法(JS数据类型,JS变量,JS运算符,JS流程控制语句)

JavaScript(JS)的基本语法 目录 JavaScript(JS)的基本语法 一. 与html结合方式 二. 注释 三. 数据类型: 四. 变量 五. 运算符(和Java有点类似) 六. 流程控制语句(和JAVA类似): 七. JS特殊语法: 一. 与html结合方式 1. 内部JS:定义<script>,标签体内容就是js代码(...

No8g攻城狮的博客 5105

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

JavaScript学习手册一:JS简介

第1关:JavaScript 语言介绍、注释及基本输出方式 任务描述 要了解一门编程语言,要从输出开始。 本关任务:采用相关知识中介绍的任意一种方法输出“ Hello, JavaScript! ”。 相关知识 JavaScript 语言简介 JavaScript 诞生于1995年。在那个时代用户提交一个表单需要获取服务器端的反馈,这个时间大概十几秒,如果能在客户 qa 端完成一些基本的验证绝对是很大的进步。当时如日中天的 Netscape 公司,决定着手开发一种客户端语言解决简单的表单验证。就职

weixin_54327001的博客 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

JavaScript 学习手册二:JS 数据类型

第1关:JavaScript 数据类型介绍 任务描述 本关任务:在函数 objectTest() 内部定义了六个变量 a、b、c、d、e、f,并已经赋值,你需要判断它们各是什么数据类型。变量 aType、bType、cType、dType、eType、fType 分别表示上面六个变量的数据类型的名字,你需要给他们赋值。比如变量 a 如果是数字类型,需要给变量 aType 赋值字符串 number。可选的数据类型名如下: number、string、bool、object、undefined 和 arra

weixin_54327001的博客 8432

JavaScript基础:js介绍、变量、数据类型以及类型转换

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

专注于前后端学习 1076

JS数据类型深度解析一

JS数据类型分为哪几个? 基本数据类型(又称为值类型) 引用类型 值类型(储存在栈中): undefined 未定义 String 字符串 Number 数字 Boolean 布尔 Symbol 符号 引用类型(储存在堆中): Array 数组 Object 对象 null 空(有歧义,也可以认为它是值类型) Function 函数 2. 怎么判断数据类型? 最常见的判断方法:typeof var a = "iamstring."; var b = 222; var c=

qq_45891136的博客 1863

JavaScript基础(一)—— JS介绍、变量、常量、数据类型、类型转换

是一种运行在客户端(浏览器)的编程语言,实现人机交互效果。网页特效(监听用户的一些行为让网页作出对应的反馈)表单验证(针对表单数据的合法性进行判断)数据交互(获取后台的数据, 渲染到前端)服务端编程(node.js)组成:ECMAScript( 基础语法 )、web APIs (DOM、BOM)。ECMAScrip规定了js基础语法核心知识。比如:变量、分支语句、循环语句、对象等等。Web APIsDOM操作文档,比如对页面元素进行移动、大小、添加删除等操作。

此心光明事上练的博客 1096

JavaScript介绍、数据类型、简单语法、函数、对象

是一种广泛应用于网页开发的脚本语言,它能够使网页变得更加动态和交互性。作为一种客户端脚本语言JavaScript可以被嵌入到HTML中,并且可以被所有现代的网页浏览器支持。return 0;

Eric_re的博客 1780

【JS基础 day01 JavaScript介绍、变量、常量、数据类型、运算符】

了解变量、数据类型、运算符等基础概念,能够实现数据类型的转换,结合四则运算体会如何编程。

Jhaiajsbzksk的博客 2219

初学JavaScript:js的组成、特点、作用、注释、变量和数据类型基本介绍

1、JavaScript的完整组成* ECMAScript,描述了该语言的语法和基本对象。 文档对象模型(DOM),描述处理网页内容的方法和接口。 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口。 ECMAScript【js标准】 由单行注释与块注释( // 、/**/)、变量、操作符、流程控制语句、数组、对象、函数、正则表达式等构成的标准。目前基本所有的js解释器都可以兼容ECMAScript。 DOM文档对象模型【document object model】 简单来说就是使用JavaSc

lalala_dxf的博客 2200

【JavaScript】一篇文章,带你拿捏JS中的数据类型

JavaScript有8种数据类型:7种基本类型(String、Number、Boolean、null、undefined、Symbol、BigInt)和引用类型Object。基本类型存储在栈内存中,引用类型存储在堆内存中,栈中保存引用地址。字符串不可变,数组可变;数字采用IEEE754标准,存在精度问题;布尔值用于逻辑运算;null表示空值,undefined表示未赋值;Symbol创建唯一标识符;BigInt处理大整数。引用类型包括对象、数组、函数等。内存分为代码空间(存储代码)、栈空间(存储基本类型和

sunshine_dd的博客 1479

一 JavaScript之数据类型

js中有5种简单数据类型:Undefined、Null、Boolean、Number和String。还有一种复杂数据类型——Object。ECMAScript不支持任何创建自定义类型的机制,所有值都成为以上6中数据类型之一。一.typeof操作符 typeof操作符是用来检测变量的数据类型。对于值或变量使用typeof操作符会返回如下字符串。 字符串 描述 undefined 未定义

IOS开发进阶之路 1792

Javascript基础(一)简单介绍、数据类型、操作符

目录 JS基础 网页、网站和应用程序 JS的强大应用举例 Javascript介绍 Javascript是什么 Javascript最初目的 Javascript现在的意义(应用场景) JS和HTML、CSS的区别 Javascript的组成 ECMScript-----Javascript的核心 BOM---浏览器对象模型 DOM---文档对象模型 Javascript...

Problem_Girl的博客 650
上一篇: 手动实现代理服务器(仿nginx)
下一篇: 深入javascript计划二:数据类型检测与数据类型抽象转换
An_s
博客等级 码龄10年 665粉丝 363原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

An_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值