练习1
const a = 888;
const b = new Number(888); // Number {888}
const c = '888';
console.log(a == b); // true
console.log(b == c); // true
console.log(a === b); // false
console.log(b === c); // false
1
2
3
4
5
6
7
2
3
4
5
6
7
- ==在进行比较的时候会先进行类型转换,b是对象,首先会调用toString方法转为字符串'888',因此b == c为true;
- a == b在进行比较时,b先转为字符串,然后再转为数字888,所以a == b也是true
- ===在进行比较时不会进行类型转换,因此后两个都是false
练习2
const a = {};
const b = {name: 'lisi'};
const c = {name: 'wangwu'};
// 对象键值会被转为字符串
a[b] = 666;
a[c] = 888;
console.log(a[b]); // 888
console.log(a); // {[object Object]: 888}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
练习3
const arr = [1, 2, 3];
arr[10] = 123;
console.log(arr); // (11) [1, 2, 3, empty × 7, 123]
1
2
3
2
3
练习4
核心知识点:箭头函数this指向。
const obj1 = {
name: 'lisi',
print() {
return () => console.log(this.name);
}
};
const obj2 = {name: 'wangwu'};
obj1.print()(); // lisi
obj1.print().call(obj2); // lisi
obj1.print.call(obj2)(); // wangwu
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
练习5
const obj = {
1: 'a',
2: 'b'
};
const set = new Set([1, 2, 3]);
// hasOwnProperty的参数要检测的属性的String字符串形式表示的名称,或者Symbol
// 如果参数不是字符串,将会自动转为字符串形式
console.log(obj.hasOwnProperty('1')); // true
console.log(obj.hasOwnProperty(1)); // true
console.log(set.has('1')); // false
console.log(set.has(1)); // true
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
练习6
async function async1() {
console.log('async1 start'); // 2
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start'); // 1
setTimeout(function() {
console.log('setTimeout0');
}, 0);
async1();
new Promise((resolve) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('script end');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
输出
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout0
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
async function async1() {
console.log('async1 start'); // 2
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start'); // 1
setTimeout(function() {
console.log('setTimeout0');
}, 0);
setTimeout(function() {
console.log('setTimeout3');
}, 3);
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick'));
async1();
new Promise((resolve) => {
console.log('promise1');
resolve();
console.log('promise2');
}).then(() => {
console.log('promise3');
});
console.log('script end');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
script start
async1 start
async2
promise1
promise2
script end
nextTick
async1 end
promise3
setTimeout0
setImmediate
setTimeout3
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
练习7
为什么[] == ![]的结果为true? 判断步骤如下:
- 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值-->false转换为0,true转换为1。
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值。
- 如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,如果得到的值不是基本类型值,则基于返回值再调用toString方法(这个过程即ToPrimitive),用得到的基本类型值按照前面的规则进行比较。
- 如果两个操作数都是对象,则比较他们是不是同一个对象。如果两个操作数指向同一个对象,则相等操作符返回true, 否则返回false。
这两个操作符在进行比较时则要遵循下列规则:
- null和undefined是相等的。
- 要比较相等性之前,不能将null和undefined转换成其他任何值。
- 如果有一个操作数是NaN,则相等操作符返回false, 而不相等操作符则返回true, NaN != NaN。
练习8
var a = 0, b = 0;
function A(a) {
A = function (b) {
alert(a + b++);
}
alert(a++);
}
A(1); // 1
A(2); // 4
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
练习9
function Foo() {
// 会覆盖全局的getName方法
getName = function() {
// console.log('----', this);
console.log(1);
}
return this;
}
Foo.getName = function() { // 相当于静态方法
console.log(2);
}
Foo.prototype.getName = function() {
console.log(3);
}
var getName = function() {
console.log(4);
}
// 会被覆盖
function getName() {
console.log(5);
}
Foo.getName(); // 2
getName(); // 4
// Foo()当做普通函数调用,this指向window
Foo().getName(); // 1
getName(); // 1
// 涉及js运算符优先级,参考mdn
new Foo.getName(); // 2
// Foo()当做构造函数调用,this指向当前实例对象,相当于调用Foo原型上的getName
new Foo().getName(); // 3
new new Foo().getName(); // 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
new Foo.getName(); // 2
1
上述代码,因为成员访问优先级是19,new (无参数列表)优先级是18,所以先进行成员访问
,即Foo.getName
,Foo.getName指向如下函数:
Foo.getName = function() {
console.log(2);
}
1
2
3
2
3
然后采用new调用该函数,因此输出2。
new Foo().getName(); // 3
1
上述代码,new (带参数列表)和成员访问优先级都是19,因此从左往右依次执行。Foo()当做构造函数调用,this指向当前实例对象,相当于调用Foo原型上的getName,因此输出3。
new new Foo().getName(); // 3
1
先执行new Foo()
,返回Foo的实例对象,new Foo().getName指向的是Foo原型上的getName方法,相当于用new调用该方法,因此输出3
运算符优先级
'b' + 'a' + + 'a' + 'a'
('b' + 'a' + + 'a' + 'a') // "baNaNa"
('b' + 'a' + + 'a' + 'a').toLowerCase() // "banana"
+ 'a' // NaN
1
2
3
2
3
+ 'a'
会进行位运算。
Function.prototype.a = 'a';
Object.prototype.b = 'b';
function Person(){};
var p = new Person();
// 因为p是对象,会找到对象原型上,而不会找到函数原型上
console.log('p.a: '+ p.a); // p.a: undefined
console.log('p.b: '+ p.b); // p.b: b
1
2
3
4
5
6
7
2
3
4
5
6
7