《原型链重置版》一万多字让你读懂JavaScript原型对象与原型链的继承,探秘属性的查找机制! (1)

简介: 为什么要使用原型!

logo.png

前言

有些新手朋友可能听说过这么一句话,就是js中存在两个链条,它们分别为:作用域链原型链

它们彼此的区别在于作用域链是为了访问变量数据而存在的一种链条访问机制

原型链是访问对象属性或者方法而存在的一种机制!

其中这里的原型链就是今天我要说的主题!

我们学习js必须要知道什么是原型、原型链、构成函数、实例对象这些彼此之间的关系和应用范围!

如果你没有搞明白js中的原型链也就说明你没有把js学明白!

那么接下来就跟着我一起开始学习吧!

为什么要使用原型?

原型js中也称之为原型模式, 那么为什么要有这种模式存在呢?

因为我们js面向对象不是说过吗?面向对象编程其实就是一种模块、一种封装对吧!

如果你还没有完全明白javascript面向对象建议你一定要听我讲完下面的知识点!

构造函数模式

有的时候我们会使用构造函数模式创建对象

虽然这种构造函数创建对象,看起来没什么大问题,但是并非没有缺点!

这里我们来看一段简单的构造函数模式创建对象的案例吧!

代码

function Person(username,age,job){
   
   
    this.username=username;
    this.age=age;
    this.job=job;
    this.say=function (){
   
   
        console.log('我的名字叫:'+this.username+',年龄:'+this.age+',职业:'+this.job);
    }
}

var test=new Person('张三',18,'ui设计师');
test.say();

这就是一段非常简单的构造函数模式封装对象的方法!

构造函数模式的缺点

任何一种技术的出现,都是为了弥补旧技术的不足!

那么构造函数模式有什么缺点呢?为什么又要搞出一个原型模式呢? 搞出这么个东西意义何在?

这里我先卖个关子,想知道的话就继续往下看吧! 😛😛😛

从上面的代码角度上看,确实感觉不出什么奇怪之处!

那我们再来看一个构造函数模式的例子:

代码

//构造函数
function Person(){
   
   
    this.say=function (num){
   
   
        console.log('测试方法'+num);
    }
}
//实例化
var obj_1=new Person();
var obj_2=new Person();

//调用
obj_1.say(1);
obj_2.say(2);

console.log(obj_1.say===obj_2.say);   //返回false

然后我们看看下面这张图你就知道其中缺点在什么地方了!

如图

structure-1.png

此时你会发现,这个函数居然会不相等!! 为什么呢?

从另一个角度来讲构造函数每执行一次就会把构造函数中的方法也重新在内存中生成一份相同的方法!

比如: 执行一万次构造函数,那么就会在内存中创建一万次构造函数里面的方法, 这对内存是一种非常大的消耗

要知道在ECMAScript中只要是函数都是对象 这句话!

之所以会返回false就是因为函数的底层地址是不一样的! 不要以为方法名称一样就是一样! 那你就错了

如图

structure-2.png

并且函数本身也是对象, 你定义一个函数,也就相当于实例化了一个函数对象, 其实就会在内存中开辟一个空间,地址也会不一样!

上面的这行代码

this.say=function (num){
   
   
    console.log('测试方法'+num);
}

其实从一定逻辑上讲也可以看成以下形式

this.say=new Function (num){
   
   
    console.log('测试方法'+num);
}

这样子其实你更好理解每个构造函数实例中的方法,其实是不同Function的实例

所以说像这种在内存中无限创建很多完成同样方法的Function实例是完全没有必要的!

那么有没有什么好的方案可以解决这个问题呢?

我们完全可以使所有的对象共享同一个方法,那么构造函数执行一万次,在内存中也只会存在一份相应的方法!

通常是可以把这个函数方法转移到构造函数外部

代码说明

function Person(username,age,city){
   
   
    this.name=username;
    this.age=age;
    this.city=city;
    this.say=say;
    /*this.say=function() {
         console.log(this.name+'的年龄是:'+this.age);
     }*/
}

//把say方法写在全局作用域中
function say() {
   
   
    //这里的this要清楚是谁在调用say这个方法 this自然就指向谁
    console.log(this.name+'的年龄是:'+this.age);
}
var test1=new Person('张三',33,'北京市');
var test2=new Person('李四',66,'深圳市');

//判断test1与test2之间的方法是否是共用的
console.log(test1.say==test2.say);

如图

structure-3.png

案例2

以下案例也是同样的道理!

//构造函数
function Person(){
   
   
    this.say=say;
}

//定义到全局下
function say(num){
   
   
    console.log('测试方法'+num);
}

//实例化
var obj_1=new Person();
var obj_2=new Person();

//调用
obj_1.say(1);
obj_2.say(2);

console.log(obj_1.say===obj_2.say);   //返回true

目的我们是达到了,但是这样写就真的行了吗? 不会存在其他问题吗?

分析

很明显在开发当中 如果把函数这样子写在全局作用域中,在多人开发的时候那么就会出现命名冲突,或者说这样做会 污染全局作用域的命名空间, 所以说我们在项目开发的时候都是尽量地不在全局作用域中写变量和函数

那么如何来解决这样的问题呢? 就是接下来我要说的原型和原型链,然后根据情况来解决相应的问题!

相关文章
|
13天前
|
JavaScript 前端开发 CDN
前端 JS 经典:package.json 属性详解
前端 JS 经典:package.json 属性详解
12 1
|
16天前
|
XML JavaScript 前端开发
如何在JavaScript中设置多个样式属性?
【6月更文挑战第29天】如何在JavaScript中设置多个样式属性?
33 3
|
16天前
|
前端开发 JavaScript
使用JavaScript动态更改元素的CSS属性
【6月更文挑战第29天】使用JavaScript动态更改元素的CSS属性
24 3
|
10天前
|
存储 Web App开发 JavaScript
浏览器【详解】Cookie(含Cookie的起源,属性,个数和大小限制,作用,优点,缺点,JS 的操作方法等)
浏览器【详解】Cookie(含Cookie的起源,属性,个数和大小限制,作用,优点,缺点,JS 的操作方法等)
11 0
|
10天前
|
JavaScript C++
js【详解】原型 vs 原型链
js【详解】原型 vs 原型链
8 0
|
12天前
|
JavaScript
js 内建对象的拓展 shim/polyfill ( 内含js 判断对象的属性是否存在的方法)
js 内建对象的拓展 shim/polyfill ( 内含js 判断对象的属性是否存在的方法)
11 0
|
13天前
|
JavaScript 前端开发 API
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
8 0
|
14天前
|
JavaScript
js 排序—— sort() 对普通数组、对象数组(单属性/多属性)排序
js 排序—— sort() 对普通数组、对象数组(单属性/多属性)排序
8 0
|
6天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
19 2
|
6天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
14 4