JS汇总1

文章目录

函数汇总

操作数组方法

一、改变原始数组的方法:

1、pop()

删除 arrayObject 的最后一个元素,把数组长度减 1,并且返回它删除的元素的值。如果数组已经为空,则 pop() 不 改变数组,并返回 undefined 值。arrayObject.pop() 。

2、push()

push() 方法可把它的参数顺序添加到 arrayObject 的尾部。它直接修改 arrayObject,而不是创建一个新的数组,arrayObject.push(newelement1,newelement2,….,newelementX) 。

3、reverse()

该方法会改变原来的数组----将原来的数组倒序,而不会创建新的数组。arrayObject.reverse()。

4、shift()

删除数组的第一个元素,并返回第一个元素的值,如果数组是空的,那么 shift() 方法将不进行任何操作。

5、unshift()

unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。arrayObject.unshift(newelement1,newelement2,….,newelementX)返回arrayObject 的新长度。

6、sort()

对数组的引用。请注意,数组在原数组上进行排序,不生成副本。arrayObject.sort(sortby) (如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
  如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。)

排序则需要:比较函数

let arr = input.sort((a,b) => a-b)

7、splice()

splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。 如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组 arrayObject.splice(index,howmany,item1,……,itemX) 。

splice(2,1,‘www’) 从index==2删除一个,加上一个

8、split()

9、pop

​ 删除最后一个元素

二、不改变原始数组的方法:

1、concat()

用于连接两个或多个数组,仅会返回被连接数组的一个副本,arrayObject.concat(arrayX,arrayX,……,arrayX) 。

2、join()

返回一个字符串。该字符串是通过把 arrayObject 的每个元素转换为字符串,然后把这些字符串连接起来,arrayObject.join(separator) 。

3、slice()

arrayObject.slice(start,end)返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

slice(2,4) 截取index2到index4-1=3

4、JSON.parse(JSON.stringify(arry))

这种方式会重新复制一个数组。也是实现深拷贝的一种方式。

join() 方法用于把数组中的所有元素放入一个字符串,通过指定的分隔符进行分隔的。

split() 方法用于把一个字符串分割成字符串数组。

splice() start,end 删除

slice() 方法可从已有的数组中返回选定的元素。 不会改变原数组 slice(start,end)

push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。

indexOf() 返回匹配的第一个元素的下标

pop() 用于删除并返回数组的最后一个元素。

find()函数用来查找目标元素,找到就返回该元素,找不到返回undefined。

findIndex()函数也是查找目标元素,找到就返回元素的位置,找不到就返回-1。

他们的都是一个查找回调函数。

sort()

https://www.cnblogs.com/bigbang66/p/13660994.html

注意: 一切都是对数组操作的,比如数组对象

默认排序顺序是根据字符串UniCode码。所以首先应该把数组元素都转化成字符串(如有必要),以便进行比较。

一、概念

arr.sort((a,b) => {
    return a - b     //升序
}) 
比较函数应该具有两个参数 a 和 b,其返回值如下:
若 a 小于 b,即 a - b 小于零,则返回一个小于零的值,数组将按照升序排列。
若 a 等于 b,则返回 0。
若 a 大于 b, 即 a - b 大于零,则返回一个大于零的值,数组将按照降序排列。

二、对字符串

数字
*********************
let arr = [2,4,8,7,3,6]
arr.sort          //[2, 3, 4, 6, 7, 8]


字符串
**********************
let arr = ['cv','s','av','ac','dfs']
arr.sort()         //["ac", "av", "cv", "dfs", "s"]
arr.sort((a,b) => {
  return a.localeCompare(b)
})              //["ac", "av", "cv", "dfs", "s"]
使用字符串的 localeCompare() 方法,可以根据本地约定顺序来比较两个字符串的大小。


字符串数字
***********************
let arr = ['10','200','30']
arr.sort((a,b) => {return a - b})   //["10", "30", "200"]

["2", "20", "23", "4", "8"] =>   8423220 最大

b.sort((a,b) => {
      return (b+a) - (a+b)
    })



数组对象
***********************

    
    
 
对象
************************
新方法:
Object.keys() Object.vaules()
[...map.values()]) [...map.keys()]
    

  因为对象只有一串属性key和一串值value
所以对它进行操作实际上可以将它们分开处理
例如: afaafbbrbc'     变为'aaabbbffcr'
1、大小升序排序 2、个数升序排序

用到了两次sort()
步骤:
1、将数组写入对象,个数+1
2、通过Object.keys()将对象中的keys取出为数组 ["a", "f", "b", "r", "c"]
3、将数组升序排序
4、将数组对应的对象属性个数升序排序
5、两次循环打印对象
let str = 'afaafbbrbc';
  function fineE(str) {
    let obj = {};
    let res = [];
    for(let i = 0; i < str.length; i++) {
      obj[str[i]] ?  obj[str[i]] = obj[str[i]] + 1 :obj[str[i]] = 1
    }
    let line = Object.keys(obj)
    console.log(line);  //["r", "f", "c", "b", "a"]
    line.sort((a,b) => {    
      return a.localeCompare(b)
    })
    console.log(line);  //["r", "f", "c", "b", "a"]
    line.sort((a,b) => {
      return obj[b] - obj[a]
    })
    console.log(line);   //["a", "b", "f", "c", "r"]
    for(let i = 0; i < line.length; i++) {
      for(let j = 0; j < obj[line[i]]; j++) {
        res.push(line[i])
      }
    }
    console.log(res);
    res = res.join('')
    console.log(res);
  }

reduce() 累加器,函数为参

let arr1 = [1,2,3,4,5]
    function add1(arr) {
        return arr.reduce((a,b) => {
        return a+b
      })
    }
    console.log(add1(arr1)); //15
let arr1 = [1,2,3,4,5]
    function add1(arr) {
        return arr.reduce((a,b) => {
        return a+b
      },8)
    }
    console.log(add1(arr1)); //23

function count(arr, item) {
            var count = arr.reduce(function(prev, curr) {
                return curr === item ? prev+1 : prev;
            }, 0);
            return count;
        }//第一个参数为结果

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

let arr1 = [1,2,3,4,5]
    function add1(arr) {
        return arr.filter((a) => {
        return a>3
      })
    }
    console.log(add1(arr1)); //4,5

字符串变数组

let arr = 'gehe'
arr.split('')  //[]
//将输入数组分开 [2,20,23,4,8] -> [2,[2,0],[2,3],4,8]
for(let i=0;i<a.length;i++) {
    arr.push((a[i].toString().split('')).map(Number))   
  }

数组变字符串

  let arr = [1,2,4,3,4]
  //方法一
arr.join()      //1,2,4,3,4
arr.join('')     //12434
	//方法二
arr.toString()   //1,2,4,3,4
  var arr = [1,[2,3],[4,5], [6,[7,8]]];
arr.toString()   //1,2,3,4,5,6,7,8

数组变对象

一、数组中分割成对象

b = ['key=2','key=3','test=4']

//直接添加方括号
b //['key=2','key=3','test=4']   //针对对象包含数组
 b.forEach(item => {
        let keys = item.split('=')[0]
        let val = item.split('=')[1]
        res[keys]? res[keys] = [].concat(res[keys],val) :res[keys] = val
      })
res //{'key':['2','3'],'test':'4'}

res[keys] = [res[keys], val]   //法1: 中括号[] ,放数组4
res[keys] = [].concat(res[keys],val)  //法2: [],concat填加数组

二、纯数组变对象

Object.assign(...arr1),{...arr}

let arr = [1,2,4,3,4,'d']
{...arr}  //{0: 1, 1: 2, 2: 4, 3: 3, 4: 4, 5: "d"}



let arr1=[
                     {user:"123"},
                    {Cause:"22"},
                    {EnterFactoryTime:"33"},
                    {OutFactoryTime:"44"},
                    {VehicleGrade:"55"},
                    {IncomingInspection:"66"},
                    {Admission:"77"}
             ];

let arr2 = Object.assign(...arr1)

//{user: "123", Cause: "22", EnterFactoryTime: "33", OutFactoryTime: "44", VehicleGrade: "55",....}

对象变数组

  let obj = {
    'a' : 1,
    'b' :2
  }
Object.keys(obj)       //["a", "b"]
Object.values(obj)      //[1, 2]


const map  = new Map()
map.set('a', 1)
map.set('b', 2)
[...map]             //[['a',1], ['b',2]]
Array.from(map)      //[['a',1], ['b',2]]
[...map.keys()];    //["a", "b"]
[...map.values()]      //[1, 2]

对象添加属性

//数组添加属性方法: 法一: (c是常量,直接在对象后加. ,对象.常量) bb = {}, bb.c = 1  bb输出: {c: 1}
//  法二: (a为变量,常用于循环) bb = {},  let a = 'ff', bb[a] = 1,   bb输出: {ff: 1}   

let bb = {}
    bb.q = 5
    let t = "fu"
    bb[t] = 55
    console.log(bb); //{q: 5, fu: 55}
    console.log(bb.q+1, ++bb[t]);     //6 56

复制对象

实际上就是对对象进行拷贝

浅拷贝:

obj1 = obj

obj1 = Object.assign(obj)

for(let i in obj) {
    obj1[i] = obj[i]
  }

