高级js

作者: 小王子__ | 来源:发表于2020-07-20 18:55 被阅读0次

1,JS中的数据类型:

  • 基本数据类型
    • String
    • Number
    • Boolean
    • Undefined
    • Null
    • symbol
    • bigint
  • 引用数据类型
    • object
      • 普通对象
      • 正则对象
      • 日期对象
      • Math数学函数对象
        .....
    • function
      数据类型检测:
  • typeof 检测数据类型的逻辑运算符
  • instanceof 检测是否为某个类的实例
  • constructor 检测构造函数
  • Object.prototype.toString.call 检测数据类型
let a = typeof typeof typeof [12, 23]
console.log(a)   // 'string'

把其他数据类型转换为数字的方法:

  • 强转换(基于底层机制转换的)
    • Number()
  • 弱转换(基于一些额外的方法转换)
    • parseInt()
    • parseFloat()
parseInt('')    //NaN
Number('')  // 0
isNaN('')   // false  isNaN走的是隐式转换,先把''转换成Number => 0  isNaN(0) => false
parseInt(null)   NaN
Number(null)   //0
isNaN(null)   // isNaN(0)   false
parseInt('12px')   // 12
Number('12px')   // NaN
isNaN('12px')  // true
parseFloat('1.6px') + parseInt('1.2px') + typeof parseInt(null)   // 1.6 + 1 + typeof NaN  => 2.6 + 'number'  => '2.6number'
isNaN(Number(!!Number(parseInt('0.8'))))   // isNaN(0)  => false
typeof !parseInt(null) + !isNaN(null)  // 'boolean' + true  => 'booleantrue'
0  NaN null undefined 空字符串 转换成布尔都是false

