JS面试题汇总(八)

news/2024/7/19 15:09:03 标签: javascript, js, 前端, 面试, es6

📒博客首页:酸狗的博客🍋
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
💖热爱前端学习,期待一起交流!✨
🙏作者水平很有限,如果发现错误,求告知,多谢!🌈
😎有问题可私信我交流🙄

🧲往期点这里:↓⚡
JS面试题汇总(一)
JS面试题汇总(二)
JS面试题汇总(三)
JS面试题汇总(四)
JS面试题汇总(五)
JS面试题汇总(六)
JS面试题汇总(七)
71. IE 和标准下有哪些兼容性的写法

参考答案:

js">var ev = ev || window.event;
document.documentElement.clientWidth || document.body.clientWidth;
var target = ev.srcElement || ev.target;

72. 变量提升

参考答案:

变量提升

A、js 代码执行的过程

  • 1 变量提升
  • 2 代码从上到下依次执行

var 关键字和 function 关键字声明的变量会进行变量提升

B、变量提升发生的环境:发生在代码所处的当前作用域。

  • 变量提升
  • 1 var 关键字进行的变量提升,会把变量提前声明,但是不会提前赋值 。
  • 2 function 关键字对变量进行变量提升,既会把变量提前声明,又会把变量提前赋值,也就是把整个函数体提升到代码的顶部
  • 3 有一些代码是不会执行的但是仍旧会发生变量提升, 规则适用于 1, 2
    1. 1 return 之后的代码依旧会发生变量提升,规则适用于 1,2
    1. 2 代码报错之后的代码依旧会发生变量提升,规则适用于 1,2
    1. 3 break 之后的代码依旧会发生变量提升,规则适用于 1, 2
  • 4 有一些代码是不会执行但是仍旧会发生变量提升,但是规则要发生变化
    1. 1 if 判断语句 if 判断语句中 var 关键字以及 function 关键字声明的变量只会发生提前声明,不会发生提前赋值, 也就是不会吧函数体整体提升到当前作用域顶部。规则跟 1, 2 不适用
    1. 2 switch case 规则跟 1, 2 不适用
    1. 3 do while 规则跟 1, 2 不适用
    1. 4 try catch catch 中声明的变量只会发生提前声明,不会发生提前赋值。
  • Ps: 在条件判断语句和 try catch 中的声明的变量不管是否能够执行,都只会发生提前
  • 声明,不会发生提前赋值。

解析:

js">// 如果一个变量声明了但是未赋值,那么输出这个变量就会输出 undefined
var num;
console.log(num);

// 如果一个变量没有声明也没有赋值,那么就会报一个错:
console.log(num); // 输出一个不存在的变量 Uncaught ReferenceError: num is not defined
js">// var 关键字进行的变量提升
console.log(num);
var num = 123;
console.log(num);
var num = 456;
console.log(num);

// 变量提升之后的代码:
var num;
console.log(num);
num = 123;
console.log(num);
num = 456;
console.log(num);
js">// function 关键字的变量提升
console.log(fn);

function fn() {
    console.log(1);
}

// 变量提升之后的代码:
function fn() {
    console.log(1);
}
console.log(fn); // 输出fn的函数体
js">// 3.1 return 之后的代码依旧会发生变量提升  规则适用于1,2
function fn() {
    console.log(num);
    return;
    var num = 123;
}
fn();

// 变量提升之后的代码:
function fn() {
    var num;
    console.log(num);
    return;
    num = 123;
}
fn(); // undefined

function fn() {
    console.log(fo);
    return;

    function fo() {}
}
fn();

// 变量提升之后的代码:
function fn() {
    function fo() {}
    console.log(fo);
    return;
}
fn(); //输出fo的函数体
js">//3.2 代码报错之后的代码依旧会进行变量提升,规则适用于1,2
console.log(num);
xsasfgdsfqdfsdf; //报一个错
var num = 123;
console.log(num);