深拷贝:

类型

git

less sass

== ===

字符串

  obj1 = JSON.parse(JSON.stringify(obj))

递归方法
function g(obj) {
    let target = {}
    if(typeof obj !== 'object') return obj
    for(let i in obj) {
        if(obj.hasOwnProperty(i)) {
            target[i] === g(obj[i])
        }
    }
    return target
}


Map和Set

Map

Map对象保存键值对,并且能够记住键的原始插入顺序。[key,value]的数组

const map  = new Map()
map.set('a', 1)
map.set('b', 2)
console.log(map.get('a'))      //1
console.log([...map.keys()]);     //["a", "b"]
console.log([...map.values()]);    //[1,2]
console.log([...map.entries()]);	//[Array(2), Array(2)]
console.log(Array.from(map));		//[Array(2), Array(2)]

let first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);
let second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);
let man = new Map([...first, ...second])   //合并
console.log([...man]);       //[Array(2), Array(2), Array(2)]

for (let [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}

正则表达式

https://tool.oschina.net/uploads/apidocs/jquery/regexp.html

exec() 用于检索字符串中的正则表达式的匹配。只返回第一个值。

let a = 'rgb(255, 255, 255)'   
let reg = /\d+/g
let res = reg.exec(a)
console.log(res);
///
let a = 'rgb(255, 254, 255)'   
let reg = /(\d+)/g
let res
while ((res = reg.exec(a)) != null) {
  console.log(res[1]);
}

replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

match() 使用正则表达式模式对字符串执行查找,并将包含查找的结果作为数组返回

let a = 'rgb(255, 255, 255)'   
let res = a.match(/\d+/g) // ["255", "255", "255"] 返回所有值

test () 方法检查字符串是否与给出的正则表达式模式相匹配,如果是则返回 true,否则就返回 false。

语法:regexp.test(str)
手机号验证:!/^[1][3,4,5,7,8][0-9]{9}$/.test(this.phone)

正则表达式组合

用exec方法,因为它返回一个值,所以设置需要的模板数量,以[1],[2]来调用结果。

注意:输出时用模板字符串形式!!

模板: 用圆括号包裹模板

let arr = "functionFunction(555),(444)"
let name = /\((\w+)\),\((\w+)\)/g  //两个模板
let arr1 = name.exec(arr2)
console.log(arr1); //["(555),(444)", "555", "444", index: 16, input: "functionFunction(555),(444)", groups: undefined]
console.log(`${arr1[1]} ${arr1[2]}`)  //555 444

多行处理: /mg 换行+全局 ,模板字符串支持换行,对行数进行循环

let arr = `functionFunction(555),(444)
functionFunction(666),(333)`
let name = /\((\w+)\),\((\w+)\)/mg  //两个模板
let arr1 = name.exec(arr2)
console.log(arr1); 
do {
    console.log(`${arr1[1]} ${arr1[2]}`)
} while ((arr1 = name.exec(arr)) !== null)  //555 444
    										//666 333

使用命名组: 相当于添加属性

/(?<name1>.+)/mg arr1.groups.name

let arr = `functionFunction(555),(444)
functionFunction(666),(333)`
let name = /\((?<first>.+)\),\((?<last>.+)\)/mg
let arr1 = name.exec(arr2)
console.log(arr1); 
do {
    console.log(`${arr1.groups.first} ${arr1.groups.last}`)
} while ((arr1 = name.exec(arr)) !== null)  //555 444
    										//666 333

合并数组

// 合并
      let arr11 = [1,2,3]
      let arr22 = [4,5,6]
      let arr33 = "fsgdsfg/sgsdg/jtjt"
      //1
      console.log([...arr11,...arr22]);

     // 2
      console.log(arr11.concat(arr22));
      //3
      arr11.splice(3,1,arr22)
      console.log(arr11);
      //4
      for(let i in arr22) {
        arr11.push(i)
      }
      console.log(arr11);     //[1, 2, 3, "0", "1", "2"]

     // 5
      arr11.push(...arr22)     //...arr22、forEach、for 遍历


      //6
      arr22.forEach(i => {
        arr11.push(i)
        console.log(i);
      })
      console.log(arr11);

        arr33.split('/')  //切分
        arr11.join('/')   //加入

        //7
      Array.prototype.push.apply(arr11,arr22)          //依次push
        console.log(arr11);
      console.log(Array.prototype.slice.call(arr33));

isNaN()

测试不属于NaN数值的值

console.log(isNaN(10)); //false

isFinite()

判断一个值是不是在有限大与有限小之间。

console.log(isFinite(resule));  

Boolean()

将其它类型值转换为布尔类型,如空,null,undefined等为false

let b = "hello"
let a = Boolean(b); //ture

原型

obj.hasOwnProperty(prop)

obj.hasOwnProperty(prop) 方法功能就是判断obj上有没有prop这个属性
注意:此属性是自身属性,原型链上的属性不属于此属性

function shallow(obj) {
      let target = {}
      for (let i in obj) {
        if(obj.hasOwnProperty(i))  {
          target[i] = obj[i]
        }
      }
      return target
    }

进制转换

parseInt(): 字符串str按照radix进制编码方式转换为10进制返回,没有radix,默认为10;

  let res = parseInt(str, 2) //str='1100000' 输出: 192

toString(): 返回表示该数字的指定进制形式的字符串。(把10进制的数据转为指定进制,并以字符串形式输出);radix支持 [2, 36] 之间的整数。默认为10;

 let x = 10; x.toString(2) // 1010

数值转换

p36–第四版

instanceof

obj instanceof Date 
    意思是: Date的propertypeof是否在obj的原型链上

Number() pareseInt() parsefloat()

toString()

1.返回自身一个副本

let lang = "java";
console.log(lang.toString())  //java  

2.返回当前字符等价物

let age = 11;
let age1 = age.toString(); //11 

3.参数进制数的字符串

let num = 10;
console.log(num.toString(2)); //"1010"

toUpperCase() toLowerCase()

把字符串转换为大小写

var txt="Runoob";
document.write(txt.toLowerCase() + "<br>"); //runoob
document.write(txt.toUpperCase());  //RUNOOB

Object.defineProperty()

使用符号作为属性

let s1 = Symbol('foo'),
    s2 = Symbol('goo'),
    s3 = Symbol('hoo'),
    s4 = Symbol('joo');

let o = {[s1]: 'foo val'};
console.log(o);   //{Symbol(foo): "foo val"}

Object.defineProperties(o,{
    [s3]:{value:'hoo val'},
    [s4]:{value:'joo val'}
});
console.log(o);//{Symbol(foo): "foo val", Symbol(hoo): "hoo val", Symbol(joo): "joo val"}

Math.pow()

指数操作

console.log(Math.path(3,2))//9
let s = 3;
s ** = 2;
console.log(s); //9

JSON.parse JSON.stringity

JSON.stringify`会处理的几种类型: `String, Number, Boolean, null, Array, Object`
不会处理的几种类型: `Date, RegExp, undefined, Function
	<script type="text/javascript">
		//序列化,js对象转换成json字符串
		var obj={'name':'tim','age':16}
		console.log(obj,typeof(obj))
		console.log(JSON.stringify(obj),typeof(JSON.stringify(obj)))

		//反序列化   json字符串转换成js对象
		console.log('********反序列化*********')
		var jsonString='{"name":"tim","age":18}'
		console.log(jsonString,typeof(jsonString))
		console.log(JSON.parse(jsonString),typeof(JSON.parse(jsonString)))




	</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtHHkwW2-1632368985381)(JS.assets/image-20210221155333401.png)]

HTML DOM Event 对象

event.preventDefault(); 阻止默认的点击事件执行 ,一般用于按钮,对按钮事件进行重新编辑,比如默认为提交数据,需求则是在数据添加警告,则设计方法

$('#register_form').on('submit', function (e) {
      e.preventDefault() //阻止默认动作
      var formData = $(this).serialize()  //通过序列化表单值,创建 URL 编码文本字符串, eamil=fewfew&nickname=fewgwewg
      $.ajax({
        url: '/register',
        type: 'post',
        data: formData,
        dataType: 'json',
        success: function (data) {
          var err_code = data.err_code
          if (err_code === 0) {
            // window.alert('注册成功!')
            // 服务端重定向针对异步请求无效
            window.location.href = '/'
          } else if (err_code === 1) {
            window.alert('邮箱已存在!')
          } else if (err_code === 2) {
            window.alert('昵称已存在!')
          } else if (err_code === 500) {
            window.alert('服务器忙,请稍后重试!')
          }
        }
      })
    })

判断类型

https://zhuanlan.zhihu.com/p/89238840

typeof

Object.prototype.toString.call()

obj instanceof Object

Array.prototype.isPrototypeOf()

js错误类型

https://www.cnblogs.com/yanze/p/5997489.html

1.SyntaxError(语法错误)

解析代码时发生的语法错误

eg:var 1a;

Uncaught SyntaxError: Unexpected number

2.ReferenceError(引用错误)

a.引用了一个不存在的变量

eg: console.log(a);

Uncaught ReferenceError: a is not defined

b.将变量赋值给一个无法被赋值的对象

eg:console.log()= 1;

Uncaught ReferenceError: Invalid left-hand side in assignment

