面试官:聊聊js原型

简介: 面试官:聊聊js原型

一分钟了解原型对象

js分为函数对象和普通对象 ,每个对象都有__proto__属性,但是只有函数对象才有prototype属性,prototype属性就是函数的原型对象。


比如说 构造函数通过new 实化一个实例对象,实例对象的__proto__ 指向原型对象 ,同时构造函数prototype也指向原型对象。


比如:

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHello = function() {
  console.log("Hello, my name is " + this.name + " and I am " + this.age + " years old.");
}
var person1 = new Person("Alice", 25);
var person2 = new Person("Bob", 30);
person1.sayHello(); // 输出:Hello, my name is Alice and I am 25 years old.
person2.sayHello(); // 输出:Hello, my name is Bob and I am 30 years old.

Person是一个函数,也是构造函数,他的prototype就是指向原型对象。我们使用 Person.prototype 对象来为每个 Person 对象定义了一个共同的方法 sayHello。这个方法输出了一个字符串,表示人物的名字和年龄。


我们使用 new 关键字来创建了两个 Person 对象,并且分别调用了 sayHello 方法,输出了不同的字符串。这是因为 person1 和 person2 都继承了 Person.prototype 对象上的 sayHello 方法,但是它们的属性值是不同的。


原型对象到底是什么?


可以将原型对象比做是一个模板,这个模板包含了一些常用属性和方法,然后我们可以用它来创建新的对象。就像是我们可以用一个模板来快速制作许多同样的产品一样,每个产品的具体细节可能不同,但是它们的基本结构和特征都是相同的。


比如说,我们可以有一个“车”的原型对象,它包含了一些常用的属性和方法,比如车型、品牌、最高时速、加速度等等。然后我们可以用这个原型对象来创建许多不同的车型,如轿车、卡车、摩托车等等。由于这些车型都基于同一个原型对象创建,因此它们都具有相同的基本特征和结构,但是具体的细节可能略有不同,比如轿车和卡车的尺寸、载重等等。


同样地,在JavaScript中,我们可以使用原型对象来快速创建多个对象,并且这些对象都具有相同的基本特征和方法。这种基于原型对象的方式可以实现代码的重用,提高开发效率。


原型对象能干什么

上面的例子已经说明,我们可以在函数的prototype熟悉,也就是原型对象上添加熟悉和方法,这些都会被将来根据这个函数new出来的对象继承。


原型对象在JavaScript中有着重要的作用,常常用于以下几个方面:


实现继承:通过原型对象,我们可以创建新的对象,并且继承原型对象上的属性和方法。这种基于原型的继承方式可以让我们更方便地实现面向对象编程。


共享属性和方法:通过将属性和方法定义在原型对象上,我们可以让多个对象共享这些属性和方法。这样可以减少内存占用,提高代码的效率。


扩展对象:通过修改原型对象,我们可以在运行时扩展对象的属性和方法。这种动态扩展对象的方式可以让我们更加灵活地处理对象。


实现一些常用的方法和功能:原型对象上已经包含了一些常用的方法和功能,比如 toString、valueOf 等等。通过在原型对象上定义相应的方法,我们可以为对象实现这些常用方法,以便在开发过程中更加便捷地使用。


举个栗子:

function Person() {}
Person.prototype.sayHello = function() {
  console.log("Hello, I'm a person.");
}
function Student() {}
Student.prototype = Object.create(Person.prototype);
const alice = new Student();
alice.sayHello(); // 输出:Hello, I'm a person.

在这个例子中,我们通过原型链访问了alice对象的原型对象,然后通过它的原型对象调用了sayHello方法。由于Student函数的原型对象继承自Person函数的原型对象,因此alice对象也继承了Person函数的原型对象上的方法和属性。


proto

__proto__是JavaScript中的一个内置属性,它指向对象的原型。在JavaScript中,每个对象都有一个原型对象,这个原型对象包含了对象的所有属性和方法,用来定义对象的共同属性和方法。__proto__属性就是用来表示对象的原型的。


例如,我们可以使用以下代码来创建一个简单的对象,然后查看其__proto__属性:

const person = {
  name: "Alice",
  age: 25
};
console.log(person.__proto__); // 输出:Object {}

上面的代码中,我们定义了一个名为person的对象,它有两个属性:name和age。然后,我们使用console.log()方法输出了person.__proto__属性,这个属性指向的是这个对象的原型对象,也就是Object对象。


需要注意的是,__proto__是一个非标准的属性,在ECMAScript 2015 标准中已经不推荐使用。应该使用Object.getPrototypeOf()方法或Object.setPrototypeOf()方法来操作对象的原型。例如,我们可以使用以下方法来获取一个对象的原型:

const person = {
  name: "Alice",
  age: 25
};
console.log(Object.getPrototypeOf(person)); // 输出:Object {}

上面的代码中,我们使用Object.getPrototypeOf()方法来获取person对象的原型,它返回的是一个Object对象。


__proto__有什么作用

查看对象的原型

我们可以使用__proto__访问一个对象的原型,以便了解它的继承关系。例如:


function Person() {}
const alice = new Person();
console.log(alice.__proto__); // 输出:Person {}

在这个例子中,我们创建了一个Person函数并使用它创建了一个alice对象。然后,通过alice.__proto__访问了alice对象的原型,这个原型就是Person函数的原型对象。


创建对象的原型链

我们可以使用__proto__来创建对象的原型链。例如:


function Person() {}
const alice = {
  name: "Alice"
};
alice.__proto__ = Person.prototype;
console.log(alice instanceof Person); // 输出:true

在这个例子中,我们定义了一个空对象alice,然后将它的原型链指向了Person函数的原型对象。由于alice对象的原型链继承了Person函数的原型,因此它可以被认为是Person类型的实例。


修改对象的原型

我们可以使用__proto__来动态地修改一个对象的原型对象。例如:

function Person() {}
const alice = new Person();
alice.__proto__ = {
  sayHello() {
    console.log("Hello, I'm a new object.");
  }
};
alice.sayHello(); // 输出:Hello, I'm a new object.

在这个例子中,我们创建了一个Person对象alice,然后通过alice.__proto__动态地修改了它的原型对象,将它的原型对象替换成一个新的对象。最后,调用alice.sayHello()方法时输出了Hello, I'm a new object.,说明alice对象的原型已经被成功替换。


原型链

当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。这个寻找的链路就是原型链。

看一个例子:


  // 构造函数
  function Foo(name,age){
    this.name=name;
    this.age=age;
  }
  Object.prototype.toString=function(){
   //this是什么要看执行的时候谁调用了这个函数。
   console.log("I'm "+this.name+" And I'm "+this.age);
  }
  var fn=new Foo('小明',19);
  fn.toString(); //I'm 小明 And I'm 19
  console.log(fn.toString===Foo.prototype.__proto__.toString); //true
  console.log(fn.__proto__ ===Foo.prototype)//true
  console.log(Foo.prototype.__proto__===Object.prototype)//true
  console.log(Object.prototype.__proto__===null)//true

来个图帮助理解。

6.png


总结

1、所有的引用类型(数组、函数、对象)都可以通过原型可以自由扩展属性(除null以外)。


2、所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。


3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。


4、所有引用类型,它的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性。(结合2和3)


5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。这就是原型链。


相关文章
|
3月前
|
JavaScript 前端开发
常见的JS面试题
【8月更文挑战第5天】 常见的JS面试题
61 3
|
14天前
|
JSON JavaScript 前端开发
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
本文介绍了JSONP的工作原理及其在解决跨域请求中的应用。首先解释了同源策略的概念,然后通过多个示例详细阐述了JSONP如何通过动态解释服务端返回的JavaScript脚本来实现跨域数据交互。文章还探讨了使用jQuery的`$.ajax`方法封装JSONP请求的方式,并提供了具体的代码示例。最后,通过一个更复杂的示例展示了如何处理JSON格式的响应数据。
27 2
[JS]面试官:你的简历上写着熟悉jsonp,那你说说它的底层逻辑是怎样的?
|
3月前
|
JavaScript 前端开发
如何在JavaScript中实现基于原型的继承机制
【8月更文挑战第14天】如何在JavaScript中实现基于原型的继承机制
29 0
|
1月前
|
Web App开发 JavaScript 前端开发
前端Node.js面试题
前端Node.js面试题
|
2月前
|
JSON JavaScript 前端开发
js原型继承|26
js原型继承|26
|
2月前
|
JavaScript 前端开发
JavaScript prototype(原型对象)
JavaScript prototype(原型对象)
31 0
|
2月前
|
JavaScript 前端开发
JavaScript基础知识-原型(prototype)
关于JavaScript基础知识中原型(prototype)概念的介绍。
37 1
|
3月前
|
存储 JavaScript 前端开发
2022年前端js面试题
2022年前端js面试题
39 0
|
3月前
|
JavaScript 前端开发
JavaScript中什么是原型?有什么用?
JavaScript中什么是原型?有什么用?
22 1
|
3月前
|
JavaScript 前端开发 Java
什么是JavaScript原型对象
【8月更文挑战第2天】什么是JavaScript原型对象
61 9