JS基础篇,持续更新。。。

一、基础知识

1. 数据类型

js 中的数据类型包含两部分:

1)基本数据类型(String、Number、Boolean、Null、Undefined、Symbol)

2)复杂数据类型(Object)

2. typeof 的作用

用于判断是否是某个数据类型:

var
  a = 'a',
  b = 1,
  c = [1, 2, 3],
  d = {a: 'a'},
  e = new Date(),
  f = new RegExp(),
  g = true,
  h = new Function(),
  i = null,
  j = undefined;
  console.log(typeof a, typeof b, typeof c, typeof d, typeof e, typeof f, typeof g, typeof h, typeof i, typeof j)

// 输出
// string number object object object object boolean function object undefined

3. 引用类型

引用类型包括:Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。

4. instanceof 的作用

用于判断是否是某个对象类型

var a = [1,2,3];
console.log(a instanceof Object); //true
console.log(a instanceof Array); //true
console.log(a instanceof RegExp); //false

5. 类型转换

js中有两种强制类型转换:

1)显示类型转换

  • 转换为数值类型:Number(mix)、parseInt(string,radix)、parseFloat(string)

  • 转换为字符串类型:toString(radix)、String(mix)

  • 转换为布尔类型:Boolean(mix)

2)隐式类型转换

  • 用于检测是否为非数值的函数:isNaN(mix);

  • 递增递减操作符(包括前置和后置)、一元正负符号操作符

  • 加法运算操作符

  • 乘除、减号运算符、取模运算符

  • 逻辑操作符(!、&&、||)

  • 关系操作符(<, >, <=, >=)

  • 相等操作符(==)

6. 原型链

推荐文章:https://www.jianshu.com/p/dee9f8b14771

7. 闭包

闭包是指有权访问另一个函数作用域中的变量的函数。

可以看下我写的另一篇关于闭包的文章:闭包的理解

8. 类和继承

五条规则:

  • 所有的引用类型(数组、函数、对象)都具有对象特性,即可自由扩展属性

  • 所有的引用类型(数组、对象、函数)有一个__proto__ 属性,属性值是一个普通的对象

  • 所有的函数都有一个prototype属性,属性值也是一个普通的对象

  • 所有的引用类型(数组、对象、函数),__proto__属性指向它的构造函数的prototype属性

  • 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么回去他的__proto__(即它的构造函数的prototype中寻找)

详情传送门:https://www.cnblogs.com/chengzp/p/extends.html

9. 变量提升与函数提升

这个很好理解,就是在某个 作用域 内,用 var 声明的变量以及函数声明会提升到作用域顶部。

console.log(a) // undefined
var a = 'haha';
console.log(a) // haha

由于变量提升,实际上是这样执行的:

var a;
console.log(a)
a = 'haha';
console.log(a)

函数也是一样,但要注意一点:只有函数声明才会提升整个函数代码块,函数表达式则只会提升标识符。

console.log(f1); // [Function: f1]
console.log(f2); // undefined

//函数声明
function f1() {

}
//函数表达式
var f2 = function () {

}

10. this 指向问题

可参考我的一篇文章:关于this的指向问题

11. new 操作符到底干了什么

就干了这些:

  1. 创建了一个新对象
  2. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) 
  3. 执行构造函数中的代码(为这个新对象添加属性) 
  4. 返回新对象

用代码表示就是:

var obj  = {};
obj.__proto__ = Person.prototype;
Person.call(obj);
  • 第一行,我们创建了一个空对象obj
  • 第二行,我们将这个空对象的__proto__成员指向了Person函数对象prototype成员对象
  • 第三行,我们将Person函数对象的this指针替换成obj,然后再调用Person函数,于是我们就给obj对象赋值了一个id成员变量,这个成员变量的值是”Person”

12. script标签的async和defer属性

有了async属性,表示后续文档的加载和渲染与js脚本的加载和执行是并行进行的,即异步执行;加载完立即执行。

