2024年6月7日 太羞耻了,被原原本本问了这些问题,答不上来,答错了、。。。面试前一定会这些内容好吗
——————————————
之前遇到了就草草看过,却没有真的理解,过一段时间就忘记了,故做一个系统整理
宏任务、微任务
1.输出顺序
setTimeout(function () {
console.log(1) 、
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for (var i = 0; i < 10000; i++) {
i == 9999 && resolve();
}
console.log(3);
}).then(function () {
console.log(4);
});
console.log(5);
解答:
在这段代码中,输出顺序如下:
console.log(2);
console.log(3);
console.log(5);
console.log(4);
console.log(1);
这是因为在 JavaScript 中,Promise 中的 executor 函数是同步执行的,而 then() 方法中的回调函数是异步执行的。因此,先输出 Promise 中的内容,然后输出 Promise 的 then() 方法中的内容,最后输出 setTimeout 中的内容。
2.输出顺序
console.log('1. Start');
setTimeout(() => {
console.log('2. setTimeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('3. Promise 1');
setTimeout(() => {
console.log('4. setTimeout 2');
}, 0);
});
Promise.resolve().then(() => {
console.log('5. Promise 2');
});
console.log('6. End');
解答:
1. Start
6. End
3. Promise 1
5. Promise 2
2. setTimeout 1
4. setTimeout 2
3.宏任务、微任务有哪些(海康威视)
宏任务(macrotasks) 包括:
- 整体代码块(script)
- setTimeout
- setInterval
- I/O 操作
- UI 渲染
微任务(microtasks) 包括:
- Promise 的回调函数(.then())
- MutationObserver
- process.nextTick (Node.js 环境)
4.输出顺序
async function foo() {
console.log('foo');
return Promise.resolve('resolved');
}
async function bar() {
console.log('bar');
return foo();
}
bar().then(res => {
console.log(res);
});
console.log('end');
打印结果:
bar
foo
end
resolved
原型链
1.alert输出结果
var color = 'green';
var test4399 = {
color: 'blue',
getColor: function(){
var color = "red";
alert(this.color);
}
}
var getColor = test4399.getColor;
getColor();
test4399.getColor();
解答:
当一个函数作为对象的方法调用时,this 指向调用该方法的对象。
getColor(); :
由于 this 指向全局对象 window,所以 alert(this.color); 显示的会是 ‘green’。
test4399.getColor(); :
由于 this 指向 test4399,因此 alert(this.color); 显示的会是 ‘blue’。
2.现有如下代码:function Person(){};const person=new Person();
如下正确的选项是
A.person.__ proto__===Person.prototype 结果是:true
B.person.__ proto__.constructor===Person.prototype.constructor 结果是:true
C.person.constructor===Person 结果是:true
D.person.constructor===Person.constructor 结果是:tue
E.Person.prototype.constructor===person.constructor 结果是true
解答:
ABCE
- person.constructor === Person
- person._ proto _ === Person.prototype
- Person.prototype.constructor === Person
- A:
person
实例的原型指向Person
构造函数的原型,所以结果为true
。 - B:
person
实例的原型的构造函数指向Person
构造函数的原型的构造函数,也就是Person.prototype.constructor
,所以结果为true
。 - C:
person
实例的构造函数指向Person
构造函数本身,所以结果为true
。 - D:构造函数没有
constructor
属性,constructor
属性存在于原型对象或实例对象上。因此,你不能直接通过构造函数来访问constructor
属性。 - E:
Person.prototype.constructor
指向Person
构造函数本身,而person.constructor
指向Person
构造函数本身,所以结果为true
。
在 JavaScript 中,每个对象都有一个原型对象和一个构造函数。下面是它们的定义:
- 构造函数:构造函数是用来创建对象的函数。当使用关键字
new
来调用构造函数时,会创建一个新的对象实例并将其返回。构造函数通常用大写字母开头来区分普通函数。
function Person(name) {
this.name = name;
}
const person = new Person('Alice');
- 原型对象:每个函数都有一个
prototype
属性,这个属性指向一个对象,这个对象就是原型对象。原型对象包含共享的属性和方法,可以被该函数创建的所有对象实例访问。
Person.prototype.sayHello = function() {
console.log('Hello, my name is ' + this.name);
};
- 实例对象:实例对象是通过构造函数创建的对象。它继承了构造函数的原型对象的属性和方法,并可以访问这些属性和方法。
const person = new Person('Alice');
person.sayHello(); // 输出:Hello, my name is Alice
总结:构造函数用于创建对象实例,每个构造函数都有一个原型对象,实例对象可以访问构造函数原型对象中的属性和方法。
3.输出结果
function Animal(name) {
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.getBreed = function() {
return this.breed;
};
const dog1 = new Dog("Buddy", "Golden Retriever");
console.log(dog1.getName()); // 输出1
console.log(dog1.getBreed()); // 输出2
const logName = dog1.getName;
console.log(logName()); // 输出3
const logBreed = dog1.getBreed.bind(dog1);
console.log(logBreed()); // 输出4
解答:
在给定的代码中,定义了 Animal 和 Dog 两个构造函数,并设置了它们的原型链关系。接着创建了一个名为 dog1 的 Dog 实例,并调用了其方法。
根据代码逐行分析,输出结果如下:
-
console.log(dog1.getName());
// 输出1- 输出为 “Buddy”,因为 dog1 是一个 Dog 实例,继承了 Animal 的 getName 方法,返回实例的 name 属性值 “Buddy”。
-
console.log(dog1.getBreed());
// 输出2- 输出为 “Golden Retriever”,因为 dog1 是一个 Dog 实例,具有自己的 breed 属性,getBreed 方法返回该属性值。
-
const logName = dog1.getName; console.log(logName());
// 输出3- 输出为 undefined,因为在这里将 getName 方法赋值给 logName 时,实际上是将该方法提取出来,与 dog1 实例的上下文关联丢失,导致 this 指向丢失,所以返回 undefined。
-
const logBreed = dog1.getBreed.bind(dog1); console.log(logBreed());
// 输出4- 输出为 “Golden Retriever”,通过使用 bind 方法将 dog1 实例绑定到 getBreed 方法中,确保了方法执行时 this 指向正确的对象,因此返回 “Golden Retriever”。
因此,四个输出分别是:
5. Buddy
6. Golden Retriever
7. undefined
8. Golden Retriever
在这段代码中,Animal.call(this, name);
的作用是调用Animal
构造函数,并将this
指向Dog
构造函数内部创建的对象,同时传入name
作为参数。
具体解释如下:
-
Animal.call(this, name);
: 这行代码实际上是在Dog
构造函数内部调用Animal
构造函数。通过使用call
方法,我们可以指定函数内部的this
指向哪个对象,这里我们将this
指向了Dog
构造函数内部创建的对象,以确保Animal
构造函数中的属性和方法能够正确地被继承。 -
name
: 这是作为参数传递给Animal
构造函数的值,用来初始化Animal
对象的name
属性。通过将name
参数传递给Animal
构造函数,我们可以在创建Dog
对象时同时初始化Animal
对象的属性。
总的来说,Animal.call(this, name);
这段代码的作用是在Dog
构造函数内部调用Animal
构造函数,并将this
指向Dog
对象,以实现一种继承关系,确保Dog
对象能够正确地继承Animal
对象的属性和方法。
这段代码中的两行:
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
是实现继承的关键部分。让我们来解释一下:
-
Dog.prototype = Object.create(Animal.prototype);
: 这一行代码创建了一个新的对象,这个新对象的原型是Animal.prototype
。这样一来,Dog.prototype
就继承了Animal.prototype
上的方法和属性。这是一种常见的原型继承方式,通过创建一个空的中间对象来实现继承。初次之外我们还会将Dog的原型指向一个新创建的Animal实例Dog.prototype = new Animal();Dog.prototype.constructor = Dog;
来实现继承。 -
Dog.prototype.constructor = Dog;
: 这一行代码将Dog.prototype
对象的constructor
属性指向Dog
构造函数本身。在上一行代码中,我们将Dog.prototype
设置为一个新对象,这个新对象不再具有默认的constructor
属性,因此我们需要手动将constructor
属性指回Dog
构造函数,以确保对象的constructor
属性指向正确的构造函数。
关于const logBreed = dog1.getBreed.bind(dog1);
这行代码的意思是,它创建了一个新的函数logBreed
,这个新函数是dog1.getBreed
的一个绑定版本,其中this
被永久绑定到dog1
对象。这样,在调用logBreed()
时,无论在什么上下文中调用,getBreed()
方法中的this
都会指向dog1
对象。
原型链继承和对象属性方法的继承是不同的概念,它们涉及到JavaScript中的原型机制和继承方式。
-
原型链:
- 在JavaScript中,每个对象都有一个指向另一个对象的引用,这个对象就是它的原型。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript会沿着原型链向上查找,直到找到对应的属性或方法为止。
- 原型链是由对象之间的原型引用构成的链式结构,通过原型链,子对象可以继承父对象的属性和方法。
-
对象属性方法的继承:
- 通过构造函数和原型链的组合,我们可以实现对象之间属性和方法的共享。在JavaScript中,通过在构造函数中调用父类构造函数来继承父类的属性,通过设置子类的原型为父类的实例来继承父类的方法。
function Dog(name, breed) { Animal.call(this, name); // 在子类构造函数中调用父类构造函数 this.breed = breed; } Dog.prototype = new Animal(); // 设置子类的原型为父类的实例
- 对象属性方法的继承主要涉及到构造函数和原型之间的关系,确保子类对象能够正确地继承父类对象的属性和方法。
总的来说,原型链是JavaScript中用来实现对象之间继承关系的机制,而对象属性方法的继承是通过构造函数和原型链的方式来实现对属性和方法的继承。原型链继承和对象属性方法的继承是紧密相关的概念,都是为了实现对象之间的属性和方法的共享和继承。