JavaScript进阶(四)原型与原型链用法实例分析


Posted in Javascript onMay 09, 2020

本文实例讲述了JavaScript原型与原型链用法。分享给大家供大家参考,具体如下:

一句话说明什么是原型:原型就是一个JavaScript对象,原型能存储我们的方法,构造函数创建出来的实例对象能够引用原型中的方法。

一、传统构造函数的问题

有如下代码

function Foo(){
 this.sayHello = function(){
  }
}

由于对象是调用new Foo()所创建出来的,因此每一个对象在创建的时候,函数 sayHello 都会呗创建一次

那么有没一个对象都含有一个独立的,不同的,但是功能逻辑一样的函数,比如:{} == {}

在代码中方法就会消耗性能,最典型的资源就越是内存

这里最好的方法就是将函数放在构造函数之外,那么在构造函数中引用该函数即可

function sayHello () {}
function Foo () {
 this.say = sayHello;
}

会在开发中变得困难:引入框架危险,代码繁冗不好维护。解决方法就是如果外面的函数不占用其名字,而且在函数名下。

每一个函数在定义的时候,有一个神秘对象(就是原型对象,暂且这么称呼)被创建出来。

每一个由构造函数创建的对象都会默认的连接到该神秘对象上。

var f1 = new Foo();
var f2 = new Foo();
f1.sayHello(); //如果f1没有sayHello那么就会在Foo.prototype中去找

由构造函数创建出来的众多对象共享一个对象就是:构造函数.prototype

只需要将共享的东西,重复会多占用内存的东西放到构造函数.prototype中,那么所有的对象就可以共享了。

function Foo(){}
Foo.prototype.sayHello = function(){
 console.log("….");
}
var f1 = new Foo();
f1.sayHello();
var f2 = new Foo();
f2.sayHello();
console.log(f1.sayHello === f2.sayHello); // true

二、一些相关概念

类class:在JS中就是构造函数

  • 在传统的面向对象语言中,使用一个叫类的东西定义模板,然后使用模板创建对象。
  • 在构造方法中也具有类似的功能,因此也称其为类

实例(instance)与对象(object)

  • 实例一般是指某一个构造函数创建出来的对象,我们称为XXXX 构造函数的实例
  • 实例就是对象。对象是一个泛称
  • 实例与对象是一个近义词

键值对与属性和方法

  • 在JS中键值对的集合称为对象
  • 如果值为数据(非函数),就称该键值对为属性
  • 如果值为函数(方法),就称该键值对为方法method

父类与子类(基类和派生类)

  • 传统的面向对象语言中使用类来实现继承那么就有父类、子类的概念
  • 父类又称为基类,子类又称为派生类
  • 在JS中没有类的概念,在JS中常常称为父对象,子对象,基对象,派生对象。

三、认识原型

在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个[[Prototype]]内部属性,这个属性所对应的就是该对象的原型。

[[Prototype]]作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了__proto__这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器"Object.getPrototype(object)")。

下面通过一个例子来看看原型相关概念:

function Person() {}
// 神秘对象就是Person.prototype
//那么只有使用构造函数才可以访问它
var o = new Person();
//以前不能直接使用o来访问神秘对象
//现在有了__proto__后,
o.__proto__也可以直接访问神秘对象
//那么o.__proto__ === Person.prototype

神秘对象(原型)中都有一个属性constructor,翻译为 构造器 。表示该原型是与什么构造函数联系起来的。

__proto__有什么用?可以访问原型。由于在开发中除非特殊要求,不要使用实例去修改原型的成员,因此该属性开发时使用较少。但是在调试过程中非常方便,可以轻易的访问原型进行查看成员

如果在早期的浏览器中使用实例需要访问原型如何处理?可以使用实例对象访问构造器,然后使用构造器访问原型

var o = new Person();
o.constructor.prototype

如果给实例继承自原型的属性赋值

function Foo();
Foo.prototype.name = "test";
var o1 = new Foo();
var o2 = new Foo();
o1.name = "张三"; // 不是修改原型中的name而是自己增加了一个name属性
console.log(o1.name + ','+ o2.name); // 张三,test

四、构造、原型、实例三角结构图