// 变量提升之后的代码:
var num;
console.log(num); //输出 undefined
dsagdsqghdwfh; // 报一个错误 ,错误之后的代码不会被执行
num = 123;
console.log(num);
js">//function 关键字
console.log(fn);
sasgfdhwhsdqg;

function fn() {}
console.log(fn);

// 变量提升之后的代码:
function fn() {}
console.log(fn); // 输出 fn 的函数体
asdgsdgdfgfdg; // 报一个错误,报错之后的代码不会被执行
console.log(fn);
js">//4 代码不执行,但是会进行变量提升,不过规则不适用于1,2
//4.1 if判断语句
console.log(num);
if (false) {
    var num = 123;
}
console.log(num)

//  变量提升之后的代码:
var num;
console.log(num); //undefined
if (false) {
    num = 123;
}
console.log(num) //undefined

console.log(fn);
if (false) {
    function fn() {}
}
console.log(fn);

// 变量提升之后的代码:
var fn;

function fn;
console.log(fn) //undefined
if (false) {
    function fn() {}
}
console.log(fn) //undefined
/*function fn//Uncaught SyntaxError: Unexpected end of input*/
js">// try catch
try {
    console.log(num);
} catch (e) {
    var num = 123;
}
console.log(num);

var num;
try {
    console.log(num); // undefined
} catch (e) {
    num = 123;
}
console.log(num); // undefined

try {
    console.log(fn);
} catch (e) {
    function fn() {}
}
console.log(fn);

var fn;
try {
    console.log(fn); // undefined
} catch (e) {
    num = 123;
}
console.log(fn); // undefined

73. 如何阻止冒泡与默认行为

参考答案:

  • 阻止冒泡行为:非 IE 浏览器 stopPropagation(),IE 浏览器 window. event. cancelBubble = true
  • 阻止默认行为:非 IE 浏览器 preventDefault(),IE 浏览器 window. event. returnValue = false

解析:

当需要阻止冒泡行为时,可以使用

js">function stopBubble(e) {
    //如果提供了事件对象,则这是一个非IE浏览器
    if (e && e.stopPropagation)
        //因此它支持W3C的stopPropagation()方法
        e.stopPropagation();
    //否则,我们需要使用IE的方式来取消事件冒泡
    else window.event.cancelBubble = true;
}

当需要阻止默认行为时,可以使用

js">//阻止浏览器的默认行为
function stopDefault(e) {
    //阻止默认浏览器动作(W3C)
    if (e && e.preventDefault) e.preventDefault();
    //IE中阻止函数器默认动作的方式
    else window.event.returnValue = false;
    return false;
}

74. js 中 this 闭包 作用域

参考答案:

this:指向调用上下文

闭包:定义一个函数就开辟了一个局部作用域,整个 js 执行环境有一个全局作用域

作用域:一个函数可以访问其他函数中的变量(闭包是一个受保护的变量空间)

js">var f = (function fn() {
        var name = 1;
        return function() {
            name++;
            console.log(name)
        }
    })()

    ==
    >
    undefined 有疑问

75. javascript 的本地对象,内置对象和宿主对象

参考答案:

1. 本地对象

ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象"。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError

2. 内置对象

JS中内置了17个对象,常用的是Array对象、Date对象、正则表达式对象、string对象、Global对象

3. 宿主对象

由ECMAScript实现的宿主环境提供的对象,可以理解为:浏览器提供的对象。所有的BOM和DOM都是宿主对象。

76. javascript 的同源策略

参考答案:

一段脚本只能读取来自于同一来源的窗口和文档的属性

解析:

同源策略:限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自 MDN 官方的解释)

简单来说就是:一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合
具体解释:

(1)源包括三个部分:协议、域名、端口(http 协议的默认端口是 80)。如果有任何一个部分不同,则源不同,那就是跨域了。

(2)限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:(要记住)

