简介

在基于原型的对象系统中,至少包含以下规则:

(1) 一切皆对象

(2) 创建一个对象的方式是找到一个原型对象,并克隆它,而不是通过实例化类

(3) 对象会记住它的原型

(4) 对象会继承它的原型链中的所有内容

创建对象:

  在 JS 中可以通过对象字面量或者构造函数来创建对象

//示例一:通过对象字面量创建对象
var boy = {
name: 'Bob',
sex: 'male'
}
//示例二:通过构造函数创建对象
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
var boy = new Person('Bob', 'male');

一切皆对象

  事实上,在 JS 中并非一切皆对象,这只是一种笼统的说法,由于 JS 引入了两种数据类型:基本类型 ( Undefind、 Null、 Boolean、 Number 和 String ) 和对象类型 ( Object ),对象类型是对象自然不必多说,问题在于基本类型是对象吗?我们先上字符串类型来说明一下:

var str = 'Make life better';
console.log(str.length); //输出 16

按理说 "str" 变量只是一个字符串,但是它却使用了对象才有的 "length" 属性,输出了字符串的长度,因此这里我们有理由把字符串类型看成对象,称为 "包装对象"。这个对象是临时的,也就是说只有在读取它的属性的时候 JS 才会把这个字符串通过 new String() 方式创建成一个字符串对象,一旦引用结束这个对象就被销毁了,换句话说 "包装对象" 的属性是 "只能读,不能写" 的。同理 "Boolean" 和 "Number" 在读取属性的时候也可以通过自己的构造函数来创建自己的一个包装对象,并像对象一样引用各自的属性。

其次,"null" 表示 "空值",对 "null" 执行 "typeof" 操作,输出结果为 "Object",所以我们也可以把 "null" 看成一个对象,称为 "空对象"

最后,"undefind" 表示 "未定义",当我们对变量只声明没有初始化时,输出 "undefind",或者引用一个不存在的属性时,输出也为 "undefind",对 "undefind" 执行 "typeof" 操作的输出结果为 "undefind",这么说来 "undefind" 其实并不属于对象范畴

创建一个对象的方式是找到一个原型对象,并克隆它,而不是通过实例化类

  在 JS 中,"Object.prototype" 是所有对象的原型,我们并不需要关心克隆的细节,因为这是引擎内部负责实现的。我们所需要做的只是显式地调用 var obj1 = {}; 或者 var obj2 = new Object(),此时,引擎内部会从 "Object.prototype" 上面克隆一个对象出来,作为新对象的原型。

示例一:

var obj1 = {};
var obj2 = new Object();
console.log(Object.getPrototypeOf(obj1) === Object.prototype); //输出true
console.log(obj2.__proto__ === Object.prototype); //输出true

每个对象都具有 "__proto__"(前后两个下划线) 属性,它指向该对象的原型,但是它只是一个内部属性,而不是一个正式的对外 API,原则上是不能访问的,这是由于很多浏览器的支持,才把这个属性暴露出来了。在ES5中使用 "Object.getPrototypeOf()" 获取一个对象的原型,在ES6中可以使用 "Object.setPrototypeOf()" 设置一个对象的原型。因此,在这里两者的作用都是一样的,都是获取对象的原型,并且它们的原型都是 "Object.prototype"。

只有函数才有 "prototype" 属性,例如 "Object.prototype"。另外函数也是一个对象,对于函数而言,"__proto__" 属性指向它自己的原型, "prototype" 属性则是通过这个函数构造出来的实例的原型,可以理解为这样一条原型链,"__proto__" 总是指向原型链的顶端,而函数恰好可以延长原型链,于是它将自己 "prototype" 属性指向的对象压入原型链的顶端,自然它构造出来的实例的 "__proto__" 属性指向原型链的顶端,也就是构造函数的 "prototype"属性。

示例二:

function Person(name, sex) {
this.name = name;
this.sex = sex;
}
var boy = new Person('Bob', 'male');
console.log(Object.getPrototypeOf(Person) === Function.prototype); //true
console.log(Object.getPrototypeOf(boy) === Person.prototype); //true

Person 函数继承自 Function 对象,如果这么写就很直观了:

var Person = new Function('name', 'sex', 'this.name = name;this.sex = sex;');

因此 Person 函数的原型指向 Function.prototype,boy 对象是通过 Person 函数构造而来的,因此它的原型指向 Person.prototype。

对象会记住它的原型

  上面已经提到,JS 给所有对象提供了一个 "__proto__" 属性,用于访问它的原型

对象会继承它的原型链中的所有内容

示例:

function A() {}
A.prototype = { name: 'better' };
var a = new A();
console.log(a.name); //输出better

a 对象本身没有 "name" 属性,于是在它的原型,即构造函数的 "prototype" 中去找,如果找到,则停止上溯,输出结果。

面向对象编程

  当要创建两个或多个对象时,如果直接使用字面量或者构造函数方式将会产生不必要的重复代码,例如:

var obj1 = {
name: 'test1',
sayName: function() {
console.log(this.name);
}
}
var obj2 = {
name: 'test2',
sayName: function() {
console.log(this.name);
}
}

"obj1" 和 "obj2" 共享同一个方法 "sayName()",但是它们却占用了两份内存,因此最好是通过构造函数的方式实现私有属性的继承,再通过原型的方式实现共有属性和共有方法的继承,例如:

function CreateObj(name) {
this.name = name;
}
CreateObj.prototype.sayName = function() {
console.log(this.name);
}
var obj1 = new CreateObj('test1');
var obj2 = new CreateObj('test2');

JS基础:基于原型的对象系统的更多相关文章

  1. JS基础-全局内置对象

    对象 JS中有那些内置对象 数据封装类对象 String.Array.Object.Boolean.Number 其他对象 Math.Date.RegExp.Error.Function.Argume ...

  2. JS基础语法---内置对象

    js学习中三种对象: 内置对象----js系统自带的对象 自定义对象---自己定义的构造函数创建的对象 浏览器对象---BOM的时候讲 内置对象: Math Date String Array Obj ...

  3. Js基础知识7-Es6新增对象Map和set数据结构

    前言 JavaScript中对象的本质是键值对的集合,ES5中的数据结构,主要是用Array和Object,但是键只能是字符串.为了弥补这种缺憾,ES6带来了一种新的数据结构Map. Map也是键值对 ...

  4. JS基础_原型对象

    原型prototype 我们创建的每一个函数,解析器都会向函数中添加一个属性prototype 这个属性,对应着一个对象,这个对象就是我们所谓的原型对象 1.如果函数作为普通函数调用prototype ...

  5. js基础篇——原型与原型链的详细理解

    js中的对象分为两种:普通对象object和函数对象function. function fn1(){}; var fn2 = function(){}; var fn3 = new Function ...

  6. JS基础——JavaScript原型和原型链及实际应用

    构造函数 function Stu(name,age){ this.name=name; this.age=age; } instanceof 查看引用类型对象是属于哪个构造函数的方法,通过__pro ...

  7. js基础知识之_对象

    javascript 对象 1.基于对象 一切皆对象,以对象的概念来编程 2.面向对象的编程(oop,Object oriented programming) 1.对象 就是人们要研究的任何事物,不仅 ...

  8. JS基础---常见的Bom对象

    BOM(Browser Object Mode)浏览器对象模型,是Javascript的重要组成部分.它提供了一系列对象用于与浏览器窗口进行交互,这些对象通常统称为BOM. 一张图了解一下先 1.wi ...

  9. js基础回顾----原型链和原型

    所有的对象都可以自由扩展属性 (null 除外) 所有的引用类型(对象,数组,函数)都有一个_proto_属性 所有的函数都有一个prototype属性 所有引用类型对象的_proto_属性指向它的的 ...

随机推荐

  1. Servlet3.0注解@WebInitParam和@WebServlet

    在以前的servlet中我们初始化一些参数都是配置在web.xml中的,自从servlet3.0之后给我们提供了注解@WebServlet和@WebInitParam,@WebServlet是用来配置 ...

  2. UNIX网络编程——内网与外网间通信

    QQ是一个基于TCP/UDP协议的通讯软件 发送消息的时候是UDP打洞,登陆的时候使用HTTP~因为登陆服务器其实就是一个HTTP服务器,只不过不是常用的那些,那个服务器是腾讯自行开发的!!! 一.登 ...

  3. 看人装X,我就来气,开启极限装X模式

    本文书写,纯属扯淡,请勿观看 4进制比二进制更合理,在01的状态中添加了两种状态,从无到有和从有到无的两种过度状态. 如果非要用数值表示,用概率表示.01作为近代计算机的基础,但终究淘汰,构成下一代计 ...

  4. Tomcat如何检测内存泄漏

    一般情况下,如果我们重启web应用是通过重启tomcat的话,则不存在内存泄漏问题.但如果不重启tomcat而对web应用进行重加载则可能会导致内存泄漏,因为重加载后有可能会导致原来的某些内存无法让G ...

  5. 关于Class文件

    什么是Class文件 Java人对class文件肯定很熟悉了,它是Java源码编译后的产物.JVM运行时负责加载class文件,并根据class定义的执行逻辑运行.java为了将硬件底层的差异屏蔽掉, ...

  6. 调用sed命令的三种方式

    调用sed命令的三种方式 调用sed有三种方式,一种为Shell命令行方式,另外两种是将sed命令写入脚本文件,然后执行该脚本文件. 三种方式的命令格式归纳如下: 一.在Shell命令行输入命令调用s ...

  7. python的sorted

    读入后,要进行组内排序,按groupseq字段排序后,然后统计前后两个项的个数,累加到全局. sorted函数使用如下: def sortlist(alllist):     sorted_key1_ ...

  8. UVa - 116 - Unidirectional TSP

    Background Problems that require minimum paths through some domain appear in many different areas of ...

  9. 安全退出app,activoty栈管理

    前言 由于一个同学问到我如何按照一个流程走好之后回到首页,我以前看到过4个解决方案,后来发现有做个记录和总结的必要,就写了这篇博文.(之前看小强也写过一篇,这里通过自身的分析完整的总结一下以下6种方案 ...

  10. DigitalClock的替代者TextClock

    DigitalClock在API 17(Android4.2)中就被官方定义为过时的方法,很奇怪为什么现在很多的网上的帖子都介绍DigitalClock方法的使用(已经过时),如果你想让自己的应用在高 ...