有了defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本的执行需要等到文档所有元素解析完成之后,DOMContentLoaded事件触发执行之前。解析完执行。

如果存在多个有defer属性的脚本,那么它们是按照 加载顺序 执行脚本的;而对于async,它的加载和执行是紧紧挨着的,无论声明顺序如何,只要加载完成就立刻执行,它对于应用脚本用处不大,因为它完全不考虑依赖。

13. 为什么TCP连接三次握手,断开4次挥手

三次握手

  • 第一次握手:客户端发送请求报文。
  • 第二次握手:服务端接受报文并发送应答报文。
  • 第三次握手:客户端发送应答报文

相当于

  • 第一次握手: A给B打电话说,你可以听到我说话吗?
  • 第二次握手: B收到了A的信息,然后对A说: 我可以听得到你说话啊,你能听得到我说话吗?  
  • 第三次握手: A收到了B的信息,然后说可以的,我要给你发信息啦!

四次挥手

  • 主动方:server我要断开连接了。
  • 被动方:等会,我还有一些响应的信息还没发给你。

。。。过了一会

  • 被动方 :响应信息发好了,我要断开连接了。

虽然server信息发好了,但是要考虑到client还在接受信息于是server就在等client的确认信息。

  • 主动方:接收好了,断开连接了。

14. 跨域问题

跨域:

浏览器对于javascript的同源策略的限制,例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了,上面提到的,同域的概念又是什么呢?简单的解释就是相同域名,端口相同,协议相同,请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同。

jsonp的产生:

1. AJAX 直接请求普通文件存在跨域无权限访问的问题,不管是静态页面也好。

2. 不过我们在调用 js 文件的时候又不受跨域影响,比如引入 jquery 框架的,或者是调用相片的时候。

3. 凡是拥有 src 这个属性的标签都可以跨域例如 <script> <img> <iframe>。

4. 如果想通过纯 web 端跨域访问数据只有一种可能,那就是把远程服务器上的数据装进js格式的文件里。

5. 而 json 又是一个轻量级的数据格式,还被js原生支持。

6.为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个 callback 参数给服务端。

基于iframe实现的跨域

要求两个域具有 aa.xx.com,bb.xx.com 这种特点;也就是两个页面必须属于一个基础域(例如都是 xxx.com ),使用同一协议和同一端口,这样在两个页面中同时添加 document.domain,就可以实现父页面调用子页面的函数,要点就是:通过修改document.domain 来跨子域。

15. 数组的用法与字符串的用法

我的另两篇文章 数组的一些用法总结  字符串的一些用法总结

二、算法知识

1. 数组去重

function arrayUnique(arr) {
  let a = [];
  let len = arr.length;
  for (let i = 0; i < len; i++) {
    if (a.indexOf(arr[i]) < 0) {
      a.push(arr[i])
    }
  }
  return a
}
let newArr = arrayUnique([1, 2, 3, 2, 3, 1, 23, 4]);
console.log(newArr) //[ 1, 2, 3, 23, 4 ]
function arrayUnique(arr) {
  let json = {}
  let newArr = []
  let len = arr.length
  for (let i = 0; i < len; i++) {
    if (!json[arr[i]]) {
      json[arr[i]] = true
      newArr.push(arr[i])
    }
  }
  return newArr
}

let newArr = arrayUnique([1, 2, 3, 2, 3, 1, 23, 4]);
console.log(newArr) //[ 1, 2, 3, 23, 4 ]
function arrayUnique(arr) {
  return Array.from(new Set(arr));
}

let newArr = arrayUnique([1, 2, 3, 2, 3, 1, 23, 4]);
console.log(newArr) //[ 1, 2, 3, 23, 4 ]
function arrayUnique(arr) {
  return [...new Set(arr)];
}