对于如下代码:

function Person(){}
var p = new Person()

console.log(Person.prototype.constructor); //function Person(){}
console.log(Person.prototype.constructor.name); //Person
console.log(typeof Person.prototype.constructor); //function

console.log(p.__prop__);
console.log(p.__prop__ === Person.prototype);//true

于是他们的关系图如下:

JavaScript进阶(四)原型与原型链用法实例分析

五、对象的原型链

凡是对象就有原型,原型也是对象。因此凡是给定一个对象,那么就可以找到他的原型,原型还有原型,那么如此下去,就构成一个对象的序列,称该结构为原型链。

问题:

  1. 原型链到底到什么时候是一个头?
  2. 一个默认的原型链结构是怎样的?
  3. 原型链结构对已知语法的修正

5.1 原型链的结构

凡是使用构造函数,创建出对象,并且没有利用赋值的方式修改原型,就说该对象保留默认的原型链。

默认原型链结构是什么样子呢?

function Person(){}
var p = new Person();
//p 具有默认的原型链

默认的原型链结构就是:当前对象 -> 构造函数.prototype -> Object.prototype -> null

JavaScript进阶(四)原型与原型链用法实例分析

在实现继承的时候,有时候会利用替换原型链结构的方式实现原型继承,那么原型链结构就会发送改变

function DunizbCollection(){}
DunizbCollection.prototype = [];
var arr = new DunizbCollection();
// arr -> [] -> Array.prototype -> Object.prototype -> null

JavaScript进阶(四)原型与原型链用法实例分析

六、函数的构造函数Function

在JS中使用Function可以实例化函数对象 。也就是说在JS中函数与普通对象一样,也是一个对象类型。函数是JS中的一等公民。

  1. 函数是对象,就可以使用对象的动态特性
  2. 函数是对象,就有构造函数创建函数
  3. 函数是对象,可以创建其它对象
  4. 函数是唯一可以限定变量作用域的结果

要解决的问题

  1. Function 如何使用
  2. Function 与函数的关系
  3. 函数的原型链结构

6.1 函数是Function的实例

语法

new Function( arg0,arg1,arg1,….argN, body );

Function 中的参数全部是字符串

该构造函数的作用是将参数链接起来组成函数

  • 如果参数只有一个,那么表示函数体
  • 如果参数有多个,最后一个参数表示函数体,前面的所有参数表示函数的参数
  • 如果没有参数,表示创建一个空函数

举例:创建一个打印一句话的函数

// 传统的
function foo () {
 console.log( '你好' );
}
//Function
var func = new Function( 'console.log( "你好" );' );
// 功能上,这里foo 与 func 等价

再比如,创建一个空函数

//传统
function foo () {}
//Function
var func = new Function();
func();

传入函数内一个数字,打印该函数

//传统
function foo ( num ) {
 console.log( num );
}
//Function
var func = new Function( "num" ,"console.log( num )" );
func();

6.2 函数的原型链结构

任意的一个函数,都是相当于Function的实例,类似于{}与new Object()的关系。

function foo () {}

上面的代告诉解析器,有一个对象叫foo,它是一个函数;相当于new Function()得到一个函数对象

  • 函数应该有什么属性?答:__proto__
  • 函数的构造函数是什么?答:Function
  • 函数应该继承自Function.prototype
  • Function.prototype继承自Object.prototype

对于Function,我们还必须知道

  • Object函数是Function的一个实例
  • Object作为对象是继承自Function.prototype的,又“Function.prototype”继承自Object.prototype

    foo.prototype.__proto__ === Object.prototype // true
  • Function是自己的构造函数
  • 在JS 中任何对象的老祖宗就是Object.prototype
  • 在JS中任何函数的老祖宗就是Function.prototype

下面绘制出 Function 的构造原型实例三角形结构

JavaScript进阶(四)原型与原型链用法实例分析

6.3 为什么要使用Function?

Function是使用字符串构建函数,那么就可以在程序运行过程中构建函数.

以前的函数必须一开始就写好,再经过预解析,一步一步的运行

假定从服务器里拿到“[1,2,3,4,5]”,将数组形式的字符串转换成数组对象