2,浏览器底层机制:堆栈内存和VO、GO等
js之所以能在浏览器中运行,是因为浏览器给js提供了执行的环境 => 栈内存
JS运行的底层机制: 浏览器之所以给JS提供运行机制,是浏览器会在计算机内存中分配一块内存,专门用来供代码执行 => 栈内存 ECStack(执行环境栈),没打开一个网页都会开辟出一块执行环境栈。
GO(全局对象),浏览器把内置的一些属性方法放到一个单独的内存中,这个内存叫堆内存;浏览器端会让window指向GO
栈内存:用来提供代码执行的环境
堆内存:存放东西(存放的是属性方法)
EC(执行上下文): 代码自己执行所在的环境

  • 全局的执行上下文 EC(G)
  • 函数中的代码都会在一个单独的私有的执行上下文中处理
  • 块级的执行上下文
    上下文执行是在栈内存中执行,进栈出栈
    VO(变量对象): 在当前的上下文中,用来存放创建的变量和值的地方(每个执行上下文中都会有一个自己的变量对象,函数私有上下文中叫做AO(活动对象),也是变量对象


    01.png
02.png 3.png
var a = {n: 1}
var b = a
a.x = a = {n: 2}
console.log(a.x)
console.log(b)
// undefined {n: 1, {n: 2}}
function fun (n, o) {
  console.log(o)
  return {
    fun: function (m) {
        return fun(m, n)
    }
  }
}
var c = fun(0).fun(1);
c.fun(2);
c.fun(3)

const定义的值能改吗?
const定义的基本类型不能改 但是定义的对象是可以通过修改对象属性改变的

const a = 10
a  // 10
a = 20
VM110:1 Uncaught TypeError: Assignment to constant variable
const b = {}
b  // {}
b.name = 'xiaowang'
b // {name: 'xiaowang'}
b = {}
VM110:1 Uncaught TypeError: Assignment to constant variable
js中的栈内存和堆内存

在js引擎中对变量的存储有两种位置: 栈、堆
栈内存主要存储基本类型的变量(string、number、Boolean、undefined、null)以及对象变量的指针,栈内存就像一个线性排列的空间,每个小单元大小基本相等
堆内存主要存储像object这种引用类型的变量
堆的特点是无序的key-value键值对存储方式。
当我们定义一个const对象的时候,我们说的常量其实就是指针,就是const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或属性是可变的,const定义的基本类型的变量,这个值相当于const对象的指针,是不可变的
js不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间,在操作对象的时候,实际上是在操作对象的引用而不是实际的对象,因此,引用类型的值都是按引用访问的,这里的引用,可以粗浅的理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联

WechatIMG20.jpeg
var a = new String('str')
var b = new String('str')
a === b //false

很明显,如果a、b存储在栈内存中,两者明显相等 这里两者不等说明他们都存储在堆内存中,指针指向不一致
3,深拷贝、浅拷贝
两者最根本的区别: 是否真正获取一个对象的复制实体,而不是引用。
B复制了A,修改A的时候看B是否发生变化,如果B发生变化,说明是浅拷贝,如果B没有发生变化,则是深拷贝。
浅拷贝只是增加了一个指针指向已存在的内存地址
深拷贝是增加了一个指针并申请了一个新的内存,使这个增加的指针指向这个新的内存;即在计算机中开辟一块新的内存地址用于存放复制的对象。
浅拷贝:

    var obj = {
      a: 1,
      arr: [1, 2]
    }
    function lightCopy (v) {
      var newObj = {}
      for (var prop in v) {
        if (v.hasOwnProperty(prop)) {
          newObj[prop] = obj[prop]
        }
      }
      return newObj
    }
    var obj2 = lightCopy(obj)
    obj2.arr[1] = 100   // obj.arr[1] = 100  obj2.arr[1] = 100
    console.log(obj, obj2)  // {a: 1, arr: [1, 2])

深拷贝实例:

方法一: 
var obj = {
      name: 'wangyaru',
      arr: [1,2,3,4,5,6,7,8,9]
}
function deepCopy(obj) {
   var newObj = obj instanceof Array ? [] : {}
   if (typeof obj !== 'object') {
      return obj
   } else {
     for (var i in obj) {
        newObj[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]
      }
   }
   return newObj
}
方法二: 只能处理符合JSON格式的对象
    var obj = {
      name: 'wangyaru',
      arr: [1,2,3,4,5,6,7,8,9]
    }
    function deepCopy (o) {
      return JSON.parse(JSON.stringify(obj))
    }
    var obj2 = deepCopy(obj)
    obj2.arr[1] = 100
    console.log(obj, obj2) 
 // obj1: {
 // arr: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
 // name: "wangyaru"
 // }
// obj2: {
 // arr: (9) [1, 100, 3, 4, 5, 6, 7, 8, 9]
 // name: "wangyaru"
 // }

深拷贝时,obj和obj2分别拥有不同的内存地址,两边的值互不影响
4,promise

function Fn() {}  // Fn函数
const fn = new Fn()   //Fn是构造函数  fn是实例对象简称对象
console.log(Fn.prototype)  // Fn是函数对象

首先先说下同回调函数和异步回调函数

同步:
 const arr = [1,2,3]
arr.forEach(i => {
  console.log(i)
})
console.log('forEach之后')
// 1 2 3 forEach之后
异步:
setTimeout(_ => {
  console.log('callback')
})
console.log('setTimeout之后')

error:
常见的内置错误:
1,ReferenceError 引入的变量不存在
console.log(a) // Uncaught ReferenceError: a is not defined
Uncaught => 未被处理的
2,TypeError 数据类型不正确的错误
let b = {}
b.xxx() // Uncaught TypeError: b.xxx is not a function
3, rangeError 范围(range) 数据值不在其所允许的范围内
function fn () {
fn()
}
fn() // Uncaught RangeError: Maximum call stack size exceeded
4,SyntaxError 语法错误
const c= "''" // SyntaxError: Unexpected string
除了错应该处理 捕获错误: try ... catch
抛出错误: throw error

try {
    let b = {}
    console.log(b.xxx() )
} catch (error) {
    console.log(error)
}

promise是什么?
promise是JS中进行异步编程的新的解决方案
使用promise是解决回调地狱(函数内部嵌套函数等)的
回调地狱缺点: 不便于阅读/不便于异常处理
解决方案: promise链式调用
终极解决方案: async await
问题
从语法上说promise是一个构造函数
从功能上promise对象用来封装一个异步操作并可以获
取其结果
promise的状态改变:

pending变成 resolved  成功的
pending变成 rejected   失败的
pending(未确定的)
只有2种,且一个promise对象只能改变一次
无论变成成功还是失败 都会有一个结果数据
成功的结果数据一般成为value, 失败的结果数据一般成为女reason
pending怎么变成resolved 需要执行一个resolve函数

创建一个promise对象
const p = new Promise ((resolve, reject) _ => {
setTimeout(() => {
const time = Date.now()
if (time%2 == 0) {
resolve('成功的数据' + time)
} else {
reject('失败的数据' + time)
}
})
})
p.then(
value => {
console.log('成功的回调' + value)
},
reason => {
console.log('失败的回调' + reason)
}
)

new Promise ((resolve, reject) => {
  setTimeout(() => {
    resolve(''成功的数据)
    reject('失败的数据')
  }, 1000)
}).then(
  value => {
    console.log('onReveloved()', value)
  }
).catch (
  reason => {
    console.log('onRejected()', reason)
  }
)

面试题:

1,setTimeout(() => {
    console.log(1)
  })
  Promise.resolve().then(() => {
    console.log(2)
  })
  Promise.resolve().then(() => {
    console.log(4)
  })
  console.log(3)
2,setTimeout(() => {
    console.log(1)
  })
  new Promise((resolve) => {
    console.log(2)
    resolve()
  }).then(() => {
    console.log(3)
  }).then(() => {
    console.log(4)
  })
  console.log(5)
3,const first = () => (new Promise((resolve, reject) => {
    console.log(3)
    let p = new Promise((resolve, reject) => {
      console.log(7)
      setTimeout(() => {
        console.log(5)
        resolve(6)
      }, 0)
      resolve(1)
    })
    resolve(2)
    p.then((arg) => {
      console.log(arg)
    })
  }))
  first().then((arg) => {
    console.log(arg)
  })
  console.log(4)
4,setTimeout(() => {
    console.log('0')
  }, 0)
  new Promise((resolve, reject) => {
    console.log('1')
    resolve()
  }).then(() => {
    console.log('2')
    new Promise((resolve, reject) => {
      console.log('3')
      resolve()
    }).then(() => {
      console.log('4')
    }).then(() => {
      console.log('5')
    })
  }).then(() => {
    console.log('6')
  })
  new Promise((resolve, reject) => {
    console.log('7')
    resolve()
  }).then(() => {
    console.log('8')
  })

答案:

1, // 3 2 4 1
2, // 2 5 3 4 1
3, // 3 7 4 1 2 5
4, // 1 7 2 3 8 4 6 5 0

相关文章

网友评论

      本文标题:高级js

      本文链接:https://www.haomeiwen.com/subject/pmqghktx.html