3.RangeError(范围错误)

超出有效范围

eg:var a= new Array(-1);

Uncaught RangeError: Invalid array length

4.TypeError(类型错误)

a.变量或参数不是预期类型,比如,对字符串、布尔值、数值等原始类型的值使用new命令,就会抛出这种错误,因为new命令的参数应该是一个构造函数。

eg: var a= new 123;

Uncaught TypeError: 123 is not a function

b.调用对象不存在的方法

eg:var a;a.aa();

Uncaught TypeError: Cannot read property ‘aa’ of undefined

5.URLError(URL错误)

与url相关函数参数不正确,主要是encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数。

eg: decodeURI(’%2’)

Uncaught URIError: URI malformed

6.EvalError(eval错误)

eval函数没有被正确执行

JS基础

for in key

	function aa(){
		let def = new Array();
		for(let i =1;i<6;i++){
			let k = i+6;
			def[k] = i+1;
		}
		for(let b in def){
			console.log(b);
		}
        for(let b in def){
			console.log(def[b]);
		}
	}//7,8,9,10,11 //2,3,4,5,6

for循环之外定义def数值属于全局变量。 而k则是局部变量,

所以for(let k in def)只是循环def中元素个数的数量。 重点在循环次数,不在循环内容

1.概述

https://blog.csdn.net/kese7952/article/details/79357868

ECMAScript 是javasctipt的一个标准

最新版本已经到6了

大部分浏览器支持es5

2.规范

script放在head 或者body

一定要双标签

多行备注/****/

严格区分大小写

console.log(num) 打印变量

source,分步操作

application 存放在浏览器

3.数据类型

number

Nan //not a number
Infinity //无限大

比较运算符

== 等于 (类型不同。值一样也为ture)
=== 绝对等于(类型一样,值一样 ture)
  • NaN===NaN 与所有的数值都不相等,包括自己
  • 只能通过isNaN(NaN) 为true

尽量避免浮点数,精度问题。

console.log(Math.abs(1/3-(1-2/3))<0.000001) // 确定精度可以

null和undefined

数组

js中数组内不需要相同类型对象。

var arr = [1,2,5,4,56,'ddd',null,ture]


数组越界,输出undefined

对象

对象大括号

var person = {
    name:"ddd",
    age:5,
    tags:['dd','ddd']
}

1.字符串

1.正常字符串 使用单引号或双引号包裹。

2.转义字符 ’a\‘’ 输出a‘

\'
\n 
\t 空格
\u4e2d 中  Unicode字符
\x41 Ascall字符

3.多行字符串编写

var msg = `  //tab键上面
    hello
    world
`

4.模板字符串

let name = "dsghj";
let mad = `你好,${name}`

5.获得属性某状态

console.log(name.length)

6.方法

//这里是方法,不是属性
console.log(name.toUpperCase()) //大小写转换
console.log(name.indexOf('d'))// 元素下标 0
console.log(name.substring(1)) //截取,sghj 
console.log(name.substring(13)) //sg 包括前不包括后 

2.数组

Array可以包含任意数据类型

1.长度可编辑,但是arr.length变小。内容则会丢失部分

2.slice()类似substring() 截取Array一部分

3.arr.push(‘a’,‘b’)压入元素 到最后面 arr.push() 踢出尾部元素

4.arr.unshift() 头部压入 shift()弹出头部

5.排序 sort() 可对字符排序(依据Ascall) 反转reverse()

6.concat(1,2,3)加入拼接输出,但是不对数组有影响

7.arr.join(’-’)
“1-1-2-A-B”
arr
(5) [1, 1, 2, “A”, “B”] 添加连接符

8.arr.splice(0,0,“排球”) 三个参数,[第几位,删去多少个数,添加元素]

arr.splice(1,2,"dd","aa")
		console.log(arr)
		console.log(arr.indexOf("1"))

3.严格检查模式

'use strict'// 写在script第一行
let i = 1;

预防js的随意性问题

局部变量使用let定义

4.对象

JavaScript中所有的键都是字符串,值是任意对象

1.动态的删减属性

delete person.age   //减
true

person.age = "hh"  //增加
"hh"

2.判断一个属性是否在对象中hasOwnProperty()

person.hasOwnProperty('age')
true

5.流程控制

1.数组遍历 for in /// for of

var arr = [1,2,5,6,3,6]

for(let num in arr){
    console.log(arr[num])
}
或者
for(let num of arr){
    console.log(num)
}

6.Map Set

Map:

var map = new Map([['ff',12],['dd',13],['ee',15]])
var named = map.get('ff')
console.log(named);
map.set('ggg',2)
console.log(map)

for(let num of map){    //遍历map
    console.log(num)
}

Set:无序不重复

var set = new Set([3,2,14,454,4,4,4,4]);
console.log(set)

1.js:36 Set(5) {3, 2, 14, 454, 4}

判断数组

https://www.cnblogs.com/lingdu87/p/9152806.html

4.函数及面对对象

1.定义函数

var abs = function(x){
    //收到抛出异常
    if(typeof x!=='number'){
        throw 'Not a Number'
    }
}

arguments

arguments:代表传递进来的所有参数x,是一个数组

var abs = function(x){
    //收到抛出异常
    if(typeof x!=='number'){
        throw 'Not a Number'
    }
        for(let i=0;i<arguments.length;i++){
        console.log(arguments[i]);
    }
}

rest

获取除了已经给定的参数外的所有参数, 只能写在后面

function aaa(a,b,...rest){
    console.log(a)
    console.log(b)
    console.log(rest)
}
aaa(1,2,5,4,6,36,245,56,6)
1
2
(7) [5, 4, 6, 36, 245, 56, 6]

2.变量的作用域

如果两个函数使用同一变量名,互不相干

let与var区别之一:var可以被作用域提升,即后面定义变量前面不会出错,输出undefined

const与let的区别:const声明变量使必须同时初始化变量,且不能修改。

let声明for循环变量,const声明for循环不被修改的变量。

**总结:**一般声明不用var

for (const key in {a:1,b:2}) {
    console.log(key);
    }//a b

for (const value of [1,2,3,4,5,6]) {
    console.log(value)
}// 1 2 3 4 5 6
function qj(){
    var x = 1;

    function qqj(){
        var x = 'a'
        console.log('1'+x)

    }
    console.log('2'+x)
    qqj()
}
qj()

21
1a

调用外部函数不会运行内部函数,调用内部变量,由内向外查找,会屏蔽外部变量,就近原则

提升变量的作用域

function ddh(){
    var y;
    var x='x'+y;
    y='y'
    console.log(x)
}
ddh()

结果:xundefined

说明:js执行引擎,自动提升了y的声明,但不会提升变量y的赋值;

所以需要养成规范:所有变量定义都放在函数头部,便于修改。

function ddh(){
    var y ='y',
        x = 'x'+y,
        z,x,y;//undefined
}

定义在类里面的则都可以使用

var x=55;
function asd(){
    console.log(x)
}
asd()
console.log(x+1)

55
56

全局对象window

alert(x)
alert(window.x)//默认所有全局变量 都会自动绑定window对象下
window.alert(x)

规范

当不同的js文件使用同一全局变量,就有冲突。所以在每个js文件定义不同全局变量,把所有代码放入自己定义的唯一变量内

//唯一全局变量
var person = { 
    name:"ddd",
    age:5,
    tags:['dd','ddd']
}
person.name = "ddfgg";

局部作用域

function asd(){
    for(let i=0;i<100;i++){
        console.log(i)
    }
    console.log(i+1) //Uncaught ReferenceError: i is not defined
}

如果是var i,则console.log(i+1) 能输出结果

预编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CvyNMu7z-1632368985388)(C:\Users\11490\AppData\Roaming\Typora\typora-user-images\image-20210517214909033.png)]

作用域与闭包

JS的作用域

作用域的概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aCPTDTJv-1632368985390)(JS.assets/image-20210421090304311.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S638Yr11-1632368985391)(JS.assets/image-20210421090428867.png)]

闭包

https://www.jianshu.com/p/9fc2e3ee4efe

闭包能够访问外部函数的变量,即使变量已经离开它所创建的环境,是因为外部变量会被闭包的作用域对象所持有。闭包这种特性实现了嵌套函数之间数据的隐式传递。

作用域链: 会被保存到一个隐式的属性中央[{scope}]这个属性是我们用户访问不到的,但是的确是存在的人,让js引擎来访问的, 里面存储的就是作用域链

一:预编译:js在运行的时候,会为每一个执行函数分配内存空间,该空间就是作用域对象(scope)。

二、执行:调用函数时,函数中的变量会依次存储到该作用域对象中。所以当内部函数用到需要外部变量时,就会在作用域链中向外找,如果找不到,那抛出错误referenceError。

闭包的缺点:

因为使用闭包,可以使函数在执行完后不被销毁,保留在内存中,如果大量使用闭包就会造成内存泄露,内存消耗很大

对代码的作用域分析

function a() {         //可以用节流和防抖函数来分析
    let aa = 345
    function b() {
    	let bb = 123
        aa = 0
    }
    return b
}
a()

一、定义a,放入作用域顶端,全局变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r905RADt-1632368985392)(JS.assets/2021-04-21_092828.png)]