var arr = ( new Function( 'return ' + str + ' ;' ) )();

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
使用正则替换变量
May 05 Javascript
js中indexof的用法详细解析
Dec 24 Javascript
javascript实现页面内关键词高亮显示代码
Apr 03 Javascript
对于jQuery性能的一些优化建议
Aug 13 Javascript
AngularJS+Node.js实现在线聊天室
Aug 28 Javascript
JS实现的N多简单无缝滚动代码(包含图文效果)
Nov 06 Javascript
跟我学习javascript的call(),apply(),bind()与回调
Nov 16 Javascript
Bootstrap前端开发案例一
Jun 17 Javascript
jQuery插件EasyUI实现Layout框架页面中弹出窗体到最顶层效果(穿越iframe)
Aug 05 Javascript
清除输入框内的空格
Dec 21 Javascript
为什么要使用Vuex的介绍
Jan 19 Javascript
python虚拟环境 virtualenv的简单使用
Jan 21 Javascript
JavaScript进阶(三)闭包原理与用法详解
May 09 #Javascript
JavaScript进阶(二)词法作用域与作用域链实例分析
May 09 #Javascript
JavaScript进阶(一)变量声明提升实例分析
May 09 #Javascript
JavaScript面向对象核心知识与概念归纳整理
May 09 #Javascript
Vue列表如何实现滚动到指定位置样式改变效果
May 09 #Javascript
Node.js API详解之 util模块用法实例分析
May 09 #Javascript
Vue实现PC端靠边悬浮球的代码
May 09 #Javascript
You might like
PHP 根据IP地址控制访问的代码
2010/04/22 PHP
Windows7下PHP开发环境安装配置图文方法
2010/05/20 PHP
YII框架http缓存操作示例
2019/04/29 PHP
JavaScript中“+=”的应用
2007/02/02 Javascript
Extjs实现进度条的两种便捷方式
2013/09/26 Javascript
深入理解JQuery keyUp和keyDown的区别
2013/12/12 Javascript
javascript中定义类的方法详解
2015/02/10 Javascript
浅谈js数组和splice的用法
2016/12/04 Javascript
vue动态改变背景图片demo分享
2018/09/13 Javascript
js逆向解密之网络爬虫
2019/05/30 Javascript
通过实例解析js简易模块加载器
2019/06/17 Javascript
vue history 模式打包部署在域名的二级目录的配置指南
2019/07/02 Javascript
解决vuex刷新状态初始化的方法实现
2019/08/15 Javascript
BootStrap表单验证中的非Submit类型按钮点击时触发验证的坑
2019/09/05 Javascript
JS co 函数库的含义和用法实例总结
2020/04/08 Javascript
详解vue之自行实现派发与广播(dispatch与broadcast)
2021/01/19 Vue.js
Python简单实现TCP包发送十六进制数据的方法
2016/04/16 Python
python3 发送任意文件邮件的实例
2018/01/23 Python
使用tensorflow实现线性回归
2018/09/08 Python
Python利用ORM控制MongoDB(MongoEngine)的步骤全纪录
2018/09/13 Python
python tkinter实现屏保程序
2019/07/30 Python
对Django的restful用法详解(自带的增删改查)
2019/08/28 Python
python 申请内存空间,用于创建多维数组的实例
2019/12/02 Python
django-利用session机制实现唯一登录的例子
2020/03/16 Python
探讨HTML5移动开发的几大特性(必看)
2015/12/30 HTML / CSS
中国第一家杂志折扣订阅网:杂志铺
2016/08/30 全球购物
GLAMGLOW格莱魅美国官网:美国知名的面膜品牌
2016/12/31 全球购物
Airbnb爱彼迎官网:成为爱彼迎房东,赚取收入
2019/03/14 全球购物
描述JSP和Servlet的区别、共同点、各自应用的范围
2012/10/02 面试题
写给学生的新学期寄语
2014/01/18 职场文书
部门活动策划方案
2014/08/16 职场文书
2014年仓库管理员工作总结
2014/11/18 职场文书
长城导游词
2015/01/30 职场文书
2016重阳节红领巾广播稿
2015/12/18 职场文书
该怎么书写道歉信?
2019/07/03 职场文书
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers