ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JavaScript基础之浅谈原型和原型链

2021-11-18 21:02:48  阅读:107  来源: 互联网

标签:function __ 浅谈 JavaScript 原型 var new prototype


前面聊了一些对象的构造函数,前面如果了解的后就可以聊原型和原型链了,其实这个听着很瘆人,不过简单的了解然后换一个名词,觉得原来如此了。

原型(prototype)

原型(prototype)其实就是function的对象的一个属性,打印出来的话也就是一个对象,如下

function Objthis(name,year){
   
        this.name=name;
        this.year=year;
   
}

console.log(Objthis.prototype)

在这里插入图片描述

既然如此其原型也是一个对象,那么他的对象可以添加属性吗?

Objthis.prototype.sex="女";
obj= new Objthis("张三",23);
console.log(obj);

在这里插入图片描述

这样看似乎对其原型添加一个属性,对根据构造函数创建的对象似乎没什么影响啊?难道真的没有影响?

// 大胆搞一下

console.log(obj.sex)

在这里插入图片描述

神奇不,在原型上赋予sex属性的值,通过obj.sex竟然也可以打印出来。

这个时候又有疑问了,如果我为对象添加一个sex属性呢?那打印谁的?、

obj.sex="男";
console.log(obj.sex);

在这里插入图片描述

这个时候又有了一个大胆的想法

function Objthis(name,year,sex){
   
        this.name=name;
        this.year=year;
        this.sex=sex;
  
}
Objthis.prototype.sex="女";
Objthis.prototype.address="中国";

obj=new Objthis("张三",23);
obj1=new Objthis("李四",23,"男");

console.log(obj.sex,obj.address);
console.log(obj1.sex,obj1.address);

在这里插入图片描述

总结:

  • 这个原型(prototype)是定义构造函数的每个对象总源头(也可以称作祖宗)。
  • 所有被该构造函数构造的都可以继承原型的属性和方法。但是只有构造函数上拥有了某个和原型上的属性或方法同名,优先用构造函数自己本身的(哪怕这个属性或方法在构造函数上没有传参,比如上图的obj.sex为undefined)。

通过上面的了解是否可以这样写:

function Objthis(name,year,sex){
   
        this.name=name;
        this.year=year;
        this.sex=sex;
  
};
Obj={
    sex:"女",
    address:"中国",
    like:function(){// 为证明也可以继承方法,所以添加一个方法
        console.log("喜欢看电视剧");
    }
};
// 声明对象的时,必须在这个后面,不然其prototype属性不会是Obj
Objthis.prototype=Obj;

obj= new Objthis("张三",23,"男");
obj.like();

补充

前面说过一个constructor

function Objthis(name,year,sex){
   
        this.name=name;
        this.year=year;
        this.sex=sex;
  
};

obj= new Objthis("张三",23,"男");
// 打印其构造
obj.constructor

在这里插入图片描述

现在看一下原型的constructor。

在这里插入图片描述

可见常规情况下构造函数的constructor指向的是自己本身。

对象的__proto__

前面一直说原型,但是有没有发现一件事就,那就是构造函数默认是有prototype的,但是声明的对象,而对象却没有prototype属性,不过细心的回发现__proto__这个属性。

在这里插入图片描述

通过上面可以看出__proto__prototype给关系以及区别

  • 每个对象都有一个__proto__属性,并且指向它的构造函数prototype原型对象

  • 每个构造函数都有一个prototype原型对象

    • prototype原型对象里的constructor指向构造函数本身

补充 JavaScript都是对象

JavaScript中最常用的一句话,那就是万物皆对象,这句话,是否很神奇。

function  test(){}

在这里插入图片描述

其实这个有点原型链的影子了,毕竟原型的原型是obejct,这个地方可以看出方法其实它的祖先也是一个object

原型链

前面一直说原型,和__proto__属性,似乎没说原型链。原型链具体是什么?

# 方便演示原型链
function  test(){} ;
var j=new test();

