js中原型对象与原型的关系

简介: js中原型对象与原型的关系

构造函数的应用

在我们类这个概念还没有出来之前,我们都是通过构造函数的方法来创建实例化对象。 我们先来看看传统创建对象和构造函数创建的区别。


//1.通过对象字面量来创建。
var student = {
  name: "zhangsan",
  age: 18,
  gender: "male",
  sayHi: function () {
    console.log("hi,my name is " + this.name);
  },
};
//2.通过 new Object() 创建对象。
var student = new Object();
    student.name = "zhangsan",
    student.age = 18,
    student.gender = "male",
    student.sayHi = function () {
      console.log("hi,my name is " + this.name);
  };

上面两种都是简单的创建对象的方式,那如果是一个班的学生,n 个学生呢? 显然如果这样做的话代码冗余率太高,是不可取的。我们也学过函数, 所以简单方式的改进是:工厂函数。


//3.通过工厂函数来创建对象。
function createStudent(name, age, gender) {
  var student = new Object();
  student.name = name;
  student.age = age;
  student.gender = gender;
  student.sayHi = function () {
    console.log("hi,my name is " + this.name);
  };
  return student;
}
var s1 = createStudent("zhangsan", 18, "male");
var s2 = createStudent("lisi", 19, "male");

这样封装代码确实解决了代码冗余的问题,但是每次调用函数 createStudent()都会创建新函数sayHi(),也就是说每个对象都有自己的 sayHi() 版本,而事实上,每个对象都共享一个函数。为了解决这个问题,我们引入面向对象编程里 的一个重要概念:构造函数。


//4.通过构造函数来创建对象。
function Student(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.sayHi = function () {
   console.log("hi,my name is " + this.name);
  };
}
var s1 = new Student("zhangsan", 18, "male");

来看看构造函数与工厂函数的区别: 1.首先在构造函数内没有创建对象,而是使用 this 关键字,将属性和方法赋给了 this 对象。 2.构造函数内没有 return 语句,this 属性默认下是构造函数的返回值。 3.函数名使用的是大写的 Student。 4.用 new 运算符和类名 Student 创建对象。

构造函数虽然科学,但仍然存在一些问题。 我们使用前面的构造函数例子来讲解(修改了 sayHi() 方法):


function Student(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.sayHi = function () {
    console.log("hi");
  };
}
//首先我们创建两个实例化对象:
var s1 = new Student("zhangsan", 18, "male");
s1.sayHi(); // 打印 hi
var s2 = new Student("lisi", 18, "male");
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayhi); // 结果为 false

由于每个对象都是由 new Student 创建出来的,因此每创建一个对象,函数 sayHi() 都会被重新创建一次,这个时候,每个对象都拥有一个独立的,但是功 能完全相同的方法,这样势必会造成内存浪费。有的人可能会想,既然是一样的 那我们就单独把它提出来,写一个函数,每次调用不就可以了吗?比如:


function sayHi() {
  console.log("hi");
}
function Student(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.sayHi = sayHi;
}
var s1 = new Student("zhangsan", 18, "male");
s1.sayHi(); // 打印 hi
var s2 = new Student("lisi", 18, "male");
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayHi); // 结果为 true

但是这样做会导致全局变量增多,可能会引起命名冲突,代码结果混乱, 维护困难。通过使用原型可以很好的解决这个问题。

原型的作用

原型:prototype 在 JavaScript 中,每一个构造函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。


function Star(uname,age) {
 this.uname = uname;
 this.age = age;
 }
 let dgl = new Star("戴古拉k",22);
 console.log(dgl);
 console.log(dgl.__proto__);

image.png

而在我们的实例对象中具有__proto__属性,它指向的是我们构造函数中的prototype原型对象


function Star(uname,age) {
  this.uname = uname;
  this.age = age;
  Star.prototype.movie = function() {
  console.log("极地追击");
  }
  }
  var dgl = new Star("戴古拉k",22);
  console.log(dgl);
  dgl.movie();

因此当我们调用的时候__proto__直接帮我们指向了prototype中的movie属性

在构造函数的prototype中存在一个constructor属性,它指向我们prototype原型对象所在的构造函数

image.png