Cookie、LocalStorage 和 IndexDB 无法获取。

无法获取和操作 DOM。

不能发送 Ajax 请求。我们要注意,Ajax 只适合同源的通信。

同源策略带来的麻烦:ajax 在不同域名下的请求无法实现,需要进行跨域操作

77. 事件冒泡与事件捕获

参考答案:

事件冒泡:由最具体的元素(目标元素)向外传播到最不具体的元素

事件捕获:由最不确定的元素到目标元素

78. foo = foo||bar ,这行代码是什么意思?为什么要这样写?

参考答案:

这种写法称为短路表达式

解析:

相当于

js">var foo;
if (foo) {
    foo = foo;
} else {
    foo = bar;
}

常用于函数参数的空判断

79. 复杂数据类型如何转变为字符串

参考答案:

  • 首先,会调用 valueOf 方法,如果方法的返回值是一个基本数据类型,就返回这个值
  • 如果调用 valueOf 方法之后的返回值仍旧是一个复杂数据类型,就会调用该对象的 toString 方法
  • 如果 toString 方法调用之后的返回值是一个基本数据类型,就返回这个值,
  • 如果 toString 方法调用之后的返回值是一个复杂数据类型,就报一个错误。

80. javascript 中 this 的指向问题

参考答案:

  • 全局环境、普通函数(非严格模式)指向 window
  • 普通函数(严格模式)指向 undefined
  • 函数作为对象方法及原型链指向的就是上一级的对象
  • 构造函数指向构造的对象
  • DOM 事件中指向触发事件的元素
  • 箭头函数…

解析:

1、全局环境

全局环境下,this 始终指向全局对象(window),无论是否严格模式;

js">// 在浏览器中,全局对象为 window 对象:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37

2、函数上下文调用

2. 1 普通函数

普通函数内部的 this 分两种情况,严格模式和非严格模式。

(1)非严格模式下,没有被上一级的对象所调用, this 默认指向全局对象 window。

js">function f1() {
    return this;
}
f1() === window; // true

(2)严格模式下,this 指向 undefined。

js">function f2() {
    "use strict"; // 这里是严格模式
    return this;
}
f2() === undefined; // true

2. 2 函数作为对象的方法

(1)函数有被上一级的对象所调用,那么 this 指向的就是上一级的对象。

(2)多层嵌套的对象,内部方法的 this 指向离被调用函数最近的对象(window 也是对象,其内部对象调用方法的 this 指向内部对象, 而非 window)。

js">//方式1
var o = {
    prop: 37,
    f: function() {
        return this.prop;
    }
};
//当 o.f()被调用时,函数内的this将绑定到o对象。
console.log(o.f()); // logs 37

//方式2
var o = {
    prop: 37
};

function independent() {
    return this.prop;
}
//函数f作为o的成员方法调用
o.f = independent;
console.log(o.f()); // logs 37

//方式3
//this 的绑定只受最靠近的成员引用的影响
o.b = {
    g: independent,
    prop: 42
};
console.log(o.b.g()); // 42

特殊例子

js">// 例子1
var o = {
    a: 10,
    b: {
        // a:12,
        fn: function() {
            console.log(this.a); //undefined
            console.log(this); //{fn: ƒ}
        }
    }
};
o.b.fn();
// 例子2
var o = {
    a: 10,
    b: {
        a: 12,
        fn: function() {
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
};
var j = o.b.fn;
j();
// this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子2中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子1是不一样的,例子1是直接执行了fn

2. 3 原型链中的 this

(1)如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法在对象上一样。

js">var o = {
    f: function() {
        return this.a + this.b;
    }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

上述例子中,对象 p 没有属于它自己的 f 属性,它的 f 属性继承自它的原型。当执行 p. f()时,会查找 p 的原型链,找到 f 函数并执行。因为 f 是作为 p 的方法调用的,所以函数中的 this 指向 p。

(2)相同的概念也适用于当函数在一个 getter 或者 setter 中被调用。用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。

(3)call()和 apply()方法:当函数通过 Function 对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的 this 值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript 内部会尝试将其转换成对象然后指向它。

js">function add(c, d) {
    return this.a + this.b + c + d;
}
var o = {
    a: 1,
    b: 3
};

add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

function tt() {
    console.log(this);
}
// 第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。
tt.call(5); // 内部转成 Number {[[PrimitiveValue]]: 5}
tt.call("asd"); // 内部转成 String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}

(4)bind()方法:由 ES5 引入, 在 Function 的原型链上, Function. prototype. bind。通过 bind 方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

js">function f() {
    return this.a;
}

