js杂

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文件中不能出现注释

node module

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


the 'this' of function => window || global
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)

protptype原型继承

我本将心向明月,奈何明月照沟渠

<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 ......

JavaScript面向对象编程

brower's location()
匿名函数get out

obj.proto === Object.getPrototypeOf(obj)

Paste_Image.png

所有对象的proto都指向其构造器的prototype

call() and apply()

call --by mdn
apply --by mdn

箭头函数

js中call、apply、bind那些事

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容