JS面向对象之原型
面向对象之原型
为什么要使用原型
由于 js 是解释执行的语言, 那么在代码中出现的函数与对象, 如果重复执行, 那么会创建多个副本, 消耗更多的内存, 从而降低性能
传统构造函数的问题
function Foo( ... ){
this.name = name;
this.age = age;
this.sayHello = function(){
...
}
}
- 由于对象是由
new Foo()创建出来的, 因此每一个对象在创建的时候, 函数 sayHello 都会被创建一次 - 每一个对象都含有一个对立的, 不容的, 但是功能逻辑一样的函数, 应该将单独的方法抽取出来, 让所有的对象共享该方法
- 使用传统方法的定义方式会影响性能, 在代码中创建方法就是消耗性能, 比如说内存
- 可以考虑将方法全部放到外面, 但是可能存在安全隐患
- 在开发中会引入各种框架和库, 自定义的成员越多, 出现命名冲突的几率越大
- 在开发中可能会存在多个构造函数, 每一个构造函数应该会有多种方法, 方法越多就越不容易维护
function sayHello(){}
function Foo(){
this.sayHello = sayHello;
}
- 每一个函数在创建的时候, 都会创建一个原型对象
- 任意一个对象都会默认链接到他的原型中
- 只要创建一个函数, 就会附带创建一个特殊的对象, 这个对象使用
函数.prototype引用, 这个特殊的对象是这个函数的原型属性 - 每一个由这个函数作为构造函数创建的对象, 都会默认链接到这个对象上( proto )
- 在该对象访问某一个成员( 方法或属性 ), 如果该对象中没有, 那么就会到这个原型对象中去查找
- 只要创建一个函数, 就会附带创建一个特殊的对象, 这个对象使用
var f1 = new Foo();
var f2 = new Foo();
f1.sayHello(); // 如果 f1 没有 sayHello, 那么就会在 Foo.prototype 中去找
f2.sayHello(); // 如果 f2 没有改方法, 那么就会在 Foo.prototype 中去找
- 由构造函数创建出来的多个对象会共享一个原型对象, 就是 构造函数.prototype
- 合理解决办法: 将共享的, 重复使用会多消耗性能的东西放到 构造函数.prototype 中, 那么所有由这个构造函数创建的对象就可以共享这些成员
function Foo() {}
Foo.prototype.sayHello = function () {
console.log( ... );
};
var f1 = new Foo();
f1.sayHello();
var f2 = new Foo();
f2.sayHello();
f1.sayHello === f2.sayHello
原型使用注意点
- 写 构造函数.prototype 的时候, 最好不要将属性也加到里面.
function Person() {}
Person.prototype.name = '张三';
var p = new Person();
- 赋值的错误
- 如果是访问数据, 当前对象中如果没有该数据就到构造函数的原型属性中去找
- 如果是写数据, 当对象中有该数据的时候, 就是修改值; 如果对象没有该数据, 那么就添加值
function Person() {}
Person.prototype.name = '张三';
var p1 = new Person();
var p2 = new Person();
p1.name = '李四';
console.log( p1.name );
console.log( p2.name );
原型相关概念
面向对象的相关概念
类 class : 在 js 中就是构造函数
* 在传统的面向对象语言中( c, java ), 使用一个叫做类的东西定义模板, 然后使用模板创建对象
* 在构造方法中也具有类似功能, 叫做类
实例( instance ) 与对象( Object )
* 实例一般是指摸一个构造函数创建出来的对象, 叫做 XXX 构造函数的实例对象
* 实例就是对象, 对象是一个泛称
* 实例与对象是一个近义词
键值对与属性和方法
* 在 js 中, 键值对的集合被叫做对象
* 如果值为数据( 非函数 ), 就称该键值对为属性 property
* 如果值为函数( 方法 ), 就称该键值对为方法 method
父类( 基类 )和子类( 派生类 )
* 传统的面向对象的语言中使用类来实现继承, 那么就有父类, 子类
* 父类又称为基类, 子类有称为派生类
* 在 js 中, 常常被称为扶对象, 子对象, 基对象, 派生对象
原型的相关概念
原型对象相对于构造函数被称为原型属性
* 原型对象就是构造函数的**原型属性**
* 简称原型
原型对象与构造函数所创建的实例对象也有联系
* 原型对象相对于构造函数创建的实例对象称为**原型对象**
* 简称原型
对象继承自原型
* 构造函数创建的实例对象 继承自 构造函数的原型属性( 构造函数.prototype )
* 构造函数创建的实例对象 继承自 该对象的原型对象
* 构造函数创建的实例对象与构造函数的原型属性表示的对象是两个不同的对象
* 原型中的成员, 可以直接被实例对象调用
* 实例对象 "*含有*" 原型中的成员
* 实例对象 继承自 原型
* 这样的继承就是 "原型继承"
构造函数是什么
* 凡是对象都有构造函数
* {} => Object
* [] => Array
* /./ => Regexp
* function... => Function
如何使用原型
- 使用对象的动态特性
- 构造函数.prototype.XXX = vvv;
- 直接替换
function Person() {}
Person.prototype = {
constructor: Person
};
// 拆解
function Person() {}
var o = {};
o.costructor = Person; // 属性中就存储着函数的地址
Person.prototype = o;
Person = 123;
这两种使用方法的区别
- 原型指向发生了变化
- 构造函数所创建的对象所继承的原型不同
- 新增的对象默认是没有 constructor 属性
注意: 在使用替换的方式修改原型的时候, 一般都会添加 constructor 属性
proto
- 以前访问原型, 必须使用构造函数才能实现, 无法直接使用实例对象来访问原型
- firefox 最早引入了
__proto__属性, 来表示使用实例对象引用原型, 早期是非标准的 - 通过
__proto__属性可以允许使用实例对象直接访问原型
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 );
继承
- 最简单的继承就是 将别的对象的属性加到这个对象身上, 那么这个对象就有这个成员了
- 利用原型也可以实现继承, 不需要在这个对象身上添加任何成员, 只要原型有, 实例对象也有
- 所以将属性和方法等成员利用 混入 的办法, 加到构造函数的原型上, 那么构造函数的实例就都具有这些属性和方法了
静态成员和实例成员
- 静态成员表示的是 静态方法 和 静态属性, 静态就是由 构造函数提供的
- 实例成员表示的是 实例方法 和 实例属性, 实例就是由 构造函数创建的实例对象
- 一般情况下, 工具方法都是由 静态成员 提供, 与实例对象有关的方法由 实例成员 表示
构造函数 与 原型 与 构造函数创建的实例对象 的关系
function Person(name){
this.name = name;
}
var P1 = new Person('Jim');

