es6循环
let output = [];
for (let item of input) {
let newItem = oodlify(item);
output.push(newItem);
}
Object.keys(),Object.getOwnPropertyNames()
Object.keys方法和Object.getOwnPropertyNames方法很相似,一般用来遍历对象的属性。它们的参数都是一个对象,都返回一个数组,该数组的成员都是对象自身的(而不是继承的)所有属性名。它们的区别在于,Object.keys方法只返回可枚举的属性(关于可枚举性的详细解释见后文),Object.getOwnPropertyNames方法还返回不可枚举的属性名。
var o = {
p1: 123,
p2: 456
};
Object.keys(o)
// ["p1", "p2"]
Object.getOwnPropertyNames(o)
// ["p1", "p2"]
上面的代码表示,对于一般的对象来说,这两个方法返回的结果是一样的。只有涉及不可枚举属性时,才会有不一样的结果。
var a = ["Hello", "World"];
Object.keys(a)
// ["0", "1"]
Object.getOwnPropertyNames(a)
// ["0", "1", "length"]
上面代码中,数组的length属性是不可枚举的属性,所以只出现在Object.getOwnPropertyNames方法的返回结果中。
由于JavaScript没有提供计算对象属性个数的方法,所以可以用这两个方法代替。
Object.keys(o).length
Object.getOwnPropertyNames(o).length
一般情况下,几乎总是使用Object.keys方法,遍历数组的属性。
js易错点
变量作用域
var a = 1;
function test() {
var a = 2;
console.log(a); // 2
}
test();
上方的函数作用域中声明并赋值了a,且在console之上,所以遵循就近原则输出a等于2。
a在function里面被声明然后提升到前面 但没有赋值
js 变量提升
var a = 1;
function test2() {
console.log(a); // undefined
var a = 2;
}
test2();
上方的函数作用域中虽然声明并赋值了a,但位于console之下,a变量被提升,输出时已声明但尚未被赋值,所以输出undefined。
var a = 1;
function test3() {
console.log(a); // 1
a = 2;
}
test3();
上方的函数作用域中a被重新赋值,未被重新声明,且位于console之下,所以输出全局作用域中的a。
let b = 1;
function test4() {
console.log(b); // b is not defined
let b = 2;
}
test4();
上方函数作用域中使用了ES6的let重新声明了变量b,而let不同于var其不存在变量提升的功能,所以输出报错b is not defined。
function test5() {
let a = 1; { let a = 2; }
console.log(a); // 1
}
test5();
上方的函数作用域中用let声明了a为1,并在块级作用域中声明了a为2,因为console并不在函数内的块级作用域中,所以输出1。
typeof获取NULL、数组、对象的类型都为object,
var arr = [];
var arr = [];
console.log(arr instanceof Object); // true
console.log(arr instanceof Array); // true
上方利用instanceof判断一个变量是否属于某个对象的实例,因为在JavaScript中数组也是对象的一种,所以两个console都为true。
this指向
var obj = {
name: 'xiaoming',
getName: function () {
return this.name
}
};
console.log(obj.getName()); // 'xiaoming'
上方对象方法中的this指向对象本身,所以输出xiaoming。
var obj = {
myName: 'xiaoming',
getName: function () {
return this.myName
}
};
var nameFn = obj.getName;
console.log(nameFn()); // undefined
上方将对象中的方法赋值给了一个变量,此时方法中的this也将不再指向obj对象,从而指向window对象,所以console为undefined。
var obj = {
myName: 'xiaoming',
getName: function () {
return this.myName
}
};
var obj2 = {
myName: 'xiaohua'
};
var nameFn = obj.getName;
console.log(nameFn.apply(obj2)); // 'xiaohua'
上方同样将obj对象中的方法赋值给了变量nameFn,但是通过apply方法将this指向了obj2对象,所以最终console为xiaohua。
4.函数参数
function test6() {
console.log(Array.prototype.slice.call(arguments)); // [1, 2]
}
test6(1, 2);
上方利用函数中的arguments类数组对象获取传入函数的参数数组,所以输出数组[1, 2]。
function test7 () { return function () { console.log(Array.prototype.slice.call(arguments)); // 未执行到此,无输出 }}test7(1, 2);
上方同样利用arguments获取参数,但因test7(1, 2)未执行return中的函数,所以无输出。若执行test7(1, 2)(3, 4)则会输出[3, 4]。
var args = [1, 2];
function test9() { console.log(Array.prototype.slice.call(arguments)); // [1, 2, 3, 4]}
Array.prototype.push.call(args, 3, 4);test9(...args);
上方利用Array.prototype.push.call()方法向args数组中插入了3和4,并利用ES6延展操作符(...)将数组展开并传入test9,所以console为[1, 2, 3, 4]。
5.闭包问题
var elem = document.getElementsByTagName('div'); // 如果页面上有5个div
for(var i = 0; i < elem.length; i++) {
elem[i].onclick = function () {
alert(i); // 总是5
};
}
上方是一个很常见闭包问题,点击任何div弹出的值总是5,因为当你触发点击事件的时候i的值早已是5,可以用下面方式解决:
var elem = document.getElementsByTagName('div'); // 如果页面上有5个div
for(var i = 0; i < elem.length; i++) {
(function (w) {
elem[w].onclick = function () {
alert(w); // 依次为0,1,2,3,4
};
})(i);
}
在绑定点击事件外部封装一个立即执行函数,并将i传入该函数即可。
对象拷贝与赋值
var obj = { name: 'xiaoming', age: 23};
var newObj = obj;
newObj.name = 'xiaohua';console.log(obj.name);//'xiaohua'
console.log(newObj.name); // 'xiaohua'
上方我们将obj对象赋值给了newObj对象,从而改变newObj的name属性,但是obj对象的name属性也被篡改,这是因为实际上newObj对象获得的只是一个内存地址,而不是真正的拷贝,所以obj对象被篡改。
var obj2 = { name: 'xiaoming', age: 23};
var newObj2 = Object.assign({}, obj2, {color: 'blue'});
newObj2.name = 'xiaohua';console.log(obj2.name); // 'xiaoming'
console.log(newObj2.name); // 'xiaohua'
console.log(newObj2.color); // 'blue'
上方利用Object.assign()方法进行对象的深拷贝可以避免源对象被篡改的可能。因为Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是Object.assign() 只是一级属性复制,比浅拷贝多深拷贝了一层,使用的时候,还要注意这个问题。
我们也可以使用Object.create()方法进行对象的拷贝,Object.create()方法可以创建一个具有指定原型对象和属性的新对象。
var obj3 = { name: 'xiaoming', age: 23};
var newObj3 = Object.create(obj3);
newObj3.name = 'xiaohua';
console.log(obj3.name); // 'xiaoming'
console.log(newObj3.name); // 'xiaohua'
”数组”(array)和”对象”(object)的区别
两者都可以用来表示数据的集合。
//数组
a=[1,2,3,4],
//对象
a={0:1,1:2,2:3,3:4}
然后你运行alert(a[1]),两种情况下的运行结果是相同的
数组表示有序数据的集合,而对象表示无序数据的集合。如果数据的顺序很重要,就用数组,否则就用对象。
当然,数组和对象的另一个区别是,数组的数据没有”名称”(name),对象的数据有”名称”(name)。
在javascript中,可以这样定义一个对象:
var a={“城市”:”北京”,”面积”:16800,”人口”:1600};
//但是,也可以定义成一个关联数组:
a["城市"]=”北京”;
a["面积"]=16800;
a["人口"]=1600;
在Javascript语言中,关联数组就是对象,对象就是关联数组。
比如运行下面这段javascript:
var a=[1,2,3,4];
a['foo']=’Hello World’;
alert(a.length);
最后的结果是4,也就是说,数组a的元素个数是4个。
js模块
CommonJS定义的模块分为:
require()用来引入外部模块;
exports()用于导出当前模块的方法或变量,唯一的导出口;
module()就代表模块本身。
json文件中不能出现注释
underscorejs 官方文档(廖雪峰的blog里也有讲解)
foreach()函数
for(var o in obj)
ep: [1, 2 ,3, 4].forEach(alert);
var data=[1,3,4] ;
var sum=0 ;
data.forEach(function(value,index,arr){
console.log(arr[index]==value); // ==> true
sum+=value;
})
console.log(sum); // ==> 8
js 的 forEach() 与jquery的map()
[].forEach(
function
(value, index, array) {
// ...
});
//对比jQuery中的$.each方法:
$.each([],
function
(index, value, array) {
// ...
});
两者在function()参数顺序上不一样
this 大坑
this指的是,调用函数的那个对象。
function test() 调用这个函数的是window so this 指向window this.x 相当于window.x
var x = 1;
function test(){
this.x = 0;
}
test();
alert(x); //0
// "this" of function also point to window so "var x" has been changed
function test(){
this.x = 1;
}
var o = new test();
alert(o.x); // 1
//"this" point to new object "o"
Map是一组键值对的结构,具有极快的查找速度。
js 对象检查是否有a属性 'a' in object() return ture or false
toUpperCase() toLowerCase() indexOf substring(0,5)
我本将心向明月,奈何明月照沟渠
<div style="font:100px/200px Microsoft Yahei;width:660px;height:200px;text-overflow:ellipsis;">
天地玄黄宇,宙洪荒日月。
</div>
<style>
div {
/*超出宽度的不可见*/
overflow: hidden;
/*不换行(除非遇到"<br>")*/
white-space: nowrap;
/*以“...”方式表示文本隐藏。*/
/*博主当时很肯定地说用这就够了,完全把上面两行忘得干干净净*/
text-overflow: ellipsis;
}
</style>
"this" use call() apply() change its target value
should learn more ......
obj.proto === Object.getPrototypeOf(obj)
所有对象的proto都指向其构造器的prototype