二、执行a

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kSPSZowk-1632368985393)(JS.assets/2021-04-21_092903.png)]

三、定义b

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9cBybwm7-1632368985394)(JS.assets/2021-04-21_092918.png)]

四、执行b

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zo8MSNlm-1632368985395)(JS.assets/image-20210421103003825.png)]

五、当a执行完后,b定义的线依然存在,所以a执行的线被剪断后(a执行完后),b依然可以用到a执行时的变量,a=123

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6uizeOoT-1632368985396)(JS.assets/image-20210421103715492.png)]

单例模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D4yYfEko-1632368985397)(JS.assets/2021-04-21_173400.png)]

理解含义

js没有c++中class的public和private的区分(ES5中),只有全局变量和局部变量这两种,引入闭包就使得js有了私有变量这一概念。
下面给出闭包的定义:闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。调用完一次后,函数没有被释放,整条作用域链上的局部变量都将得到保留。
在本质上,闭包就是将函数内部和函数外部连接的一座桥梁

四种闭包书写方式(倾向于第四种)

function a(){        //   闭包方式一    
			var tim=5
			return function(){
				console.log(tim)
			}
			
		}
		
		a()();
		
		
		function a(){        //   闭包方式二
			var tim=5
			var b=function(){
				console.log(tim)
			}
			return b
		}
		
		var b=a()
		b()
		
		
		var a=(function (){        //   闭包方式三
			var tim=9
			var b=function(){
				console.log(tim)
			}
			return b
		})();
		
		a()
		
		
		var a=(function (){        //   闭包方式三_1,返回内部函数
			var tim=9
			return function(){
				console.log(tim)
			}
			
		})();
		
		a()       //这种比较好,原因是有() 提醒这是闭包,然后调用只需要一个括号,如a()

//输出5.5.9.9

与平时多一个调用函数步骤

function rec(){            //平时
	let dd=4;
	return dd;
};
let le =rec();		//声明le为rec(),也可以不声明,直接alert(rec())
alert(le)              //4
function rec(){           //闭包
	let dd=4;
	return function(){
		return dd;
	};
	};

// let le =rec()
alert(le()) 
alert(rec()())         //4
rec()()                //返回空,其实是返回的,只是没有console.log输出4

闭包有什么好处呢?

1.希望一个变量长期驻扎在内存中

2.避免全局变量的污染

3.私有成员的存在

我们使用全局变量也可以实现同样的效果

js中的super

1.this和super的区别:

  • this关键词指向函数所在的当前对象
  • super指向的是当前对象的原型对象

2.super的简单应用

