首页 > 其他分享 >JS中原型、原型链的理解

JS中原型、原型链的理解

时间:2023-04-27 16:45:41浏览次数:37  
标签:对象 Object JS Person 理解 原型 prototype 构造函数

1.构造函数

构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立的,即实例识别。构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。

另外就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。

function Person(name, age, gender) {    //创建一个构造函数 
        this.name = name
        this.age = age
        this.gender = gender
        this.sayName = function () {    //定义构造函数中的一个方法
            alert(this.name);
        }
    }
    var per = new Person("孙悟空", 18, "男");     //调用创建的构造函数,必须用new关键字调用
​
    console.log(per)            //当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值
​
//toSting(): 可以把一个Number转换为字符串

每创建一个Person构造函数,在Person构造函数中,为每一个对象都添加了一个sayName方法,也就是说构造函数每执行一次就会创建一个新的sayName方法。这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的,为什么不把这个方法单独放到一个地方,并让所有的实例都可以访问到呢?这就需要原型(prototype)

2.原型对象

原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中在JavaScript中。每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。

在JavaScript中是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性,它的属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。当使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。一般来说不应该能够获取到这个值的,但是现在浏览器中实现了 __proto__属性来访问这个属性,但是最好不要使用这个属性,因为它不是规范中规定的。ES5 中新增了一个 Object.getPrototypeOf() 方法,可以通过这个方法来获取对象的原型。

3.原型链

3.1 .__proto__和constructor

每一个对象数据类型(普通的对象、实例、prototype......)也天生自带一个属性__proto__,属性值是当前实例所属类的原型(prototype)。原型对象中有一个属性constructor, 它指向函数对象。

function Person() {}
    var person = new Person()
    console.log(person.__proto__ === Person.prototype)//true
    console.log(Person.prototype.constructor===Person)//true
    //顺便学习一个ES5的方法,可以获得对象的原型
    console.log(Object.getPrototypeOf(person) === Person.prototype) // true

3.2 何为原型链?

在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止(person → Person → Object),这样就形成了一个原型指向的链条,专业术语称之为原型链

 

当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined。注意:Object对象是老祖宗,没人比他更大了,所以Object的_proto_为空, 即原型链的尽头一般来说都是 Object.prototype

console.log(Object.prototype.__proto__ === null) // true

我们可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性;使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true

function Person() {}                                               //创建构造函数
    Person.prototype.a = 123;                                       //给构造函数的原型实例中添加a属性,而不是在构造函数中添加a属性
    Person.prototype.sayHello = function () {                     //给构造函数的原型实例中添加sayHello方法,而不是在构造函数中添加该方法
      alert("hello");
    };
​
    var person = new Person()                                      //创建一个构造函数实例对象
    console.log(person.a)//123                                  // 虽然在构造函数中没有a属性,但是在其父函数(实例原型)中有该属性,所以构造                                                                函数继承了a属性,仍能正常输出而不报错
    console.log(person.hasOwnProperty('a'));//false                // hasOwnProperty方法仅检查对象自身是否含有某属性,a属性是继承的,自身中没                                                                有,所以不能正常输出     
    console.log('a'in person)//true                             // 若当前实例对象的构造函数中没有属性a时,in方法可以查询其父函数或祖父函数中                                                                是否有a属性,即查户口查到祖宗十八代去了,23333         
​
​
//getPrototypeOf():返回参数内部特性Prototype的值
console.log(Object.getPrototypeOf(person1) == Person.prototype)  //true

4.原型链指向

p.__proto__  // Person.prototype
Person.prototype.__proto__  // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor  // Person

5.如何获取对象中非原型链上的属性?

使用后hasOwnProperty()方法来判断属性是否属于原型链的属性

function iterate(obj){
   var res=[];
   for(var key in obj){
        if(obj.hasOwnProperty(key))
           res.push(key+': '+obj[key]);
   }
   return res;
}

function关键词本身也有一个原型对象”Function”,其他函数在使用“function”关键词时,一定存在属性继承于原型对象“Function.prototype”

原型的作用

假如没有原型,那我们需要这样声明一个对象