在这里插入图片描述

这个图可以看出一点对象 j 的__proto__下面还有一个__proto__,当然最后当其构造方法变成你object()的时候就不在有了,可见obejet是所有__proto__的重点。

当然__proto__的构造函数也有自己的__proto__,其终点也是指向object()。

在这里插入图片描述

原型链本质就是__proto__指向了原型,而原型上也有一个__proto__,这样一串的__proto__等于prototype,所以称之为原型链。

原型链演示

前面聊原型和原型链,如果没有作用或者意义,那就没有什么出现的作用了。

如果有点java基础的,瞬间会联想到java中的父类和子类,以及其继承逻辑。而原型链也遵循这个逻辑。那就是继承属性。

演示1

老规矩先来一些代码:

function Country(){
    this.countryName="中国";
    this.countryFun=function(){
        console.log("我来自的国家--",this.countryName);
    }
    
}
// 这个地方一定是new 对象 不然返回的不到继承的数据(后面解释)
Province.prototype=new Country();

function Province(){
     this.provinceName="河北";
     this.provinceFun=function(){
        console.log("我来自的省份--",this.provinceName);
    }
}
City.prototype=new Province();

function City(){
   this.cityName="石家庄";
    this.cityFun=function(){
        console.log("我来自的城市--",this.cityName);
    }
}

var address= new City();


在这里插入图片描述

可以看出address 可以打印构造函数的属性以及方法,也可以待用原型链上的属性和方法。

补充

Province.prototype=new Country(); 这个地方为什么要new?

如果不new的话如下:

function Country(){
    this.countryName="中国";
    this.countryFun=function(){
        console.log("我来自的国家--",this.countryName);
    }
    
}

Province.prototype= Country;

function Province(){
     this.provinceName="河北";
     this.provinceFun=function(){
        console.log("我来自的省份--",this.provinceName);
    }
}
City.prototype=Province;

function City(){
   this.cityName="石家庄";
    this.cityFun=function(){
        console.log("我来自的城市--",this.cityName);
    }
}

var address= new City();


在这里插入图片描述

contry上的属性和方法无法使用,为什么会这样?

前面说过对象__proto__=构造函数的prototype

首先City.prototype=Province;前面说过没有return this(new的作用说过)。而这个

简单来看就是

City.prototype=Province;
function City(){
   this.cityName="石家庄";
    this.cityFun=function(){
        console.log("我来自的城市--",this.cityName);
    }
}

var address= new City();

//具体效果如下
address.__proto__=function Province(){
       // 这样函数就是一个空函数 return undefined
    }
}
//function Province() 不是对象 所以其prototype=Country

如果使用new的话:

City.prototype=new Province();
function City(){
   this.cityName="石家庄";
    this.cityFun=function(){
        console.log("我来自的城市--",this.cityName);
    }
}

var address= new City();

//具体效果如下
address.__proto__=new  Province(){
           this.__proto__={//Country 的对象,有点套娃,所以不再写
                      }
            this.cityName="石家庄";
            this.cityFun=function(){
                 console.log("我来自的城市--",this.cityName);
            }
            return this;
    }
}
// 这样一个逻辑 __proto__ 会一直下去从而完美的拥有了对象继承的属性

这个时候又有了一个疑问因为前面在Objthis.prototype.sex="女";

这样写的时候new 构造函数的时候就把prototype的属性继承给对象了啊?是咋回事呢?

var a={}
a.name="李四";

其实这个上面那种方式而已
Objthis.prototype.sex="女"
为Objthis.prototype创建一个属性为sex,然后赋值。等于直接赋值的。

演示2

不过一般这样用

function test() {
  this.testarr1 = [];
  this.testarr2 = [];
}

var testfather={
  addarr: function(v) {
    this.testarr1.push(v);
  }
};

test.prototype = testfather;// 直接prototype=实例化的对象

var t=new test();
t.addarr("1")

在这里插入图片描述