[复制代码](javascript:void(0)😉

const person = {
    name:'jack'
}

const man = {
    sayName(){
        return super.name;
    }
}

Object.setPrototypeOf( man, person );

let n = man.sayName();

console.log( n )    //jack

[复制代码](javascript:void(0)😉

3.super的另类实现

super.name  
等同于   
Object.getPrototypeOf(this).name【属性】  
等同于   
Object.getPrototypeOf(this).name.call(this)【方法】

4.super中的this指向(易混淆)

super.name指向的是原型对象person 中的name,但是绑定的this还是当前的man对象。

[复制代码](javascript:void(0)😉

const person = {
    age:'20多了',
    name(){
        return this.age;
    }
}

const man = {
    age:'18岁了',
    sayName(){
        return super.name();
    }
}

Object.setPrototypeOf( man, person );

let n = man.sayName();

console.log( n )    //18岁了

[复制代码](javascript:void(0)😉

Object.getPrototypeOf(this).name指向的是person的name,绑定的this也是person

[复制代码](javascript:void(0)😉

const person = {
    age:'20多了',
    name(){
        return this.age;
    }
}

const man = {
    age:'18岁了',
    sayName(){
        return Object.getPrototypeOf(this).name();
    }
}

Object.setPrototypeOf( man, person );

let n = man.sayName();

console.log( n )        //20多了

[复制代码](javascript:void(0)😉

Object.getPrototypeOf(this).name.call(this)指向的是person的name,不过通过call改变了函数的执行上下文,所以this指向的还是man

[复制代码](javascript:void(0)😉

const person = {
    age:'20多了',
    name(){
        return this.age;
    }
}

const man = {
    age:'18岁了',
    sayName(){
        return Object.getPrototypeOf(this).name.call(this)
    }
}

Object.setPrototypeOf( man, person );

let n = man.sayName();

console.log( n )    //18岁了

[复制代码](javascript:void(0)😉

防抖与节流函数

防抖

当持续连续触发事件,一定时间内没有再触发时间,事件处理函数才会执行一次.

实际运用: 搜索框、页面大小变化时,echart图表随之变化

<div>
    <input type="text" id="input">
  </div>
  <script>
    //基本方法
    let input = document.getElementById('input')
    let timer = null
    function debounce() {
      clearTimeout(timer)
        timer = setTimeout(() => {
        console.log(input.value);
      }, 1000)
    }
    input.addEventListener('keyup', debounce)
        
        
    //闭包方法
    function debounce() {
      let timer = null
      console.log(123);   //123 只输出一个
      return function() {
        clearTimeout(timer)
        timer = setTimeout(() => {
        console.log(input.value);
      }, 500)
    }
  }
    input.addEventListener('keyup',debounce())
  </script>
   
    

代码分析

input.addEventListener(‘keyup’, debounce()) 的步骤:

  • 先执行debounce函数,此时如果在执行函数则只需要写函数名即可,即:input.addEventListener(‘keyup’, debounce)

  • 创建timer的全局作用域,输入123,消除debounce

  • input.addEventListener(‘keyup’, debounce()), 此后只调用外层创建好的timer,不执行(创建timer的全局作用域,输入123),执行return function。

let ddd = debounce()
input.addEventListener('keyup',function() {
       ddd()
      })   

函数外层有一个function包着,调用时就应该函数名加括号!!

节流

当持续触发事件的时候,保证一段时间内只调用一次事件

设置个闭包来限制timer 作用域。

应用: 节流防抖 图片懒加载

<button id="button">Z点击</button>

document.getElementById('button').onclick = thro(handle, 1000)
    function handle() {
      console.log(456);
    }
    function thro(fn, delay) {
      let timer = true
      return function() {
        if(!timer) {
          return false
        }
        timer = false
        setTimeout(function() {
          fn()
          timer = true
        }, delay)
      }
    }

this

this 永远指向函数运行时所在的对象,而不是函数创建时所在的对象。
匿名函数和不处于任何对象中的函数,this指向window.
call,appply,with 指的this 是谁就是谁。
普通函数调用,函数被谁调用,this就指向谁。

箭头函数和this

箭头函数this指向定义位置时this的指向

匿名函数中的this在严格模式下指向undefined,非严格模式指向window

旧的this是谁调用指向谁,如果是传回调函数的话,会导致函数定义的人不确定this是谁,箭头函数相当于让定义函数的人确定this是谁

因为最后调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数。

一、ES5中

其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象

var name = "windowsName";
function a() {
 var name = "Cherry";
 console.log(this.name);   // windowsName
 console.log("inner:" + this); // inner: Window
}
a();   

a是函数,调用a函数的是window! 所以this指向window

var name = "windowsName";
var a = {
 // name: "Cherry",
 fn : function () {
  console.log(this.name);  // undefined
 }
}
window.a.fn();

​ fn是函数,调用fn函数的最后一个对象是a对象! 所以this指向a,但是这里a对象对name没有定义,所以结果为undefined

var name = "windowsName";
var a = {
 name : null,
 // name: "Cherry",
 fn : function () {
  console.log(this.name);  // windowsName
 }
}
var f = a.fn;
f();

这里虽然 f() 复制了 fn() ,但是没有改变调用f()的事实,调用f函数的最后一个对象是window对象!,所以this指向window,返回windowsName

二、箭头函数的this

原理:

  • 箭头函数的this是在定义函数的时候绑定的,而不是在执行函数的时候绑定。
  • 箭头函数中,this指向固定化,并不是因为箭头函数内部有绑定this 的机制,实际上箭头函数根本就没有自己的this,导致内部this就是外层代码块的this,所以不能被当做构造函数。
  • 所谓的定义时候绑定,就是this是继承自父执行上下文中的this,比如这里的箭头函数中的this.x,箭头函数本身与say平级以key:value的形式,也就是箭头函数本身所在的对象为obj,而obj的父执行上下文就是window,因此这里的this.x表示window.x
let x = 11;
let obj = {
    x: 22,
    say: () => {
        console.log(this.x);
    }
}
obj.say()

第一:首先记住:调用 setTimeout 的对象是 window!

第二:箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。意思就是this向外找this!

const a1 = {
      aa() {
        setTimeout(function(){
          console.log(this);         //window
        }),
        setTimeout(() => {			//aa() 返回对象
          console.log(this);
        })
      }
    }
var name = "windowsName";
var a = {
 name : "Cherry",
 func1: function () {
  console.log(this.name)  
 },
 func2: function () {
  setTimeout( () => {
   this.func1()
  },100);
 }
};
a.func2()  // Cherry

this.func1()等于a.func1(),因为this向外找this,找到了a对象

第三:可以用_this = this 来替代

先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this,这样 _this 就不会改变了。

var name = "windowsName";
var a = {
 name : "Cherry",
 func1: function () {
  console.log(this.name)  
 },
 func2: function () {
  var _this = this;            //_this为a对象
  setTimeout( function() {
   _this.func1()
  },100);
 }
};
a.func2()  // Cherry

三、apply、call、bind 函数

fun.apply(thisArg, [argsArray])

thisArg:在 fun 函数运行时指定的 this 值。

argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。

写法:

this.func1().apply(a);

this.func1().call(a)

this.func1().bind(a)( )

var a = {
 name : "Cherry",
 func1: function () {
  console.log(this.name)
 },
 func2: function () {
  setTimeout( function () {
   this.func1()
  }.apply(a),100);
 }
};
a.func2()   // Cherry

参考:https://www.jb51.net/article/124024.htm

前端的this,是会发生变化的。this主要四种常见方式有:

赋值、深浅拷贝

浅拷贝 与 赋值的区别

  • 赋值:当我们把一个对象赋值给一个新的变量时,赋值的是该对象在栈中的地址,该地址指向堆中的数据,所以两个对象联动
  • 浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但是引用类型因为共享同一内存,相互影响
  • 深拷贝: 在堆中开辟一个新的区域存放对象,对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响
类型是否和原对象指向同一对象修改基本类型是否同一改变引用类型是否同一改变
赋值
浅拷贝
深拷贝

浅拷贝的实现方式:仅适用于对不包含引用对象的一维数组的深拷贝

  • …mapstate 辅助函数的对象展开符

  • lodash clone

  • concat

  • Object.assign()

深拷贝:

JSON.parse()与 JSON.stringify() 但是JSON.stringify(…) 在对象中遇到 undefined 、 function 和 symbol 时会自动将其忽略, 在数组中则会返回 null (以保证单元位置不变)。

  • $.extend()
  • deepClone

let person = {
      name: '一把实收',
      kids: ['123',[12,45],"gwsd"],
      function() {},
      date: new RegExp('\\w+')
    }
//赋值
    let person1 = person
    console.log("person1",person1);
    
    person1.name = "我是傻逼"
    person1.fuck = "fuck"
    console.log(person1);
    console.log("person",person);
//浅拷贝
	function shallow(obj) {
      let target = {}
      for (let i in obj) {
        if(obj.hasOwnProperty(i))  {
          target[i] = obj[i]
        }
      }
      return target
    }
    let person1 = shallow(person)
    console.log("person1",person1);
    person.name = "牛逼"
    person1.name = "我是傻逼"
    person1.fuck = "fuck"
    person1.kids[0] = 456
    console.log(person1);
    console.log("person",person);
//深拷贝
function shallow(obj) {
      let target = {}
      if(obj === null) return obj
      if(obj instanceof Date) return new Date(obj)
      if(obj instanceof RegExp) return new RegExp(obj)
      if(typeof obj !== "object") return obj
      for (let i in obj) {
        if(obj.hasOwnProperty(i))  {
          target[i] = shallow(obj[i])
        }
      }
      return target
    }
    let person1 = shallow(person)
    console.log("person1",person1);
    person.name = "牛逼"
    person1.name = "我是傻逼"
    person1.fuck = "fuck"
    person1.kids[0] = 456
    person.kids[0] = 456
  
    console.log(person1);
    console.log("person",person);

数组扁平化

arguments对象

在函数体内,标识符arguments是指向实参对象的引用,实参对象是一个类数组对象 arguments[0],arguments.length

arguments是什么?
  答:1:arguments是收到的实参副本
  在词法分析中, 首先按形参形成AO的属性,值为undefined
  当实参传来时, 再修改AO的相应属性.
  2:并把所有收到实参收集起来,放到一个arguments对象里
  t(a,b,c){},
  调用时: t(1,2,3,4,5) 5个参数
  此时 , AO属性只有a,bc,3个属性, arguments里有1,2,3,4,5, 所有的值

对于超出形参个数之外的实参, 可以通过arguments来获得
  3:arguments 的索引 从 0, 1,2,…递增,与实参逐个对应
  4:arguments.length 属性代表实参的个数
  5:arguments一定不是数组, 是长的比较像数组的一个对象,虽然也有length属性
  6:arguments每个函数都会有,因此,arguemnts只会在内部找自身的arguments,
  无法引用到外层的arguments

 // 求圆形面积,矩形面积, 三角形面积
  function area () {
  if(arguments.length == 1) {
  alert(3.14 * arguments[0] * arguments[0]);
  } else if(arguments.length == 2) {
  alert(arguments[0] * arguments[1]);
  } else if(arguments.length == 3) {
  alert(arguments[0] + arguments[1] + arguments[2]);
  } else {
  return null;
  }
  }
  area(10,20,30);


function fn() { 
      console.log(arguments);//Arguments(6) [1, 3, 4, 5, 64, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
      console.log(...arguments);  //1,3,.....
      console.log([...arguments].slice(1)); //[1,3,....]
    }
    fn(1,3,4,5,64,4)

promise

https://zhuanlan.zhihu.com/p/355143116

回调函数分类

1. 同步回调: 
    理解: 立即执行, 完全执行完了才结束, 不会放入回调队列中
    例子: 数组遍历相关的回调函数 / Promise的excutor函数
2. 异步回调: 
    理解: 不会立即执行, 会放入回调队列中将来执行
    例子: 定时器回调 / ajax回调 / Promise的成功|失败的回调

callback

function doSomething(msg, callback){
    alert(msg);
    if(typeof callback == "function") 
    callback();
 } 
doSomething("回调函数", function(){
    alert("匿名函数实现回调!");
 }); 

**含义:回调函数,将一个函数作为参数传递给另一个函数。 **

缺点:

1、没有return

2、形成回调地狱

promise是什么?

1、主要用于异步计算
2、可以将异步对象和回调函数脱离开来,通过.then方法在这个异步操作上绑定回调函数,Promise可以让我们通过链式调用的方法去解决回调嵌套的问题,promise.all这样的方法存在,可以让同时执行多个操作变得简单。

Promise构造函数是同步还是异步执行,then呢?

promise构造函数是同步执行的,then方法是异步执行的

console.log(1)
let a = new Promise((res,rej) => {
   console.log(2);
});
console.log(3);
let b = new Promise((res,rej) => {
    console.log(4);
});
console.log(5);
输出的是12345

console.log(1)
let a = new Promise((res,rej) => {
    console.log(2);
    res();
});
console.log(3);
let b = new Promise((res,rej) => {
    console.log(4);
    res();
});
console.log(5);
a.then(() => {
    console.log(6)
})
b.then(() => {
    console.log(7)
})
答案是1234567

优势

2、并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
代码风格,容易理解,便于维护
3、多个异步等待合并便于解决

步骤

1、resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
2、reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

promise有三个状态:
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;
promise状态一经改变,不会再变。

Promise对象的状态改变,只有两种可能:
从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AhLpD9Ui-1632368985403)(%E5%9B%BE%E7%89%87/JS/v2-0496e6978cf8bbb595cd13c63e6c1a94_720w.jpg)]

错误处理

Promise会自动捕获内部异常,并交给rejected响应函数处理。

错误处理两种做法:

第一种:reject(‘错误信息’).then(() => {}, () => {错误处理逻辑})
第二种:throw new Error(‘错误信息’).catch( () => {错误处理逻辑}) ,推荐使用第二种方式,更加清晰好读,并且可以捕获前面所有的错误(可以捕获N个then回调错误),catch能捕获Error,then也可以捕获Error

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3ID6soI-1632368985404)(JS.assets/15311104-d93b7cf287478e43.png)]

Promise.all() 批量执行

Promise.all([p1, p2, p3])用于将多个promise实例,包装成一个新的Promise实例,返回的实例就是普通的promise
它接收一个数组作为参数
数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变

当所有的子Promise都完成,该Promise完成,返回值是全部值得数组!!!

有任何一个失败,该Promise失败,返回值是第一个失败的子Promise结果!!

  function cutUp(){
        console.log('开始切菜。');
        var p = new Promise(function(resolve, reject){        //做一些异步操作
            setTimeout(function(){
                reject('切好的菜');
            }, 1000);
        });
        return p;
    }

    //烧水
    function boil(){
        console.log('开始烧水。');
        var p = new Promise(function(resolve, reject){        //做一些异步操作
            setTimeout(function(){
                resolve('烧好的水');
            }, 1000);
        });
        return p;
    }

    Promise.all([cutUp(), boil()])
        .then((result) => {
            console.log('准备工作完毕');
            console.log(result);
        }).catch((result) => {
          console.log('准备工作失败');
            console.log(result);
        })

开始切菜。
开始烧水。
准备工作失败
切好的菜

Promise.race()

顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

封装对象

const obj = {
    name: 'shui'
}
Vue.prototype.obj = obj     //vue.protoytype vue的原型
console.log(obj.name)    //shui
new Promise((resolve, reject) => {
      setTimeout(function() {
        resolve('Hello')
      },1000)
    }) .then(data => {
      console.log(data);
      return data + '123';
    }).then(data => {
      console.log(data);
      return Promise.reject(data + 'error');
    }).then(data =>{
      console.log(data);
    }).catch(data => {
      console.log(data);
      return data + '333';
    }).then(data => {
      console.log(data);
    })

new Promise(resolve => {
    setTimeout(() => {
      resolve('hello')
    }, 2000)
  }).then(val => {
    console.log(val) //  参数val = 'hello'
    return new Promise(resolve => {
      setTimeout(() => {
        resolve('world')
      }, 2000)
    })
  }).then(val => {
    console.log(val) // 参数val = 'world'
  })

若干问题

1、 如何改变promise的状态?
    
    * 1.修改promise状态的几种方式??
*1): resolve(value) : 如果当前状态是pending就会变为resolved
*2): reject(reason) : 如果当前状态是pending就会变为rejected
*3): 抛异常: 如果当前是pending就会变为rejected
    
    
    
2、一个promise指定多个成功/失败回调函数, 都会调用吗?
    
    当promise改变为对应状态时是都会调用的
    const p2 = new Promise((resolve,reject) => {
        //假设异步任务执行成功
        resolve('哈哈!异步任务执行成功啦');
    })
    p2.then(
    	//value:哈哈!异步任务执行成功啦
        value => {console.log('value:' + value);}
    )
    p2.then(
    	//value2:哈哈!异步任务执行成功啦
        value => {console.log('value2:' + value);}
    )

    
3、promise.then()返回的新promise的结果状态由什么决定?
    由then()指定的回调函数执行的结果决定


4、改变promise状态和指定回调函数谁先谁后?
    都有可能 
//常规:先指定回调函数,后改变的状态
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('成功1') //后改变的状态(同时指定数据),异步执行回调函数
        }, 1000)
    }).then(//先指定回调函数,保存当前指定的回调函数
        value => {
            console.log('value1', value)
        },
        reason => {
            console.log('reason1', reason)
        }
    )
 
    //如何向改变状态,再指定回调函数
    new Promise((resolve, reject) => {
        resolve('成功2') //先改变的状态(同时指定数据)
    }).then(//后指定回调函数,异步执行回调函数
        value => {
            console.log('value2', value)
        },
        reason => {
            console.log('reason2', reason)
        }
    )


    
    
