JavaScript原型链(重要)
1. 构造函数与原型
先了解一个概念:
类就是对象的模板,对象就是类的实例。
在构造函数内部的this指向它的实例对象。
2. new关键字
这个也是面试常考的知识点
在实例化构造函数时,做了什么?或者说在JavaScript中new
创建空对象
var zs = { }
将构造函数内部的this指向空对象
this -> zs
把属性和方法挂载到实例对象上。
zs.name zs.age zs.sing()
隐式返回新对象。
3. 实例成员与静态成员
- 实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问。
- 静态成员:在构造函数本身上添加的成员称为静态成员,只能由构造函数本身来访问。
var arr = new Array()console.dir(arr);console.dir(Array);
4. 构造函数与静态成员
同一个函数,会在内存中保存多份,会造成内存的浪费。
<script>function Cup(color, size) {this.color = colorthis.size = sizethis.save = function () {console.log("储水");}}var mycup1 = new Cup("紫色", "3400ml")var mycup2 = new Cup("绿色", "400ml")console.log(mycup1);console.log(mycup2);mycup1.save()mycup2.save()引用数据类型,比较的是内存中的地址console.log(mycup1.save == mycup2.save);输出false地址不同,造成浪费
</script>
引用性数据类型比较的是地址
5. 原型对象Prototype/[__proto__]
是构造函数的属性;
是Object类
构造函数的原型protoeype,作用是实现对象和属性共享,解决内存浪费问题。
每个一构造函数都有一个protoeype属性指向一个对象,这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所有。
一般情况下,我们公共属性放在构造函数里面,公共的方法我们放到原型对象身上。
原型对象里面的this指向的就是这个实例对象
作用:可以通过原型对象,对原来的内置对象进行拓展自定义的方法。
function Cup(color, size) {this.color = colorthis.size = sizeCup.prototype.save = function () {console.log("储水");}Cup.prototype.fill = function () {console.log("储水");}}
6. __proto__
对象能够访问原型对象中的方法:
原因:对象的_ _ proto_ _ 属性指向构造函数的prototype/原型对象
名称:对象原型
__proto__对象原型和原型对象prototype是等价的
__proto__
对象原型的意义就在于为对象的查找机制提供一个方向,或者说是一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,他只是内部指向原型对象prototype.
非标准:
不能使用,只能直接看他指向的结果,不能设置,只能直接访问
7. constructor属性
对象原型(__proto__
)和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因此它指回构造函数本身。
- 作用:主要用于记录该对象引用哪个构造函数,它可以让原型对象重新指向原来的构造函数。
constructor属性在那里可以访问:
__proto__
有constructor属性
原型对象/prototype
有constructor属性
我们称constructor为构造函数。
使用:当以对象的形式修改原型对象
的内容时,会发现修改后的属性把原来的属性覆盖掉了,这时候就需要重新设置一下constructor属性,并指挥回原来的构造函数。
function Cup(color, size) {this.color = colorthis.size = size}Cup.prototype = {constructor: Cup,save: function () {console.log("储水");},warn: function () {console.log("保温");}}
(以对象的形式,修改了原型对象中的内容,这样修改后的原型对象constructor就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个constructor指向原来的构造函数)
8.原型链
JavaScript对象,都有__proto__属性
,指向原型对象。
(mycup,Cup,Object,null)
- 作用:js中在查找对象和属性的方式时,遵循的一条链式规则。
- 当访问一个对象的属性(包括方法)时,首先找到这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是
__proto__
指向的prototype原型对象) - 如果还没有就查找原型对象的原型(Object原型对象)
- 以此类推一直找到Object为止(null)
__proto__
对象原型的意义在于为对象成员查找机制提供了一种方向,或者说一条路线。
如果原型链找不到属性,undefined。如果找不到方法,会报错。
关系:
instance.constructor.prototype == instance.__proto__
特点:JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
小例子:
function Cup(color, size) {this.color = colorthis.size = size}Cup.prototype = {constructor: Cup,save: function () {console.log("储水");},warn: function () {console.log("保温");}}var mycup = new Cup("粉色", "1500ml")console.log(mycup);console.log(mycup.__proto__ == Cup.prototype);console.log(mycup.__proto__.constructor); //指向当前的构造函数console.log(Cup.prototype.constructor); //指向当前的构造函数//验证原型链console.log(mycup.__proto__ == Cup.prototype);console.log(Cup.prototype.__proto__ == Object.prototype);console.log(Object.prototype.__proto__ == null);var arr = [1, 2, 3]var arr1 = new Array(1, 2, 3)console.log(arr, arr1);arr1.push(4)Array.prototype.sum = function () {var total = 0;for (var i = 0; i < this.length; i++) {total += this[i];}return total}console.log(arr.sum());console.log(arr1.sum());
9.继承
JavaScript如何实现继承
- 构造继承
- 原型继承
- 实例继承
- 拷贝继承
- 原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式
function Parent(){this.name = 'wang';
}function Child(){this.age = 28;
}Child.prototype = new Parent();//继承了Parent,通过原型var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被继承的属性
ES6:利用extends实现继承
组合继承:构造函数+原型对象
es5继承:构造函数+原型对象
//es5继承:构造函数 + 原型对象//1. 利用构造函数继承属性function Father(name, age) {this.name = namethis.age = age}Father.prototype.work = function () {console.log("工作");}function Son(name, age, gender) {Father.call(this, name, age);this.gender = gender;}Son.prototype = new Father() //子构造函数的peototype = new 父构造函数Son.prototype.constructor = Son; // 子构造函数的constructor手动设置为sonSon.prototype.study = function () {console.log("学习");}var son = new Son('xh', 6, "男")console.log(son);
核心原理:
- 将子类所共享的方法提取出来,让子类的prototype原型对象 = new 父类()
- 本质:子类原型对象等于是实例化父类,因为父类实例化后另外开辟空间,就不会影响原来的父类
- 将子类的constructoe重新指向子类的构造函数
Son.prototype = new Father() //子构造函数的peototype = new 父构造函数Son.prototype.constructor = Son; // 子构造函数的constructor手动设置为son
利用原型对象继承方法
es6:继承: extend
//es6: 类 extendsclass Father1 {constructor(name, age) {this.name = namethis.age = age}work() {console.log("父亲工作");}}class Son1 extends Father1 {constructor(name, age, gender) {super(name, age)this.gender = gender}study() {console.log("子学习");}}var son1 = new Son1("小米", 20, "男")console.log(son1);
es6继承的关键:
extend
,super
10.对象的特性
- 封装
将对象所有的组成部分组合起来,尽可能的隐藏对象的部分细节,使其受到保护,只提供有限的接口与外部发生联系。
- 优点:
- 安全,使用时无法看到具体的细节,只需要直接调用
- 便于修改操作
- 继承
将对象拥有另外一个对象的属性和方法。
父类(基类):被继承的对象。
子类:继承的对象
- 优点:
- 提高代码重用性,提高代码的逻辑性和可维护性。
使用es5和es6实现类的封装
- es5
//es5 构造函数+原型对象function Cup(color, size) {this.color = colorthis.size = size}Cup.prototype = {constructor: Cup,save: function () {console.log("储水");},warn: function () {console.log("保温");}}var mycup = new Cup("粉色", "1500ml")
- es6
//es6类 语法糖class Cup1 {constructor(color, size) {this.color = colorthis.size = size}save() {console.log("储水");}warn() {console.log("保温");}}var mycup1 = new Cup("绿色", "500ml")var mycup2 = new Cup1("蓝色", "600ml")
上面这两种完全等同,但es6的更简单,封装更容易
11.函数
函数的三种定义方式
- 利用funcation关键字定义函数,也叫
命名函数
//定义,利用funcation 命名函数function fn() {console.log(1);}fn()
- 利用字面量定义函数,也叫
匿名函数
//2. 字面量定义 匿名函数var fn1 = function () {console.log(2);}fn1()
由于声明函数方式的不同以及预解析的因素,导致1,2两种方式略微不同。1,这种定义方式,把函数调用提前是完全没有问题的,但2,这种方式就会报错。(预解析知识点)
- 实例化Funcation
//3.实例化Funcationvar fn2 = new Function('num', 'concole.log(num)')fn2(3)
这种方式也是可以传参的,但由于写法复杂,用的并不多。
函数的调用
- 普通函数,this指向window
function fn() {console.log("普通函数");}fn();
- 构造函数,this指向实例化的对象
function Cup(size) {this.size = size}var cup = new Cup("500ml")
- 原型对象的方法,this指向实例化的对象
Cup.prototype = {constructor: Cup,save: function () {console.log("储水");}}var cup = new Cup("500ml")cup.save();
- 事件处理函数,this指向事件源 < button >< /button >
var btn = document.querySelector("button")btn.onclick = function () {console.log("事件处理函数");console.log(this);}
- 定时器函数,this 指向window
setTimeout(function () {console.log("定时器中的函数");}, 1000)
- 立即执行函数,this 指向window
(function () {console.log("立即执行函数");})()
改变this指向的三种方式
call方法
- 调用函数
- 改变this指向
fn.call(thisAry,arg1,arg2,...)
- thisAry:当前调用函数this的指向对象
- arg1,arg2:传递的其他参数
返回值就是函数的返回值
var obj = { name: "zs", age: 20 }function fn(num) {console.log(1); 20console.log(this); 21console.log(num); 22}fn(0); 25fn.call(obj, 'call') 28
很明显可以看到又调用了 一次函数。而且this指向也变成了obj,不再是window了
apply方法
- 调用函数
- 改变this指向
fun.apply(thisAry,[arg1,arg2])
- thisAry:在fun函数运行时指定的this值
- arg1,arg2 :传递的其他参数
返回值就是函数的返回值
var obj = { name: "zs", age: 20 }function fn(num) {console.log(1); 20console.log(this); 21console.log(num); 22}fn(0); 25fn.apply(obj, ['apply']) 31
和call方法一样,也会调用函数
也可以不改变参数只传值,不常用。
fn.apply(null, ['apply'])
bind方法
用到比较多
- 改变this指向
fun.bind(thisArg,arg1,arg2,...)
- thisArg:在fun函数运行时指向的this值
- arg1,arg2:传递的参数
返回由原来函数改变this之后的新函数
var obj = { name: "zs", age: 20 }function fn(num) {console.log(1); 20console.log(this); 21console.log(num); 22}fn(0); 25var f = fn.bind(obj, "bind") 33fn() 34
总结
是否可以改变this指向 | 是否可以调用函数 | 返回值 | 使用场景 | |
---|---|---|---|---|
call | 是 | 是 | 就是函数返回值 | 用来继承 |
apply | 是 | 是 | 就是函数返回值 | 数组相关 |
bind | 是 | 否 | 返回由原函数改变this之后的新函数 | 不希望函数立即执行(比如定时器) |
原型,构造函数,实例,以及原型链
原型,构造函数,实例三者之间的关系
JavaScript原型链(重要)相关推荐
- javascript原型链中 this 的指向
为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = {d: 40};var a = {x: 10,calculate: function (z) {retu ...
- 深度解析JavaScript原型链
深度解析JavaScript原型链 文章目录 深度解析JavaScript原型链 前言 JavaScript原型链,这里只分享我自己的见解 一.原型链是什么 二.心得 三图解 总结 前言 JavaSc ...
- JavaScript原型链污染攻击
前言 最近在看js的时候看到p神的一篇关于js原型链污染的文章,学习一下. 下面转自p神:深入理解 JavaScript Prototype 污染攻击 还有一篇案例关于js原型链污染的ctf题:从一道 ...
- JavaScript 原型链和继承面试题
JavaScript 原型链和继承问题 JavaScript 中没有类的概念的,主要通过原型链来实现继承.通常情况下,继承意味着复制操作,然而 JavaScript默认并不会复制对象的属性,相反,Ja ...
- JavaScript 原型链常用方法
JavaScript 原型链常用方法 对象属性类型 数据属性 Configurable(表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性) En ...
- 技术分享经典 javaScript原型链面试题
技术分享 javaScript原型链 一个小题目 前置知识 变量提升和函数提升 this指针的指向 原型链是什么 new操作符的工资流程 一个小题目 今天我们部门的技术分享上出现了这样一段代码: fu ...
- 如何理解JavaScript原型链
如何理解JavaScript原型链 实例对象与原型对象的关系 构造函数.原型对象和实例对象之间的关系 原型链结构图 函数在原型链中的结构 原型链的理解和总结 实例对象与原型对象的关系 构造函数.原型对 ...
- JavaScript原型链以及Object,Function之间的关系
JavaScript里任何东西都是对象,任何一个对象内部都有另一个对象叫__proto__,即原型,它可以包含任何东西让对象继承.当然__proto__本身也是一个对象,它自己也有自己的__proto ...
- 理解JavaScript原型链
JavaScript中的每个对象都有一个prototype属性,我们称之为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联起来了一条原型链,原型链的链头是object,它的prototy ...
- JavaScript原型链的理解
一.原型链的概念 JavaScript是一门面向对象的编程语言,JavaScript 中的所有事物都是对象,并且对象与对象之间不是彼此独立的,而是有"继承"关系的. 这种" ...
最新文章
- Spark、Flink、CarbonData技术实践最佳案例解析
- continue和break的区别
- 设备驱动--中断开关执行的匹配
- RNN以及LSTM的介绍和公式梳理
- java 成员变量声明顺序_C++核心准则讨论:按照成员声明的顺序定义和初始化成员变量...
- workflow and email in QD3 - IS_INBOX_USER method
- mysql怎么访问用户B_MySQL访问控制和用户管理
- iframe异步加载_5种延迟加载图像的方法以帮助你提升网站性能与用户体验
- mysql 指令没有用_Mysql指令
- C++ 语法概括总结
- 计算机学生的高职英语课程,高职计算机英语课程教学方法探索
- 科学管理之父——泰勒的故事
- 数学|如何求解线性方程系数?
- 报错org.apache.ibatis.builder.BuilderException: Error creating SqlSource for SqlProvider. Method ‘inse
- Xcode6中如何添加pch文件
- Word2013使用 插入题注的方式为word自带编辑器编辑的公式进行编号
- 彩信数据库mmssms.db
- 自学java面向实习从零开始路线
- 老牌CRM厂商,轻松玩转SaaS!
- OpenWRT实现NAT64/DNS64
热门文章
- 【JAVA】读取excel导入数据库,形成树状结构
- 最大团算法(Maximum Clique)
- 10分钟完成蓝牙模块与手机之间的数据读写交互
- 安装Office2016,桌面没有PPT图标,右键新建没有图标
- python计算菜单消费总额字典_三、Python的列表、字典、元组合集合
- 65、Spark Streaming:数据接收原理剖析与源码分析
- 百年前的小学课本令人汗颜!
- css实现带小三角形的边框
- visualsvn php,windowns下使用TortoiseSVN与VisualSVN Server搭建SVN版本控制系统
- 八年级计算机考操作试题,初二信息技术考试试题及答案