let newArr = arrayUnique([1, 2, 3, 2, 3, 1, 23, 4]);
console.log(newArr) //[ 1, 2, 3, 23, 4 ]

2. 数组降维  

var arr = [1, [2, [3, [4, [5, [6, [7]]]]]]]
function dimensionalityReduction(arr){ 
    var tempArr = Array.from(arr.join('-'));
    for(var i = 0;i<tempArr.length;i++){ 
        if(isNaN(tempArr[i])){ 
            tempArr.splice(i,1) 
        } 
    } 
    return tempArr; // 1,2,3,4,5,6,7
}
let flatten = arr => arr.reduce((pre,cur)=>{
  Array.isArray(cur)?pre.push(...flatten(cur)):pre.push(cur);
  return pre //1,2,3,4,5,6,7
},[])

3. 输出字符中最长的没有重复字符的字串

var str = 'aadacd'
function getMaxUniquePart(str) {
  let res = 0;
  let unqiueStr = '';
  let maxStr = '';
  let len = str.length;
  for (let i = 0; i < len; i++) {
    let a = str.charAt(i);
    let index = unqiueStr.indexOf(a)
    if (index === -1) {
      unqiueStr += a
      if (res <= unqiueStr.length) {
        res = unqiueStr.length
        maxStr = unqiueStr
      }
    } else {
      unqiueStr = unqiueStr.substr(index + 1) + a
    }
  }
  return maxStr
}

console.log(getMaxUniquePart(str)) //dac

这种方法有一个不足,如果有多个长度相同的子串则无法得到多个字串,只会输出第一个。

var str = 'aadacd'
function getMax(data) {
  data = data.trim();
  let obj = {
    start: 0
  };
  let nowStr = '';
  let maxStr = '';
  let strGroup = []
  let maxLen = 0;
  let len = data.length;
  for (let i = 0; i < len; i++) {
    let char = data[i];
    if (!(obj[char] >= 0)) { // 若不重复
      obj[char] = i;
      nowStr += char;
    } else {  // 若重复
      if (obj.start <= obj[char]) { // 若start指针在重复字符(重复字符的第一个字符)之前
        obj.start = obj[char] + 1; // 改变start指针位置
        obj[char] = i; // 改变这个字符的位置
        if (nowStr.length > maxLen) { // 比较当前子串跟最长子串的长度
          maxStr = nowStr;  // 若大于,则替换
          maxLen = nowStr.length;
          nowStr = data.substring(obj.start, i + 1);
        } else if (nowStr.length === maxLen) { // 若等于,则隔一个空格加在末尾
          maxStr += ' ' + nowStr;
          nowStr = data.substring(obj.start, i + 1);
        } else {  // 若小于,仅更新nowStr
          nowStr = data.substring(obj.start, i + 1);
        }
      } else { // 若start指针在重复字符(重复字符的第一个字符)之后
        obj[char] = i;  // 改变这个字符的位置
        nowStr = data.substring(obj.start, i + 1);
      }
    }
  }
  if (nowStr.length > maxLen) {
    maxStr = nowStr;
    maxLen = nowStr.length;
  } else if (nowStr.length === maxLen) {
    maxStr += ' ' + nowStr;
  }
  return maxStr
}

console.log(getMax(str)) //dac acd

不知是否还有更为简单的方式,望告知。

4. 输入一个数组和一个数,找出数组中两个值之和为该数,返回该俩个值的位置

function getOrder(arr, sum) {
  let a = {}
  let b = []
  for (let i = 0; i < arr.length; i++) {
    let c = sum - arr[i]
    if (a[c] === undefined) {
      a[arr[i]] = i
    } else {
      b.push([a[c], i])
    }
  }
  return b
}

console.log(getOrder([1, 17, 8, 20, 5, 9, 0], 25)) //[ [ 1, 2 ], [ 3, 4 ] ]
发布了29 篇原创文章 · 获赞 35 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/linxner/article/details/87177987