5、promise如何串连多个操作任务?
    通过then()的链式调用
    
6、当.then()中有两个回调函数时,只取最前面的
	p.then(
        value => {
            console.log(88888)
          	return value+5;},
        reason => {
            console.log('reason', reason);
            // return Promise.resolve(reason)
        }
    )///88888
    
7、promise异常传(穿)?中断promise链?
中断办法:在回调函数中返回一个pendding状态的promise对象
返回一个这个:new Promise(()=>{}

.catch(reason=>{
        console.log("onRejected1()",reason)

        //注意:没有return的 时候下面的then执行的是成功
        // Promise.reject(reason)

        //下面的then走reason那一条路的 方法
        // throw  reason
        // return Promise.reject(reason)

        //中断:返回一个pedding的promise
        return new Promise(()=>{})
        // return 4
    })

手写promise

1、需要三个准备 完成 拒绝状态,通过状态的变化执行相应的函数

2、需要value值来传递

3、resolve与reject用类方法来写

async/await yield

​ https://zhuanlan.zhihu.com/p/112081953

只是一个语法糖

**async/await **:

两个连在一起用,async说明该function是异步的,await是阻塞功能(函数挂起,等待返回进程),resolve也要执行。

反正就是不管异步同步,等我执行完再来。

注意 : async是微任务,await是同步任务,yield是同步任务

区别:yield两个函数直接有关联,可以拿到return值。yield需要next()去推动执行。

await只是各管各的,执行完就下一个,不管是异步还是同步。

function call(){
    console.log('call funtion');
    return new Promise(resolve=>{
        setTimeout(function(){
            console.log('call funtion timeout');
            resolve('dd');
        },1000);        
    }).then(val => {
      console.log(val);
    });

}
function normalFunction() {
    console.log('normalFunction');
    return 'data'
}
// call(function(){
//     console.log('callback');
// });
async function asynctest() {
    console.log('start');
    await call();
    await normalFunction();
    await new Promise(resolve=>{ console.log('wait result'); resolve()});
    console.log('end');
}
asynctest();

结果:
start
call funtion
call funtion timeout
dd
normalFunction
wait result
end

yield

generator函数:处理异步编程的

function *demo(),yield就是停止,执行完后暂停,如果要继续,则使用.next()函数执行下一个yield。

yield只能在generator函数中。

通过return定义最后一个状态,next()返回值是一个状态:

​ done: 是否遍历成功

​ value: 状态值


    console.log('call funtion');
    return new Promise(resolve=>{
        setTimeout(function(){
            console.log('call funtion timeout');
        },0);  
        resolve('dd');
    });

}
function normalFunction() {
    console.log('normalFunction');
    return 'data'
}
function *yieldFunc() {
    console.log('start');
    yield call();
    yield normalFunction(); 
    console.log('end');
}
let yieldData=yieldFunc();
let firstData=yieldData.next();   //call()
console.log(firstData);      //{value: Promise {<fulfilled>: "dd"}, done: false}
firstData.value.then(function(data){
    console.log(data);          //dd
});
yieldData.next();         //normalFunction()
console.log(yieldData);   //yieldFunc {<suspended>}
start
call function
{value:Promise {<fulfilled>: "dd"}, done: false}
normalFunction
yieldFunc {<suspended>}
dd
call funtion timeout

…展开运算符

https://blog.csdn.net/weixin_45031595/article/details/99695879

ajax和axios

ajax

是什么? 作用

https://zhuanlan.zhihu.com/p/98288927

https://www.cnblogs.com/theblogs/p/10553043.html

如何解决跨域问题? jsonp

https://segmentfault.com/a/1190000007665361

https://baijiahao.baidu.com/s?id=1596094573722602418&wfr=spider&for=pc

var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执⾏函数为onBack
script.src = 'http://www.....:8080/loginuser=admin&callback=onBack';
document.head.appendChild(script);
// 回调执⾏函数
function onBack(res) {
 alert(JSON.stringify(res));

axios

https://www.jianshu.com/p/eb325d70990b

封装:http.js来封装axios,api.js用来管理接口

1、环境切换 :开发环境、测试环境、生产环境

2、设置请求头,设置请求时间

3、请求拦截、响应拦截

4、封装get、post方法

1、在api.js中统一管理接口

2、在页面调用api接口

1.区别
axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样。
简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
axios是ajax ajax不止axios。

ES6

不同

1、新增模板字符串 var messag1e = 你好, ${name}, 你今年${age}岁了!

2、箭头函数

箭头函数

箭头函数相当于匿名函数,并且简化了函数定义。

1、箭头函数是匿名函数,不能作为构造函数,不能使用new

2、箭头函数不绑定arguments,取而代之用rest参数…解决

3、箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()

4、箭头函数没有原型属性


3、for…of

4、arguments对象可被不定参数和默认参数完美替代

ES6中arguments不管是在严格模式下还是不在严格模式下都不会随着实参改变。

function foo(num1,num2){    //es5这表明在非严格模式下,arguments对象总是会被更新反映出实参的变化。
    //es5这表明在严格模式下,arguments并没有随着实参的变化而变化。
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
    num1 = 'a';
    num2 = 'b';
    console.log(num1 === arguments[0]);
    console.log(num2 === arguments[1]);
}
foo(1,2); 
//true
//true
//true
//true

https://blog.csdn.net/hsany330/article/details/100519025

5、将Promise对象纳入规范中,提供原生的promise对象

let var const

1、var:

(1)函数作用域,函数中声明了var,整个函数内都有效;for循环定义var,循环外也可以拿到

(2)在全局作用域内用var声明变量,会在window对象中添加该属性,而let不会

(3)var可以变量提升,let const不行

(4)var可以重复声明,且覆盖前者,let const不行

1、let和const的相同点:

① 只在声明所在的块级作用域内有效。

② 不提升,同时存在暂时性死区,只能在声明的位置后面使用。

③ 不可重复声明。

2、let和const的不同点:

① let声明的变量可以改变,值和类型都可以改变;const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值。

const i ; // 报错,一旦声明,就必须立即初始化
const j = 5;
j = 10; // 报错,常量不可以改变

② 数组和对象等复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const只保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个复合类型的变量声明为常量必须非常小心。

7、增加的块级作用域,块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

8、引入module模块的概念 https://www.cnblogs.com/huancheng/p/9447641.html

forEach、for in 、 for of三者的区别

https://blog.csdn.net/w390058785/article/details/80522383

forEach: 对数组的每一个元素执行一次提供的函数(不能使用return、break等中断循环),不改变原数组,无返回值undefined。

for…in: 循环遍历的值都是数据结构的键值(索引)

for …of : 循环获取一对键值对中的值,一个数据结构只有部署了 Symbol.iterator 属性, 才具有 iterator接口可以使用 for of循环。例子中的obj对象没有Symbol.iterator属性 所以会报错。

哪些数据结构部署了 Symbol.iteratoer属性了呢?

数组 Array
Map
Set
String
arguments对象
Nodelist对象, 就是获取的dom列表集合

https://blog.csdn.net/one_girl/article/details/80192899?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.baidujs&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.baidujs

原型链

https://www.cnblogs.com/loveyaxin/p/11151586.html

原型链实际上就 是构造函数、原型和实例的关系,当对象找不到属性时,就往对象的原型与寻找属性,当找不到时就继续往对象的原型的原型寻找属性,依次向下找。

其实原型对象就是通过 Object 构造函数生成的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ICFHCTiw-1632368985404)(JS.assets/850375-20190708153139577-2105652554.png)]