属性搜索原则( 就近原则 )
- 所谓的属性搜索原则, 就是对象在访问属性与方法的时候, 首先在当前对象中查找
- 如果当前对象中存储在属性或方法, 停止查找, 直接使用该属性与方法
- 如果对象没有改成员, 那么再其原型对象中查找
- 如果原型对象含有该成员, 那么停止查找, 直接使用
- 如果原型还没有, 就到原型的原型中查找
- 如此往复, 直到直到 Object.prototype 还没有, 那么就返回 undefied.
- 如果是调用方法就包错, 该 xxxx 不是一个函数
JS面向对象之原型的更多相关文章
- JS面向对象,原型,继承
ECMAScript有两种开发模式:1.函数式(过程化),2.面向对象(OOP).面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象.但是,ECMAScript ...
- js面向对象与原型
创建对象 var box = new Object();//创建对象 box.name = 'Lee'; //添加属性 box.age = 100; box.run = function(){ ret ...
- JS面向对象之原型链
对象的原型链 只要是对象就有原型 原型也是对象 只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成 ...
- 从零开始的全栈工程师——JS面向对象( 原型 this 继承)
一.生成对象的方式 ①单例模式(字面量定义)var obj = {} ②类的实例 var obj = new Object( ) ③工厂模式 ④构造函数:扮演三种角色 普通函数 普通对象 类 工厂模式 ...
- JS面向对象——动态原型模型、寄生构造模型
动态原型模型 组合使用构造函数模型和原型模型,使得OO语言程序员在看到独立的构造函数和原型时很困惑.动态原型模型致力于解决该问题,它把所有的信息封装在构造函数中,通过在构造函数中初始化原型(仅在必要情 ...
- JS面向对象(2) -- this的使用,对象之间的赋值,for...in语句,delete使用,成员方法,json对象的使用,prototype的使用,原型继承与原型链
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- js面向对象-原型链
var Person = function (name) { this.name = name; } Person.prototype.say = function () { console.log( ...
- 【JavaScript】 JS面向对象的模式与实践 (重点整治原型这个熊孩子 (/= _ =)/~┴┴ )
参考书籍 <JavaScript高级语言程序设计>—— Nicholas C.Zakas <你不知道的JavaScript> —— KYLE SIMPSON 在JS的面向 ...
- js面向对象、创建对象的工厂模式、构造函数模式、原型链模式
JS面向对象编程(转载) 什么是面向对象编程(OOP)?用对象的思想去写代码,就是面向对象编程. 面向对象编程的特点 抽象:抓住核心问题 封装:只能通过对象来访问方法 继承:从已有对象上继承出新的对象 ...
随机推荐
- 【poj1743-Musical Theme】不可重叠最长重复子串-后缀数组
http://poj.org/problem?id=1743 这题是一道后缀数组的经典例题:求不可重叠最长重复子串. 题意: 有N(1 <= N <=20000)个音符的序列来表示一首乐曲 ...
- 【洛谷 P4886】 快递员 (点分治)
这题因为一些小细节还是\(debug\)了很久...不过我第一次用脚本对拍,不亏. 先随便找一个点作为根,算出答案,即所有点对到这个点的距离和的最大值,并记录所有距离最大的点对.如果这个点在任意一个距 ...
- TLS回调函数
@author: dlive TLS (Thread Local Storage 线程局部存储 )回调函数常用于反调试. TLS回调函数的调用运行要先于EP代码执行,该特性使它可以作为一种反调试技术使 ...
- 命令行工具PathMarker
一直使用Guake 终端,Guake提供的其中一个功能是快速打开. 大概的意思就是,显示在终端上的数据会经过匹配,如果符合一定的规则,则可以按住ctrl,使用鼠标单击以触发指定操作. 比如对于一个文件 ...
- Python3安装cx_Oracle连接oracle数据库实操总结
弄清版本,最重要!!! 首先安装配置时,必须把握一个点,就是版本一致!包括:系统版本,python版本,oracle客户端的版本,cx_Oracle的版本,然后安装配置就容易了! 如果已经安装Pyth ...
- 【bzoj1086】王室联邦
我以为树分块什么的必有高论,结果居然是个暴力…… 方法也很简单,我看下每个节点dfs的时候是否已经大于k个,大于的话我就新开一块. 注意dfs的时候当前节点不能放进子树的块中. #include< ...
- golang之http
go获取html页面 package main import ( "fmt" "io/ioutil" "net/http" "ne ...
- Newtonsoft.Json 序列化和反序列化 以及时间格式 2 高级使用
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
- OC学习——OC中的@protocol(@required、@optional)、代理设计模式
一.什么是协议? 1.协议声明了可以被任何类实现的方法 2.协议不是类,它是定义了一个其他对象可以实现的接口 3.如果在某个类中实现了协议中的某个方法,也就是这个类实现了那个协议. 4.协 ...
- CSS中的HSLA颜色
CSS 中的颜色可以由RGB色彩空间和HSL色彩空间两种方式来表述.其中我们常用的是RGB色彩空间,RGB色彩空间的颜色表示方式有:十六进制颜色(如红色:#FF0000).RGB颜色(如红色:rgb( ...