注意我们使用prototype创建方法时都是prototype + .属性 ,如果我们使用的是对象添加方法则constructor会不一样

function Star(uname,age) {
 this.uname = uname;
 this.age = age;
 Star.prototype.movie = function() {
 console.log("极地追击");
 }        
}
 let dgl = new Star("戴古拉k",22);
  console.log(dgl);
  console.log(dgl.__proto__.constructor);
image.png
function Star(uname,age) {
 this.uname = uname;
 this.age = age;
 Star.prototype = {
  movie: function() {
  console.log("极地追击");
 }       
}          
}
 let dgl = new Star("戴古拉k",22);
 console.log(dgl);
 console.log(dgl.__proto__.constructor);

image.png

上图可看两种方式得到的构造函数不一样,因为我们用{}创建时会覆盖掉原来的constructor属性,因此得到的结果不同

构造函数、实例、原型三者之间的关系

每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针 constructor,而实例都包含一个指向原型对象的内部指针__proto__。

image.png

原型链

在我们的构造函数的prototype原型对象中还有一个Object原型对象以及__proto__属性,__proto__属性指向Object 原型对象而Object通过constructor又指向Object构造函数,如此形成一条链式结构,即原型链

image.png

属性查找原则

image.png

相关文章
|
22天前
|
JavaScript 前端开发
JavaScript遍历数组和对象常用方法总结
以上代码展示了数组和对象的多种遍历方法。对于数组,使用了传统的 `for` 循环、`for...in` 和 ES6 的 `for...of` 进行遍历;对于对象,则通过 `for...in`、`Object.keys()`、`Object.values()` 和 `Object.entries()` 来获取键值对。`for...of` 循环适用于遍历具有迭代协议的数据结构,如数组、字符串等,而对象遍历则更多地依赖于 `Object` 方法来获取其属性集合。
JavaScript遍历数组和对象常用方法总结
|
1月前
|
JavaScript 前端开发 索引
JS遍历数组里数组下的对象,根据数组中对象的某些值,组合成新的数组对象
这篇文章介绍了如何在JavaScript中遍历数组里数组下的对象,并根据对象的某些属性值组合成一个新的数组对象。主要内容包括使用ES6的`for...of`循环来遍历数组对象,然后根据需要提取对象中的属性值,并将它们放入新的对象中,最终形成一个新的对象数组以供使用。
|
1月前
|
JSON JavaScript 前端开发
JavaScript实现字符串转json对象的方法
JavaScript实现字符串转json对象的方法
|
1月前
|
JavaScript 前端开发
如何在JavaScript中实现基于原型的继承机制
【8月更文挑战第14天】如何在JavaScript中实现基于原型的继承机制
24 0
|
17天前
|
JavaScript 前端开发
JavaScript基础知识-枚举对象中的属性
关于JavaScript基础知识中如何枚举对象属性的介绍。
24 1
JavaScript基础知识-枚举对象中的属性
|
8天前
|
JavaScript 前端开发
JavaScript Boolean(布尔) 对象
Boolean(布尔)对象用于将非布尔值转换为布尔值(true 或者 false)。
26 8
|
17天前
|
JavaScript 前端开发
JavaScript基础知识-原型(prototype)
关于JavaScript基础知识中原型(prototype)概念的介绍。
24 1
|
18天前
|
JavaScript 前端开发
JavaScript基础知识-对象的基本操作
关于JavaScript对象基本操作的基础知识文章。
27 2
|
17天前
|
JavaScript 前端开发
JavaScript基础知识-对象字面量
文章介绍了JavaScript中对象字面量的创建和使用,包括基本语法、属性赋值以及如何在控制台输出对象属性。
24 0
JavaScript基础知识-对象字面量
|
19天前
|
JavaScript 前端开发 API
Javaweb之javascript的BOM对象的详细解析
BOM为Web开发提供了强大的API,允许开发者与浏览器进行深入的交互。合理使用BOM中的对象和方法,可以极大地增强Web应用的功能性和用户体验。需要注意的是,BOM的某些特征可能会在不同浏览器中表现不一致,因此在开发过程中需要进行仔细的测试和兼容性处理。通过掌握BOM,开发者能够制作出更丰富、更动态、更交互性的JavaWeb应用。
13 1