var obj = {
toString: window.Object.prototype.toString,
hasOwnPropertyOf: window.Object.......
}
obj.toString()
var obj2 = {
toString: window.Object.prototype.toString,
hasOwnPropertyOf: window.Object.......
}
obj2.toString()

 

有了原型,我们只需要一句话就可以搞定了

let obj = {}

所以原型的作用就是让你无需重复声明共有属性,省代码,省内存。 ​

来源 | https://blog.csdn.net/qq_38867012/article/details/124001609

标签:对象,Object,JS,Person,理解,原型,prototype,构造函数
From: https://www.cnblogs.com/0627st/p/17359343.html

相关文章

  • 关于聚合根,领域事件的那点事---深入浅出理解DDD
    作者:京东物流赵勇萍前言最近有空会跟同事讨论DDD架构的实践落地的情况,但真实情况是,实际中对于领域驱动设计中的实体,值对象,聚合根,领域事件这些战术类的实践落地,每个人理解依然因人而异,大概率是因为这些概念还是有一些抽象,同时有有别于传统的MVC架构开发。在此,通过小demo的方式......
  • jsp js iframe用post方式提交大数据
    <!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><html><head><title>NewDocument</title><metaname="Generator"content="Edi......
  • js url urlencoding,乱码,编码,解码,编解码
    %25%37%DD上述形式不是乱码。这是urlencoding。可以使用js内置的方法encodeURIComponent进行编码再使用decodeURIComponent把上述形式再解码为普通字符对付火狐的自动编码有特效黑色头发:http://heisetoufa.iteye.com/......
  • Day 28 28.2 JS进阶之eval和hook函数
    JS进阶之eval函数和hook函数【一】evaleval()函数计算JavaScript字符串,并把它作为脚本代码来执行。如果参数是一个表达式,eval()函数将执行表达式。如果参数是Javascript语句,eval()将执行Javascript语句。eval(string)//eval('[1,2,3,4,5].map(x=>x*x)')h......
  • Day 28 28.1 JS进阶之三元运算符
    JS工具之三元运算符【1】格式三元运算符:条件表达式?语句1:语句2;leta=10;letb=20;letd=a>b?a:bconsole.log(d);注释:条件运算符在执行时,首先对条件表达式进行求值,如果该值为true,则执行语句1,并返回执行结果如果该值为false,则......
  • 条款28.理解引用折叠
     理解引用折叠以下面这个模板为例template<typenameT>voidfunc(T&&param);12模板形参T的推导类型中,会把传给param的实参是左值还是右值的信息给编码进去。编码机制是直截了当的:如果传递的实参是个左值,T的推导结果就是个左值引用类型;如果传递的实参是个右值,T的推导结......
  • Day 27 27.2 JS进阶之window对象
    JS-Function对象之window对象window是客户端浏览器对象模型的基类,window对象是客户端JavaScript的全局对象。一个window对象实际上就是一个独立的窗口,对于框架页面来说,浏览器窗口每个框架都包含一个window对象。(1)全局作用域在客户端浏览器中,window对象是访问BOM......
  • Day 27 27.1 JS进阶-Function对象之prototype对象
    JS-Function对象之prorotype原型对象案例1://创建方式1varfoo=newFunction("console.log('helloworld!')")foo()//创建方式2functionPerson(){console.log("helloperson")}varp1=Person()console.log(p1)varp2=newPers......
  • Day 27 27.3 JS进阶之ES6新语法
    JS工具之三元运算符【1】格式三元运算符:条件表达式?语句1:语句2;leta=10;letb=20;letd=a>b?a:bconsole.log(d);注释:条件运算符在执行时,首先对条件表达式进行求值,如果该值为true,则执行语句1,并返回执行结果如果该值为false,则......
  • Day 27 27.3 JS进阶之ES6新语法
    JS进阶之ES6新语法1.var、let以及constES6中引入了关键字let和const作为var的替代。它们非常有用,如今几乎每个JavaScript开发人员都在使用它们。与关键字var不同,这两个关键字具有块作用域。这意味着当你在块中声明它们时,它们只能在该块{}内访问。//f......