var g = f.bind({
    a: "azerty"
});
console.log(g()); // azerty

var o = {
    a: 37,
    f: f,
    g: g
};
console.log(o.f(), o.g()); // 37, azerty

2. 4 构造函数中的 this

当一个函数用作构造函数时(使用 new 关键字),它的 this 被绑定到正在构造的新对象。

构造器返回的默认值是 this 所指的那个对象,也可以手动返回其他的对象。

js">function C() {
    this.a = 37;
}

var o = new C();
console.log(o.a); // 37
// 为什么this会指向o?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。

function C2() {
    this.a = 37;
    return {
        a: 38
    }; // 手动设置返回{a:38}对象
}

o = new C2();
console.log(o.a); // 38

特殊例子

当 this 碰到 return 时

js">// 例子1
function fn() {
    this.user = "追梦子";
    return {};
}
var a = new fn();
console.log(a.user); //undefined
// 例子2
function fn() {
    this.user = "追梦子";
    return function() {};
}
var a = new fn();
console.log(a.user); //undefined
// 例子3
function fn() {
    this.user = "追梦子";
    return 1;
}
var a = new fn();
console.log(a.user); //追梦子
// 例子4
function fn() {
    this.user = "追梦子";
    return undefined;
}
var a = new fn();
console.log(a.user); //追梦子
// 例子5
function fn() {
    this.user = "追梦子";
    return undefined;
}
var a = new fn();
console.log(a); //fn {user: "追梦子"}
// 例子6
// 虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊
function fn() {
    this.user = "追梦子";
    return null;
}
var a = new fn();
console.log(a.user); //追梦子

// 总结:如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。

2. 5 setTimeout & setInterval

(1)对于延时函数内部的回调函数的 this 指向全局对象 window;

(2)可以通过 bind()方法改变内部函数 this 指向。

js">//默认情况下代码
function Person() {
    this.age = 0;
    setTimeout(function() {
        console.log(this);
    }, 3000);
}

var p = new Person(); //3秒后返回 window 对象
//通过bind绑定
function Person() {
    this.age = 0;
    setTimeout(
        function() {
            console.log(this);
        }.bind(this),
        3000
    );
}

var p = new Person(); //3秒后返回构造函数新生成的对象 Person{...}

3、在 DOM 事件中

3. 1 作为一个 DOM 事件处理函数

当函数被用作事件处理函数时,它的 this 指向触发事件的元素(针对 addEventListener 事件)。

js">// 被调用时,将关联的元素变成蓝色
function bluify(e) {
    //this指向所点击元素
    console.log("this === e.currentTarget", this === e.currentTarget); // 总是 true
    // 当 currentTarget 和 target 是同一个对象时为 true
    console.log("this === e.target", this === e.target);
    this.style.backgroundColor = "#A5D9F3";
}

// 获取文档中的所有元素的列表
var elements = document.getElementsByTagName("*");

// 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for (var i = 0; i < elements.length; i++) {
    elements[i].addEventListener("click", bluify, false);
}

3. 2 作为一个内联事件处理函数

(1)当代码被内联处理函数调用时,它的 this 指向监听器所在的 DOM 元素;