https://juejin.cn/post/6844903885488783374

Generator函数

https://blog.csdn.net/qq_36667170/article/details/105157081

Generator 函数是 ES6 提供的一种异步编程解决方案。有人称为生成器。

function* greet() {
  console.log(123);
  yield 'ok'
  console.log(456);
  yield 'ook'
  console.log(789);
  return 'oook'
}

let x = greet()    
x.next()                  //输出 123, 遇到yield停止
x.next()                  //输出456



BFC概念

call、apply、bind

区别

1.非严格模式

如果不传参数,或者第一个参数是nullnudefinedthis都指向window

2.严格模式

第一个参数是谁,this就指向谁,包括null和undefined,如果不传参数this就是undefined

call、apply区别:所以 apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)()   // 3

实现

call

Function.prototype.call = function(content) {
    //判断调用call是否是一个函数,this指向调用call的
    if(typeof this!== 'function') {
        throw new TypeError("Not a function")
    }
    //不传参默认为window
    const content = content || window;
    //this指向对象调用的函数
    content.func = this;
    //使伪数组转化为数组
    const args = [...arguments].slice(1)
    //调用函数
    const res = content.func(...args)
    //删除函数
    delete content.func
    return res
}

apply

Function.prototype.apply1 = function(content) {
    if(typeof this!== "function") {
        throw new TypeError("Not a function")
    }
    let res
    const con = content || window
    con.func = this
    if(arguments[1]) {
        res = con.func(...arguments[1])
    }else {
        res = con.func()
    }
    delete con.func
    return res
}

bind

    Function.prototype.myBind = function(context){
      // 判断是否是一个函数
      if(typeof this !== "function") {
        throw new TypeError("Not a Function")
      }
      // 保存调用bind的函数
      const _this = this 
      // 保存参数
      const args = Array.prototype.slice.call(arguments,1)
      // 返回一个函数
      return function F () {
        // 判断是不是new出来的
        if(this instanceof F) {
          // 如果是new出来的
          // 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化
          return new _this(...args,...arguments)
        }else{
          // 如果不是new出来的改变this指向,且完成函数柯里化
          return _this.apply(context,args.concat(...arguments))
        }
      } 
    }


 function foo(c, d) {
      this.b = 100
      console.log(this.a)
      console.log(this.b)
      console.log(c)
      console.log(d)
    }
    var func = foo.es3Bind({a: 1}, '1st');
    func('2nd');  // 1 100 1st 2nd
    func.call({a: 2}, '3rd'); // 1 100 1st 3rd
    new func('4th');  //undefined 100 1st 4th

https://blog.csdn.net/u010377383/article/details/80646415

symbol

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。

定时器滚动图片

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			*{margin:0 ;padding: 0;}
			#banner {
				position: relative;
				width: 37.5rem;
				height: 9.375rem;
				margin: 100px auto;
				overflow: hidden;
			}
			#banner ul {
				position: absolute;
				width: 1200px;
				left: 0;
				top: 0;
			}
			#banner li{
				width: 200px;
				height: 150px;
				float: left;
				list-style: none;
			}
			#banner li img{
				width: 200px;
				height: 150px;
			}
		</style>
	</head>
	<body>
		<div id="banner">
			<ul>
				<li><img src="img/1.png"></li>
				<li><img src="img/2.png"></li>
				<li><img src="img/3.png"></li>
				<li><img src="img/4.png"></li>
				<li><img src="img/5.png"></li>
				<li><img src="img/6.png"></li>
			</ul>
		</div>
		<script type="text/javascript">
			window.onload=function(){
			let oDiv=document.getElementById('banner');
			let oUl=oDiv.getElementsByTagName('ul')[0];
			let oLi=oUl.getElementsByTagName('li');
			let timer=null;
			
			oUl.innerHTML+=oUl.innerHTML;
			oUl.style.width=oLi[0].offsetWidth*oLi.length+'px';
			function moving(){
				if(oUl.offsetLeft<-oUl.offsetWidth/2){
					oUl.style.left='0';
				}
				oUl.style.left=oUl.offsetLeft-2+'px';
			}
			timer=setInterval(moving,10);
			oDiv.onmouseover=function(){
				clearInterval(timer);
			}
			oDiv.onmouseout=function(){
				timer=setInterval(moving,10);
			}
			}
		</script>
	</body>
</html>


//       1.oUl.innerHTML+=oUl.innerHTML;  获得oUl中的内容
		 2.滚动图片是 宽度乘二 左度到半归零
		 3.执行鼠标函数前,需要运行onmouseout的内容先。

this与原型链题目

function Parent() {
      this.a = 1;
      this.b = [1, 2, this.a];
      this.c = { demo: 5 };
      this.show = function () {
        console.log(this.a , this.b , this.c.demo );
      }
    }
    function Child() {
      this.a = 2;
      this.change = function () {
        this.b.push(this.a);
        this.a = this.b.length;
        this.c.demo = this.a++;
      }
    }
    Child.prototype = new Parent();
    var parent = new Parent();
    var child1 = new Child();
    var child2 = new Child();
    child1.a = 11;
    child2.a = 12;
    parent.show(); //1,[1,2,1],5
    child1.show();//11,[1,2,1],5
    child2.show();//12,[1,2,1],5
    child1.change();                 // 原型链是从对象中找属性,找不到才去原型里面找。而构造函数原型只有一个,改变了里面的属性,那些继承它属性的对象在调用原型的属性是也会改变
    child2.change();
    parent.show();
    child1.show();//5,[1,2,1,11,12],5
    child2.show();//6,[1,2,1,11,12],6

JS事件循环机制

https://www.cnblogs.com/hity-tt/p/6733062.html

设计模式

https://zhuanlan.zhihu.com/p/78259452

单例模式

单例模式:

多次实例化,只会执行构造函数一次,提高性能

在一个类只能有一个实例,即使多次实例化该类,也只返回第一次实例化后的实例对象

单例模式能减少不必要的内存开销,并且在减少全局的函数和变量冲突也具有重要的意义。

https://www.jianshu.com/p/7fa6ea107eff

发布订阅模式

定义:当一个对象的状态发生变化时,所有依赖于他的对象都将得到通知

实现:指定一个发布者,给发布者添加一个缓存列表,列表用于存放回调函数以便通知订阅者, 发布者发布消息的时候,会遍历这个缓存列表,触发里面存放的订阅者回调函数

工厂模式

定义:不暴露创建对象的具体逻辑,而是将将逻辑封装在一个函数中,这个函数被视为一个工厂

分类:简单工厂,工厂方法,抽象工厂

区别:简单工厂是将创建对象的步骤放在父类进行,工厂方法是延迟到子类中进行,它们两者都可以总结为:“根据传入的字符串来选择对应的类”,而抽象工厂则是:“用第一个字符串选择父类,再用第二个字符串选择子类”

四大编程思想

面向过程编程

面向对象编程

面向服务架构

面向方面

面向过程(Procedure Oriented 简称PO :如C语言):

从名字可以看出它是注重过程的。当解决一个问题的时候,面向过程会把事情拆分成: 一个个函数和数据(用于方法的参数) 。然后按照一定的顺序,执行完这些方法(每个方法看作一个过程),等方法执行完了,事情就搞定了。

面向对象(Object Oriented简称OO :如C++,JAVA等语言):

看名字它是注重对象的。当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。

H5C3

https://www.jianshu.com/p/b3762ca713b1

https://www.html.cn/qa/html5/22947.html

1、新增标签,header,footer,nav,aside,article,section

2、本地存储。localstorage、sessionstorage、indexedDB本地存储

3、离线web应用

4、表单新增功能。input通过form属性绑定form表达id,可以写道外面来

5、css5.新增伪类选择器 before、after、first-child、nth-child。新增效果:box-shadow、text-shadow、background-size

animation,transition,transform

6、地理定位,新增方法geolocation , window.navigator.geolocation ,包含三个方法:

getCurrentPosition()
    watchPosition()
    clearWatch

事件流

https://www.cnblogs.com/sunyan-blog/p/11869040.html

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。

DOM事件流分为三个阶段,分别为:

捕获阶段:事件从Document节点自上而下向目标节点传播的阶段;

目标阶段:真正的目标节点正在处理事件的阶段;

冒泡阶段:事件从目标节点自上而下向Document节点传播的阶段。

事件委托

http://www.itcast.cn/news/20201020/1024078755.shtml

就是利用事件冒泡原理,子元素的事件会冒泡到父元素,可以只给父元素添加事件,通过事件目标判断元素。

优点:不用生成多个函数,节省内存,动态添加的子元素也包含事件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XT7zSHHA-1632368985405)(%E5%9B%BE%E7%89%87/JS/20201020102654420.jpg)]

继承

https://blog.csdn.net/weixin_43972437/article/details/94340482

构造函数继承 原型链继承 组合继承 es6的extends

