综合习题

3/22/2022 running

# 1. js引用类型

下面代码输出什么?

var a = {n: 1}
var b = a
a.x = a = {n: 2}
console.log(a.x)
console.log(b.x)
1
2
3
4
5
查看答案

结果
undefined
{n: 2}

  1. a 和 b 同时引用了 {n: 2} 对象
  2. 执行到 a.x = a = {n: 2} 语句
    • 尽管赋值是从右到左的没错,但是.的优先级比=要高,所以这里首先执行a.x,相当于为 a所指向的{n: 1}对象新增了一个属性x,即此时对象将变为 { n: 1, x: undefined }
    • 之后按正常情况,从右到左进行赋值,此时执行 a = {n: 2} 的时候,a的引用改变,指向了新对象{n: 2},而b依然指向的是旧对象
    • 之后执行 a.x = {n: 2} 的时候,并不会重新解析一遍a,而是沿用最初解析a.x时候的a,也即旧对象,故此时旧对象的x的值为{n: 2},旧对象为 { n: 1, x: {n: 2} },它被b引用着。
  3. 访问 a.x 的时候,又要解析a了,此时的a是指向新对象的a,而这个新对象是没有x属性的,故访问时输出 undefined
  4. 访问 b.x 的时候,将输出旧对象的x的值,即{n: 2}

# 2. js类型

下面代码输出什么?

// example 1 
var a = {},
    b = '123',
    c = 123;
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
// example 2
var a = {},
    b = Symbol('123'),
    c = Symbol('123');
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
// example 3
var a = {},
    b = {
        key: '123'
    },
    c = {
        key: '456'
    };
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
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
查看答案
  • example 1: 'c'
  • example 2: 'b'
  • example 3: 'c'
查看解析
  1. 对象的键名只能是字符串和 Symbol 类型。
  2. 其他类型的键名会被转换成字符串类型。
  3. 对象转字符串默认会调用 toString 方法。

// example 1

  • c的键名会被转换成字符串'123',这里会把b覆盖掉,输出'c'

// example 2

  • b 是 Symbol 类型,不需要转换
  • c 是 Symbol 类型,不需要转换
  • 任何一个 Symbol 类型的值都是不相等的, 所以不会覆盖掉b,输出'b'

// example 3

  • b 不是字符串也不是 Symbol 类型,需要转换成字符串。对象类型会调用 toString 方法转换成字符串 [object Object]
  • c 不是字符串也不是 Symbol 类型,需要转换成字符串。对象类型会调用 toString 方法转换成字符串 [object Object]
  • 所以这里会把 b 覆盖掉,输出'c'

# 3. js引用类型2

下面代码输出什么?

function changeObjProperty(o) {
    o.siteUrl = "http://www.baidu.com"
    o = new Object()
    o.siteUrl = "http://www.google.com"
}
let webSite = new Object();
changeObjProperty(webSite);
console.log(webSite.siteUrl);
1
2
3
4
5
6
7
8
查看答案

// http://www.baidu.com

  1. webSite 属于复合数据类型,函数参数中以地址传递,修改值会影响到原始值。
  2. 但是之后o指向了新的地址,修改了新的地址的值,原值没有收到影响。
  3. 所以输出的是 http://www.baidu.com

# 4. 类

请写出如下代码的打印结果

function Foo() {
    Foo.a = function () {
        console.log(1);
    };
    this.a = function () {
        console.log(2);
    };
}
Foo.prototype.a = function () {
    console.log(3);
};
Foo.a = function () {
    console.log(4);
};
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
查看答案

// 4 2 1

  • 第一个 Foo.a() 是调用Foo的静态方法,因为构造函数没有调用,所以内部方法没有执行,所以会执行外面的4
  • 第二个 obj.a() 是实例化的Foo,调用a会先查找内部ownProperty,再去找原型链,所以这里输出2
  • 第三个 Foo.a() 构造函数已经调用,内部方法优先级高,已经覆盖同名的静态方法,所以会执行内部1

# 5. 隐式类型转换

请写出如下代码的打印结果

const foo = {
  toString () {
    return 'xm'
  },
  valueOf () {
    return 1
  }
}
console.log(1+foo)
1
2
3
4
5
6
7
8
9
查看答案

// 2

  • 加法运算符,foo对象会调用其toString方法或者valueOf方法,所以我们经常会通过改变这两种方法控制加法的运算结果。
  • 如果只有toString则会输出1xm,如果只有valueOf则会输出2,如果两者都有,这道题valueOf优先。
更新时间: 2022-04-10 13:23