(2)当代码被包括在函数内部执行时,其 this 指向等同于 普通函数直接调用的情况,即在非严格模式指向全局对象 window,在严格模式指向 undefined:

<button onclick="console.log(this)">show me</button>
<button onclick="(function () {console.log(this)})()">show inner this</button>
<button onclick="(function () {'use strict'; console.log(this)})()">
    use strict
</button>

// 控制台打印
<button onclick="console.log(this)">show me</button>
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
undefined

4、箭头函数

4. 1 全局环境中

在全局代码中,箭头函数被设置为全局对象:

js">var globalObject = this;
var foo = () => this;
console.log(foo() === globalObject); // true

4. 2 this 捕获上下文

箭头函数没有自己的 this,而是使用箭头函数所在的作用域的 this,即指向箭头函数定义时(而不是运行时)所在的作用域。

js">//1、箭头函数在函数内部,以非方法的方法使用
function Person() {
    this.age = 0;
    setInterval(() => {
        this.age++;
    }, 3000);
}
var p = new Person(); //Person{age: 0}

//普通函数作为内部函数
function Person() {
    this.age = 0;
    setInterval(function() {
        console.log(this);
        this.age++;
    }, 3000);
}
var p = new Person(); //Window{...}

4. 2 this 捕获上下文

箭头函数没有自己的 this,而是使用箭头函数所在的作用域的 this,即指向箭头函数定义时(而不是运行时)所在的作用域。

js">//1、箭头函数在函数内部,以非方法的方法使用
function Person() {
    this.age = 0;
    setInterval(() => {
        console.log(this);
        this.age++;
    }, 3000);
}
var p = new Person(); //Person{age: 0}

//普通函数作为内部函数
function Person() {
    this.age = 0;
    setInterval(function() {
        console.log(this);
        this.age++;
    }, 3000);
}
var p = new Person(); //Window{...}

在 setTimeout 中的 this 指向了构造函数新生成的对象,而普通函数指向了全局 window 对象。

4. 3 箭头函数作为对象的方法使用

箭头函数作为对象的方法使用,指向全局 window 对象;而普通函数作为对象的方法使用,则指向调用的对象。

js">var obj = {
    i: 10,
    b: () => console.log(this.i, this),
    c: function() {
        console.log(this.i, this);
    }
};
obj.b(); // undefined window{...}
obj.c(); // 10 Object {...}

4. 4 箭头函数中,call()、apply()、bind()方法无效

js">var adder = {
    base: 1,
    //对象的方法内部定义箭头函数,this是箭头函数所在的作用域的this,
    //而方法add的this指向adder对象,所以箭头函数的this也指向adder对象。
    add: function(a) {
        var f = v => v + this.base;
        return f(a);
    },
    //普通函数f1的this指向window
    add1: function() {
        var f1 = function() {
            console.log(this);
        };
        return f1();
    },
    addThruCall: function inFun(a) {
        var f = v => v + this.base;
        var b = {
            base: 2
        };

        return f.call(b, a);
    }
};

console.log(adder.add(1)); // 输出 2
adder.add1(); //输出全局对象 window{...}
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3,其内部的this并没有因为call() 而改变,其this值仍然为函数inFun的this值,指向对象adder

4. 5 this 指向固定化

箭头函数可以让 this 指向固定化,这种特性很有利于封装回调函数

js">var handler = {
    id: "123456",

    init: function() {
        document.addEventListener(
            "click",
            event => this.doSomething(event.type),
            false
        );
    },

    doSomething: function(type) {
        console.log("Handling " + type + " for " + this.id);
    }
};

上面代码的 init 方法中,使用了箭头函数,这导致这个箭头函数里面的 this,总是指向 handler 对象。如果不使用箭头函数则指向全局 document 对象。

4. 6 箭头函是不适用场景

(1)箭头函数不适合定义对象的方法(方法内有 this),因为此时指向 window;