//构造函数继承   
  function Person() {
    this.name = 'jack'
    this.say = function() {
      console.log('say');
    }
  }

  Person.prototype.add = function() {   //无法继承原型对象,所以只继承到构造函数内的属性
    console.log('add');
  }

  function Student() {
    Person.call(this)
    this.age = 11
  }

  let out = new Student()
  console.log(out);    //Student {name: "jack", age: 11, say: ƒ}
  console.log(out.add);  //undefined

  //原型链继承
  function Person() {
    this.name = 'jack'
    this.arr = [1,2]
    this.say = function() {
      console.log('say');
    }
  }
  Person.prototype.add = function() {   
    console.log('add');
  }
  function Student() {
    this.age = 11
  }
  Student.prototype =new Person()      
  
  let s1 = new Student()                //实例化原型对象的属性是引用类型的时候,会出现浅拷贝的情况,数据相互影响
  let s2 = new Student()
  s1.arr.push(3)
 
  console.log(s1,s2);


  //组合继承
  function Person() {
    this.name = 'jack'
    this.arr = [1,2]
    this.say = function() {
      console.log('say');
    }
  }
  Person.prototype.add = function() {   
    console.log('add');
  }
  function Student() {
    Person.call(this)                  //2.执行Person.call(this),此时this为s1,与s2区别开来了,但是这里执行了第二次的Person,优化: 所以可以将new Person()改为 Person.prototype
    this.age = 11
  }
  // Student.prototype =new Person()      //1.new Student时执行了Person,获取Person原型属性。  
  Student.prototype = Person.prototype    
  
  let s1 = new Student()                
  let s2 = new Student()
  s1.arr.push(3)
  console.log(s1.prototype);
  console.log(s1,s2);



es6的extends

class Animal {
	constructor (name) {
		this.name = name
	}
	showName () {
		alert(this.name)
	}
}
class Cat extends Animal {
	constructor (name) {
		super(name)
		this.type = '宠物'
	}
}

var cat = new Cat('飞翔的哔哔鸡')
cat.showName()  //飞翔的哔哔鸡

super关键字
super这个关键字,既可以当作函数使用,也可以当作对象使用。当作函数使用时,super代表父类的构造函数,并在子类中执行Parent.apply(this),从而将父类实例对象的属性和方法,添加到子类的this上面。以下三点需要特别注意:

1)子类必须在constructor方法中调用super方法,如果子类没有定义constructor方法,constructor方法以及其内部的super方法会被默认添加。
2)在子类的constructor方法中,只有调用super之后,才可以使用this关键字,否则会报错。
3)super作为对象时,在子类中指向父类的原型对象。即super=Parent.prototype。

class Animal {
	constructor (name) {
		this.name = name
	}
	showName () {
		alert(this.name)
	}
}
class Cat extends Animal {
	constructor (name) {
		super(name)
	}
	sayMy () {
		super.showName()
	}
}
var cat = new Cat('飞翔的哔哔鸡')
cat.sayMy() //飞翔的哔哔鸡

static关键字

在方法前添加stiatic,该方法不会被实例继承,但是父类的静态方法,可以被子类继承

class Animal {
	static showWhat (name) {
		alert(name)
	}
	showName (name) {
		showWhat(name)
	}
}
class Cat extends Animal {}


Cat.showWhat('小猪') //小猪  //父类的静态方法,可以被子类继承
var an = new Animal()
an.showWhat('小狗') //Uncaught TypeError: an.showWhat is not a function

宏任务 微任务 同步队列

从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理:

https://segmentfault.com/a/1190000017204460

顺序:

同步任务(主线程) --> 微任务 --> 宏任务

定时器模块

宏任务: settimeout ,

​ dom渲染(所以script(同步)放在dom后面,使dom先渲染。 dom更新时节点变化需要等待事件循环,并不是更新一个节点就渲染一次,是有多个任务在异步队列中的)

微任务:promise,async也是promise

setTimeout(() => {          //宏任务  定时器放在定时器模块,当运行时就开始计时,轮到它时就直接进入宏任务,调用进同步任务
  console.log("定时器1");
  new Promise(resolve => {
    console.log("settime promise");
    resolve();
  }).then(() => {
    console.log("settime timeout");
  })
}, 0)

new Promise(resolve =>{      //微任务
  console.log("promise");
  resolve();
}).then(() =>{
  console.log("promise then");   
})

console.log("同步任务");           

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSSF9oxs-1632368985406)(%E5%9B%BE%E7%89%87/JS/image-20210904162721572.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XnwKp4g0-1632368985406)(%E5%9B%BE%E7%89%87/JS/image-20210904162612349.png)]

当任务过大时,可以拆分任务,好处是不需要只等它一个,可以同时允许别的。

原理:用settimeout分多次,放入宏队列

let num =4563245   //进行递减累加
let count = 0
function hd() {
  for(let i = 0; i < 100000; i++) {   //分100000次输出
    if(num <= 0) break;
    count += num--; 
  }
  if(num > 0) {         
    setTimeout(hd)              //嵌套 
  }
  console.log(count);
}
hd()   

async和await

async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end')
}
async1()

//await是同步,’async2 end‘是在同步队列, async是异步,在微队列中
console.log('script start')

async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end')
}
async1()

setTimeout(function() {
  console.log('setTimeout')
}, 0)

new Promise(resolve => {
  console.log('Promise')
  resolve()
})
  .then(function() {
    console.log('promise1')
  })
  .then(function() {
    console.log('promise2')
  })

console.log('script end')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VH9889WP-1632368985407)(%E5%9B%BE%E7%89%87/JS/image-20210904170605375.png)]

同步:console.log(‘script start’) console.log(‘async2 end’) console.log(‘Promise’)

微队列:console.log(‘async1 end’) console.log(‘promise1’) console.log(‘promise2’)

宏队列:console.log(‘setTimeout’)

构造函数静态,实例成员

https://blog.csdn.net/songlf521/article/details/60144182

js的构造函数(在别的后台语言上叫做类)上可以添加一些成员,可以在构造函数内部的this上添加,可以在构造函数本身上添加,通过这两种方式添加的成员,就分别称为实例成员和静态成员。

1、实例成员和静态成员
实例成员:构造函数中this上添加的成员
静态成员:构造函数本身上添加的成员

function Person(name,age){
    this.name = name ;
    this.age = age;
    this.sayHi = function(){
    console.log('Hello...')
    }
    //上述的name\age\sayHi就是实例成员
}
Person.hobby = 'running'
Person.climb = function(){
    console.log('Climbing...')
}
//上述的hobby和climb就是静态成员
Person.prototype.jump = function(){
    console.log('Jumping...')
}
//jump为p1的__proto__属性指向的它的原型对象上的成员
//===============那么,
var p1 = new Person('Lucy',29)
p1.name  //'Lucy'
p1.age  //29
p1.sayHi() //Hello...
p1.jump()  // Jumping...
Person.climb() //Climbing...
Person.hobby  //running...
//==============但是
p1.climb()  //报错
Person.sayHi()  //报错
Person.jump() //报错

2、总结

实例成员,只能由实例化的对象来访问 p1.jump()
静态成员,只能由构造函数本身来访问 Person.climb()
实例化对象的proto指向构造函数的prototype属性指向的对象,实例化的对象可以访问到它后者身上的成员

栈堆,数组链表

栈和堆

一、程序的内存分配方式不同

  • 栈区(stack):编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构的栈。

  • 堆区(heap):一般是由程序员分配释放,若程序员不释放的话,程序结束时可能由OS回收,值得注意的是他与数据结构的堆是两回事,分配方式倒是类似于数据结构的链表。

二、申请的大小限制不同

  • 栈:在 windows 下,栈是向低地址扩展的数据结构,是一块连续的内存区域,栈顶的地址和栈的最大容量是系统预先规定好的,能从栈获得的空间较小。

  • 堆:堆是向高地址扩展的数据结构,是不连续的内存区域,这是由于系统是由链表在存储空闲内存地址,自然堆就是不连续的内存区域,且链表的遍历也是从低地址向高地址遍历的,堆得大小受限于计算机系统的有效虚拟内存空间,由此空间,堆获得的空间比较灵活,也比较大。

三、堆和栈的存储内容不同

  • 栈:在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令的地址,然后函数的各个参数,在大多数的 C 编译器中,参数是从右往左入栈的,当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令。

  • 堆:一般是在堆的头部用一个字节存放堆的大小,具体内容由程序员安排。


数组链表

数组是最基本的数据结构,所开辟的内存空间是连续的,且内存大小一经确定之后便无法再更改。浪费内存,缺乏弹性(不能根据当前实际需求更改大小)。

优点:查找速度快。通过数组的索引得到对应的数据,另一方面因为存储数据的内存连续,就算不知道所需要的数据对应的索引,即便从头到尾顺序查找一遍也能快速得到想要的数据。

缺点:增添和删除的效率

存储数据的内存不需要连续的,链表中的数据可以存储在内存的任何地方,这是因为链表中的每个数据都存储了下一个链表的地址,从而使离散的内存空间联系在一起,能合理的利用内存。每个链表包含多个节点,每个节点又包含数据域和引用域。

优点为:添加和删除元素十分方便。只需要知道修改前一个元素指向的地址即可。

缺点。查找元素麻烦。如果要查找链表中的一个元素,需要从第一个元素开始,依次往下,直到找到需要的元素位置。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值