遍历对象
for in (自身及原型对象 可枚举)、Object.keys()(自身可枚举)以及Object.getOwnPropertyNames(自身不可枚举)的区别
var obj= Object.create(parent, {
b: {
value: 2,
writable: true,
enumerable: true,
configurable: true
},
c: {
value: 3,
writable: true,
enumerable: false,
configurable: true
}
});
obj.__proto__ = {age:123};
1、 for in 遍历对象,会将对象自身的属性以及原型上继承的属性都打印出来,但是不会获取不可枚举的属性。
for(let key in obj){
console.log(key) // =>b ,age
}
2、Object.keys()遍历对象,获取对象自身可枚举属性。
var arr = Object.keys(obj);
console.log(arr) => ['b']
3、Object.getOwnPropertyNames()遍历对象,获取所有自身属性,包括不可枚举的属性。
var arr = Object.getOwnPropertyNames(obj);
console.log(arr) => ['b','c']
Promise
下面代码中,Promise 新建后立即执行,所以首先输出的是2,3。
然后,then
方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved
最后输出。
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
//
2
3
5
4
1
Promise
Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
Promise对象状态:pending(进行中)、fulfilled(成功)、rejected(失败)
JavaScript引擎提供了函数:resolve、reject
resolve
函数的作用是,将Promise
对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject
函数的作用是,将Promise
对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
const promise = new Promise((resolve,reject)=>{
if(异步成功){resolve(value)}
else{reject(error)}
})
Promise.prototype.then()
Promise 实例具有then
方法,也就是说,then
方法是定义在原型对象Promise.prototype
上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。
then
方法返回的是一个新的Promise
实例(注意,不是原来那个Promise
实例)。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
promise.then((value)=>{//sucess}, (error)=>{//fail})
采用链式的then
,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise
对象(即有异步操作),这时后一个回调函数,就会等待该Promise
对象的状态发生变化,才会被调用。
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
}).then(function(){console.log("3")})
.then(function(){console.log("4")})
.then(function(){console.log("5")})
.then(function(){console.log("6")})
.then(function(){console.log("7")})
.then(function(){console.log("8")})
console.log(0)
//2,0,1,3,4,5,6,7,8
链式的then是按次序执行的。另,调用resolve(1)
以后,后面的console.log(2)
还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
Promise.prototype.catch()
Promise.prototype.catch
方法是.then(null, rejection)
的别名,用于指定发生错误时的回调函数。
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
上面代码中,getJSON
方法返回一个 Promise 对象,如果该对象状态变为resolved
,则会调用then
方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected
,就会调用catch
方法指定的回调函数,处理这个错误。另外,then
方法指定的回调函数,如果运行中抛出错误,也会被catch
方法捕获。
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
噢,我的想法被证实了!!
如果 Promise 状态已经变成resolved
,再抛出错误是无效的。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
上面代码中,Promise 在resolve
语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch
语句捕获。
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
上面代码中,一共有三个 Promise 对象:一个由getJSON
产生,两个由then
产生。它们之中任何一个抛出的错误,都会被最后一个catch
捕获。
一般来说,不要在then
方法里面定义 Reject 状态的回调函数(即then
的第二个参数),总是使用catch
方法。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
Promise.prototype.finally()
finally
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
finally
方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled
还是rejected
。这表明,finally
方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
Promise.all()
Promise.all
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
p
的状态由p1
、p2
、p3
决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
Promise.race()
Promise.race
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为reject
,否则变为resolve
。
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p
.then(console.log)
.catch(console.error);
上面代码中,如果 5 秒之内fetch
方法无法返回结果,变量p
的状态就会变为rejected
,从而触发catch
方法指定的回调函数。
小注:
setTimeout是异步函数,需要等主进程运行完才会运行
for(var i=0;i<10;i++){
setTimeout(function() {
console.log(i);
}, 0);
}
-
你问为什么这里输出10的原因是异步?
我只能告诉你,因为setTimeout()
函数是异步的 -
为什么
setTimeout()
函数是异步的?
这个问题你得去问Brendan Eich
。 -
如果你想问的是这里为什么输出10?
因为异步函数必须等主进程运行完毕才会运行,setTimeout()
内部回调运行的时候,主进程已经运行完毕了,此时i=10
,所以输出10。
setTimeout(func,ms,x)第三个参数是要作为参数传入func中的:
如:var f=function(x){console.log(x)};
setTimeout(f,1000,456)//1秒后,打印456
定时器setInterval和setTimeout中的this指向:
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
window.setTimeout(function () {
console.log(this.name); //my name is window
}, 1000)
}
}
obj.fn()
如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window。这是因为JS的定时器方法是定义在window下的。setTimeout实际是window.setTimeout,setInterval实际是window.setInterval。但是平时很多场景下,都需要修改this的指向。这里总结了几种:
1、最常用的方法:在外部函数中将this存为一个变量,回调函数中使用该变量,而不是直接使用this。
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
var that = this;
window.setTimeout(function () {
console.log(that.name); //my name is obj
}, 1000)
}
}
obj.fn()
在fn中加了var that = this; 回调函数中使用that代替this即可。这种方法最常见,使用也最广泛。
2、使用bind()方法(bind()为ES5的标准,低版本IE下有兼容问题,可以引入es5-shim.js解决)
bind()的作用类似call和apply,都是修改this指向。但是call和apply是修改this指向后函数会立即执行,而bind则是返回一个新的函数,它会创建一个与原来函数主体相同的新函数,新函数中的this指向传入的对象。
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
window.setTimeout(function () {
console.log(this.name); //my name is obj
}.bind(this), 1000)
}
}
obj.fn()
在这里为什么不能用call和apply,是因为call和apply不是返回函数,而是立即执行函数,那么,就失去了定时器的作用。
3、使用es6的箭头函数:箭头函数的最大作用就是this指向。箭头函数没有自己的this,调用的是定义时的this。
var name = 'my name is window';
var obj = {
name: 'my name is obj',
fn: function () {
window.setTimeout( ()=>{
console.log(this.name); //my name is obj
}, 1000)
}
}
obj.fn()
箭头函数没有自己的this,它的this继承自外部函数的作用域。所以,在该例中,定时器回调函数中的this,是继承了fn的this。当然箭头函数也有兼容问题,要是兼容低版本ie,需要使用babel编译,并且引入es5-shim.js才可以。
箭头函数=>;
转自:http://blog.csdn.net/wendelle/article/details/51804633
最近感觉ES6的代码看着帅帅哒,忍不住去看了看....
使用箭头函数=>可以省略function以及return等内容的书写,定义一个箭头函数的基本语法为
(param1,param2...)=>{
statesments;
}
1.param为参数,根据参数的不同,箭头函数可以分为三种情况
①当没有参数时,写一对括号()即可
②当只有一个参数时,可以省略括号
③当有多个参数时,用括号把各个参数括起来。
2.剩余参数与多行语句①箭头函数与普通函数一样,也可以使用ES6的默认参数、剩余参数
②当语句不为单行,而是多行语句时,需要用{}把语句括起来,若将单行语句用{}括起来,则会用undefined作为返回值,而单行语句不使用{}时,执行结果即为返回值。
3.箭头函数内部没有constructor与prototype属性,不能被new
4.箭头函数内部的this被绑定为函数定义时的this,并且无法改变