(2)需要动态 this 的时候,也不应使用箭头函数。

js">//例1,this指向定义箭头函数所在的作用域,它位于对象cat内,但cat不能构成一个作用域,所以指向全局window,改成普通函数后this指向cat对象。
const cat = {
    lives: 9,
    jumps: () => {
        this.lives--;
    }
};

//例2,此时this也是指向window,不能动态监听button,改成普通函数后this指向按钮对象。
var button = document.getElementById("press");
button.addEventListener("click", () => {
    this.classList.toggle("on");
});

http://www.niftyadmin.cn/n/805939.html

相关文章

用CSS样式实现显示隐藏层 (转)

用CSS样式实现显示隐藏层 (转)[more]CSS样式实现显示隐藏层 作者: 严正来自: www.oso.com.cn此方法不用Javascript&#xff0c;代码少、简单&#xff0c;显示的层自动在链接处 以下代码加入页面中&#xff0c;鼠标悬浮于链接“1234567890”上时&#xff0c;层内容“1111111…

【JUC源码系列】Fork / Join 框架源码解析

Fork / Join 使用 ForkJoinTask&#xff1a;我们要使用 ForkJoin 框架&#xff0c;必须首先创建一个 ForkJoin 任务。它提供在任务中执行 fork() 和 join() 操作的机制&#xff0c;通常情况下我们不需要直接继承 ForkJoinTask 类&#xff0c;而只需要继承它的子类&#xff0c…

学完计组后,我马上在「我的世界」造了台显示器,你敢信?

前言今天的主题十分有趣&#xff0c;我们将在我的世界(Minecraft)这个游戏里&#xff0c;靠一个个逻辑门来组合实现一个简单的七段显示器&#xff0c;可以实现将选择的数字输出在显示器上。演示视频在下面&#xff0c;来看看这个宏大的工程&#xff1a;接下来&#xff0c;我会从…

Linux Deepin 2014安装Lenovo LJ2600D驱动

双11老师给实验室抢了个Lenovo LJ2600D的USB接口打印机&#xff0c;并用旧的HP-1080MFP网络打印服务器连接上了。Windows下就不多说了&#xff0c;官方给的驱动就是针对它的&#xff0c;同学们都用得爽爆了&#xff0c;因为他们用的全是Windows&#xff0c;可怜了我这个Linux娃…

java获取当前时间加半小时之后的时间

1、获取当前时间&#xff0c;获取到的时间类型是long类型的&#xff0c;单位是毫秒long currentTime System.currentTimeMillis() ;2、在这个基础上加上30分钟&#xff1a;currentTime 30*60*1000&#xff1b;3、格式化时间&#xff0c;获取到的就是当前时间半个小时之后的时间…

C++Builder和Delphi中的复活节彩蛋 (转)

CBuilder和Delphi中的复活节彩蛋 (转)[more]CBuilder和Delphi中的复活节彩蛋XML:namespace prefix o ns "urn:schemas-microsoft-com:Office:office" /> ideograph; TEXT-INDENT: 21pt; TEXT-ALIGN: justify">许多软件中都带有复活节彩蛋&#xff0c;也…

VUE面试题汇总(四)

往期点这里&#xff1a;↓ VUE面试题汇总&#xff08;一&#xff09; VUE面试题汇总&#xff08;二&#xff09; VUE面试题汇总&#xff08;三&#xff09; 31. v-model 语法糖的组件中的使用 参考答案&#xff1a; <input type"text" v-model"mes"&g…

【JVM系列】运行时数据区域详解

运行时数据区域 程序计数器 在任何一个确定的时刻&#xff0c;一个处理器&#xff08;对于多核处理器来说是一个内核&#xff09;都只会执行一条线程中的指令。因此&#xff0c;为了线程切换后能恢复到正确的执行位置&#xff0c;每条线程都需要有一个独立的程序计数器&#x…