最近需要看一个node express 的项目,不过对js这块学的不是太好,所以想系统的看一遍js的文档,把基础的部分重新看了一遍,方便后面的学习 ,这里记录一下新颖的,以前不知道的,以及和别的编程语言不同的地方。
- 使用Array的map函数,对数组中的每个元素进行同样的处理,产生另外一个数组
const array1 = [1, 4, 9, 16];
function square(x) {return x ** 2}
// pass a function to map
const map1 = array1.map(square);
console.log(map1);
-
js中的数字(number)和字符串(string)类型没有原型,不可使用.prototype。 它们是 primitive ( 原语 )数据, 不是对象数据。primitive 数据 没有 属性,底层实现 往往就是 直接对应 存储在内存的 数据,所以非常高效。 调用.length属性时,解释器会把我们的字符串封装成对象。
-
for循环遍历数组和对象: for … of & for … in
let colors = ['red', 'green', 'blue'];
for (const color of colors) {
console.log(color);
}
/**如果我们需要遍历一个对象里面的所有属性和值,怎么办?
* Object.entries 方法可以返回 对象的属性和值 到一个数组,方便我们遍历
* 然后使用 for ... of 遍历数组
* 如下
*/
var obj1 = {
a: 'somestring',
b: 42
};
// 以 obj1 为原型创建 obj2 对象
var obj2 = Object.create(obj1)
obj2.c = 33
obj2.d = 44
// 使用for ... of 遍历数组
for (let [key, value] of Object.entries(obj2)) {
console.log(`${key}: ${value}`);
}
/**
* js 种还有一种 for ... in 循环遍历对象的方法。
* 但是,这种方式获取的不仅仅是对象自身的属性,还会获取 对象原型的属性 。
* 如果要过滤掉原型属性,可以加一个判定条件,如下
*/
for (let key in obj2) {
if (obj2.hasOwnProperty(key))
console.log(`${key}: ${obj2[key]}`);
}
- var 和 let的区别
因为es6 引入了块代码和let , let和var的区别就在于块代码这里。 块代码里面用let定义的变量,块外部不可用,而块内部用var定义的变量外部可以使用
例子如下:
{
let b = 2
var a = 1
}
console.log(a) // 正常执行
console.log(b) // 报错
- 以前的的js都是通过构造函数或者对象原型生成新的对象,学过别的编程语言C++, java的感觉会很别扭, ES6给js引入了 类的概念,这样就和别的编程语言差不多了。
- 回调: 一个函数在使用的时候并不立刻调用它,而是 在发生一个事件之后再调用它
- 匿名函数:有的函数只用一次,可以不给函数起名字,直接写函数的功能,如下:
setTimeout(
// 直接定义函数,不用起名
function() {
console.log("这里是等待2秒的后续代码");
},
2000 // 2000毫秒,就是2秒
)
- 箭头函数: ES6中引入了箭头函数来更简洁的定义匿名函数
(a) => {
return a + 100;
}
//如果箭头函数只有一个参数,可以省略参数周围的括号
a => {
return a + 100;
}
//如果 箭头函数 体内 只有一行代码,并且是返回一个值,可以省略 return 和 花括号
a => a + 100
// 前面的示例,使用箭头函数可以这样定义
setTimeout(
() => { console.log("这里是等待2秒的后续代码"); },
2000
)
- this : 通过什么对象调用的, this就指向那个对象,例子如下:
// 前面学过一个汽车类的例子,如下
class Car {
constructor(price, owner) {
this.price = price
this.owner = owner
}
showInfo(){
console.log(`车辆信息如下:`)
console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)
}
}
car1 = new Car(230000,'白月黑羽')
car1.showInfo()
// 前面讲过 通过哪个对象调用了这个函数,函数里面的 this 对应的是就是这个对象
// 我们可以把函数对象赋值给另外的变量,比如
let obj1={
price: '3333',
owner: '张三',
anotherShowInfo : car1.showInfo
}
obj1.anotherShowInfo()
/**
* 输出结果如下
* 车辆信息如下:
* VM121:11 车主 : 张三 - 售价 : 3333
*/
- 最后有一个问题: 修改showInfo方法会出现问题, 如下:
class Car {
constructor(price, owner) {
this.price = price
this.owner = owner
}
showInfo_Delay1Sec(){
// 1秒后通过回调函数打印出 this.owner 和 this.price
setTimeout(
function (){
// console.log(this===window)
console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)
},
1000
)
}
}
car1 = new Car(230000,'白月黑羽')
car1.showInfo_Delay1Sec() // 这里都是unidenfied
// 执行以下会发现结果 如下:
// 车主 : undefined - 售价 : undefined
/** 原因时什么呢
因为setTimeout函数是js引擎实现的,它内部调用回调函数时,没有 xxx.调用前缀
js中,调用函数没有前缀,就等于通过全局对象 window 调用
也就是 window.setTimeout, 所以,回调里面的this就是windows对象。
windows对象并没有 price 、onwer属性。
所以,也出现了上述的错误显示。
这里的this带来的问题,可以说是js语言 最臭名昭著的,让人头疼的问题之一。
*/
/** 两个解决方法
* 1. 保存以下this
* 2. 用箭头函数
*/
// 1.保存this到其它变量
class Car1 {
constructor(price, owner) {
this.price = price
this.owner = owner
}
showInfo_Delay1Sec(){
// 保存 调用对象 到self中
let self = this
setTimeout(
function () {
// 使用self,也就是调用对象
console.log(`车主 : ${self.owner} - 售价 : ${self.price} `)
},
1000
)
}
}
var car1 = new Car1(230000,'白月黑羽')
car1.showInfo_Delay1Sec()
// 2.使用箭头函数
class Car2 {
constructor(price, owner) {
this.price = price
this.owner = owner
}
showInfo_Delay1Sec(){
setTimeout(() => {
console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)
}, 1000)
}
}
var car2 = new Car2(230000,'白月黑羽')
car2.showInfo_Delay1Sec()
/*
可以发现,运行结果正确
因为:箭头函数中的this比较特殊,它对应的 是 包含该箭头函数 的函数的执行环境 。
本例中,包含箭头函数的函数 是 showInfo_Delay1Sec (注意不是setTimeout,这里setTimeout是调用,而不是定义)
这里,我们是通过 car1 调用的showInfo_Delay1Sec, 所以 里面的执行环境, 就是 car1
*/
// 如果箭头函数没有包含函数,里面this对应的就是全局对象,浏览器中就是 window
// 比如
var price = 1000
var owner = '白月黑羽'
setTimeout(
() => {
console.log(`车主 : ${this.owner} - 售价 : ${this.price} `) // 这里就是undifined
},
1000
)
箭头函数中的this比较特殊,它对应的 是 包含该箭头函数 的函数的执行环境 。