JS的执行机制
特点: 1、单线程, 即,同一个时间只能做一件事,不要多线程是为了提升效率 (用途是与用户互动,操作Dom,否则会带来很复杂的同步问题) 2、任务队列(消息队列), 同步任务(主线程上排队执行),异步任务(不进入主线程,而是进入‘任务队列task queue’,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行) console.log('a'); while(true){} console.log('b') //只能输出a,因为是同步任务,程序由上到下执行,遇到while死循环,下面的语句就没法执行 console.log('a'); setTimeout(function(){ console.log('b') },0) while(true){} //还是只能输出a,setTimeout()就是个异步任务。在所有同步任务执行完之前,任何的异步任务是不会执行的 3、Event Loop 1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。 3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 4)主线程不断重复上面的第三步。 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。 哪些语句会放入异步任务队列及放入时机 1、setTimeout和setlnterval 2、DOM事件 3、ES6中的Promise 4、Ajax异步请求 javascript 代码运行分两个阶段: 1、预解析 ---把所有的函数定义提前,所有的变量声明提前,变量的赋值不提前 2、执行 ---从上到下执行(按照js运行机制) for(var i=0;i<5;i++){ setTimeout(function(){ console.log(i) },1000) } //5个5 在到达指定时间时,定时器就会将相应回调函数插入“任务队列”尾部。这就是“定时器(timer)”功能 关于定时器的重要补充: 1、定时器包括setTimeout与 setInterval 两个方法。它们的第二个参数是指定其回调函数推迟/每隔多少毫秒数后执行。 2、对于第二个参数有以下需要注意的地方:当第二个参数缺省时,默认为 0; 当指定的值小于 4 毫秒,则增加到 4ms(4ms 是 HTML5 标准指定的,对于 2010 年及之前的浏览器则是 10ms);也就是说至少需要4毫秒,该setTimeout()拿到任务队列中。
2、js的浅copy和深copy
JS浅copy与深copy //后台返回了一堆数据,你需要对这堆数据做操作,多人开发情况下,没办法明确这堆数据是否有其它功能也需要使用,直接修改可能会造成隐性问题,深拷贝能帮你更安全安心的去操作数据, 1、封装一个深拷贝的函数(PS:只是一个基本实现的展示,并非最佳实践) function deepClone(obj){//递归 let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; } let a=[1,2,3,4], b=deepClone(a); a[0]=2; console.log(a,b); 2、slice只能实现一维数组的深拷贝,, let a=[0,1,[2,3],4], b=a.slice(); a[0]=1; a[2][0]=1; console.log(a,b); //是做不到的 3、concat方法 与slice也存在这样的情况,他们都不是真正的深拷贝 4、我们还可以借用JSON对象的parse和stringify function deepClone(obj){ let _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone } let a=[0,1,[2,3],4], b=deepClone(a); a[0]=1; a[2][0]=1; console.log(a,b); 5、JQ的extend方法 //$.extend( [deep ], target, object1 [, objectN ] ) let a=[0,1,[2,3],4], b=$.extend(true,[],a); a[0]=1; a[2][0]=1; console.log(a,b);
3、js类型转换
显示转换 1、Number() 1)如果是布尔值,true和false分别被转换为1和0 2)如果是数字值,返回本身。 3)如果是null,返回0. 4)如果是undefined,返回NaN。 5)如果是字符串,遵循以下规则: 1、如果字符串中只包含数字,则将其转换为十进制(忽略前导0) 2、如果字符串中包含有效的浮点格式,将其转换为浮点数值(忽略前导0) 3、如果是空字符串,将其转换为0 4、如果字符串中包含非以上格式,则将其转换为NaN 6)如果是对象,则调用对象的valueOf()方法,然后依据前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,再次依照前面的规则转换返回的字符串值。 2、parseInt(string, radix) 1)忽略字符串前面的空格,直至找到第一个非空字符 2)如果第一个字符不是数字符号或者负号,返回NaN 3)如果第一个字符是数字,则继续解析直至字符串解析完毕或者遇到一个非数字符号为止 4)如果上步解析的结果以0开头,则将其当作八进制来解析;如果以0x开头,则将其当作十六进制来解析 5)如果指定radix参数,则以radix为基数进行解析 3、parseFloat(string) 它的规则与parseInt基本相同,但也有点区别:字符串中第一个小数点符号是有效的,另外parseFloat会忽略所有前导0,如果字符串包含一个可解析为整数的数,则返回整数值而不是浮点数值。 4、toString(radix) 除 undefined 和 null 之外的所有类型的值都具有toString()方法,其作用是返回对象的字符串表示。 5、String(mix) 1)如果有toString()方法,则调用该方法(不传递radix参数)并返回结果 2)如果是null,返回”null” 3)如果是undefined,返回”undefined” 6、Boolean(mix) 以下值会被转换为false:false、”"、0、NaN、null、undefined,其余任何值都会被转换为true。 隐式转换 1、isNaN(mix) 2、递增递减操作符(包括前置和后置)、一元正负符号操作符 1)如果是包含有效数字字符的字符串,先将其转换为数字值(转换规则同Number()),在执行加减1的操作,字符串变量变为数值变量。 2)如果是不包含有效数字字符的字符串,将变量的值设置为NaN,字符串变量变成数值变量。 3)如果是布尔值false,先将其转换为0再执行加减1的操作,布尔值变量编程数值变量。 4)如果是布尔值true,先将其转换为1再执行加减1的操作,布尔值变量变成数值变量。 5)如果是浮点数值,执行加减1的操作。 6)如果是对象,先调用对象的valueOf()方法,然后对该返回值应用前面的规则。如果结果是NaN,则调用toString()方法后再应用前面的规则。对象变量变成数值变量。 3、加法运算操作符 4、乘除、减号运算符、取模运算符 5、逻辑操作符(!、&&、||) 6、关系操作符(<, >, <=, >=) 7、相等操作符(==)
4、js的组成部分
javascript是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成: 1、ECMAScript,由ECMA-262定义,提供核心语言功能; 2、文档对象模型(DOM),提供访问和操作网页内容的方法和接口; 3、浏览器对象模型(BOM),提供与浏览器交互的方法和接口;
5、js严格模式
"use strict"; //是进入严格模式的标志,放在脚本文件的第一行,则整个脚本都将以"严格模式"运行。如果这行语句不在第一行,则无效,整个脚本以"正常模式"运行 1、全局变量显式声明 变量必须先用var声明,然后再使用 2、静态绑定 1)禁止使用with()语句 2)创设eval作用域 3、禁止this关键字指向全局对象 4、禁止在函数内部遍历调用栈 5、禁止删除变量 严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。 'use strict' var x; delete x; //语法错误 var o = Object.create(null,{ 'x':{ value:1, configurable:true } }) delete o.x //删除成功 6、严格模式下,对一个使用getter方法读取的属性进行赋值,会报错。 var o = {}; Object.defineProperty(o, "v", { value: 1, writable: false }); o.v = 2; console.log(o)//1 虽然没有改变,但是也没有报错 'use strict'; var o = {}; Object.defineProperty(o, "v", { value: 1, writable: false }); o.v = 2; // 报错 console.log(o) 7、严格模式下,对禁止扩展的对象添加新属性,会报错。 var o = {}; Object.preventExtensions(o); o.v = 1; console.log(o)//空对象 'use strict'; var o = {}; Object.preventExtensions(o); o.v = 1; // console.log(o) 8、严格模式下,删除一个不可删除的属性,会报错。 delete Object.prototype; //无影响 'use strict'; delete Object.prototype; // 报错 9、对象不能有重名的属性 10、函数不能有重名的参数 11、禁止八进制表示法 12、arguments对象的限制 13、 函数必须声明在顶层 14、保留字