这个涉及到this指向,如果不了解可以看之前的博客,里面讲了this的指向以及如果修改this指向。

为什么一般说演示2是最常用的呢,很简单说一个需求

架构师写了一个祖先A。这个祖先构A里面的函数被很多人用

var A={
    funA:function1(){}
    ……………………
}
function B(){
    key:"value"
};

B.prototype=A;

var b =new B()



##一般都会将方法放在prototype中,而属性一般都会变,所以没有必要。


突然又发现,B继承了A的很多方法,而自己的方法又和C中常用都有,D没有相同的方法?

方法一: 将B的方法写入A
var A={
    funA:function(){}
    funB:function(){}
    ……………………
}
function B(){
    key:"value"
};
function C(){
    key:"value"
};
function D(){
    key:"value"
};
B.prototype=A;
C.prototype=A;

D.prototype=A;

var b =new B();

var c =new C();

var d =new D();

# 上面看似解决问题,但是 一般总的类都不允许别人东的。但又想让方法变大可以重复利用咋办?

方法二:

方法一: 将B的方法写入A
var A={
    funA:function(){}
    ……………………
}

var A2={
    funB:function(){}
    ……………………
}

A2.__proto__=A;


function B(){
    key:"value"
};
function C(){
    key:"value"
};
function D(){
    key:"value"
};

B.prototype=A2;
C.prototype=A;

D.prototype=A2;

var b =new B();

var c =new C();

var d =new D();

一般会用第二种方式将其中间添加一个对象,这样不会修改最顶端对象的方法他添加修改以及删除。

原型一些常用方法

for

for (key in address){
    console.log(key)
}

在这里插入图片描述

可以看出可以得到整个原型链上的属性。

hasOwnProperty

上面的for循环可以循环所有的属性,而hasOwnProperty可以判断整个属性是否是其是其构造函数的prototype上的属性。

for (key in address){
    console.log(key , City.prototype.hasOwnProperty(key))
}

在这里插入图片描述

只能判断直系,如果隔代就无法判断。

不同方式创建和生成原型链

语法结构创建的对象

var A={a:1};
// A 这个对象继承了Object.prototype上面的所有属性
// A 自身没有名为 hasOwnProperty 的属性
// hasOwnProperty 是 Object.prototype 的属性
// 因此 A 继承了 Object.prototype 的 hasOwnProperty
// Object.prototype 的原型为 null
// 原型链如下:
//  A ---> Object.prototype ---> null



var arr = ["a", "b", "c"];

// 数组都继承于 Array.prototype
// (Array.prototype 中包含 indexOf, forEach等方法)
// 原型链如下:
// arr ---> Array.prototype ---> Object.prototype ---> null

function fun() {
  return 1;
}

// 函数都继承于Function.prototype
// (Function.prototype 中包含 call, bind等方法)
// 原型链如下:
// fun ---> Function.prototype ---> Object.prototype ---> null



构造器创建的对象

function test() {
  this.testarr1 = [];
  this.testarr2 = [];
}

var testfather={
  addarr: function(v) {
    this.testarr1.push(v);
  }
};

test.prototype = testfather;

Object.create 创建的对象 (ES5)

var a = { k: 1 };
// a ---> Object.prototype ---> null

var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.k); // 1 (继承而来)

var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null

var d = Object.create(null);
// d ---> null  因为d没有继承Object.prototype, 这个和 var d={}不一样下面看图

在这里插入图片描述

class 关键字创建对象 (ES6)

这个以后单独聊ES6与ES5区别。下面这个也是一种方式。

class fatherFun {
  constructor(test) {
    this.test=test;
  }
}

class sonFun extends fatherFun {
  constructor(test) {
    super(test);
  }
  get fun1() {
    return this.test * this.test;
  }
 
}


标签:function,__,浅谈,JavaScript,原型,var,new,prototype
来源: https://blog.csdn.net/u011863822/article/details/121409859

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有