继承

mixin混合继承

    function mixin(obj1, obj2) {for (var key in obj2) {//重复不复制if (!(key in obj1)) {obj1[key] = obj2[key];}}return obj1;}

  这种复制是浅复制,对象或者数组函数等都是同一个引用,改变obj1的会同时影响obj2。

寄生继承

  ...

隐式继承

  子类调用fn.call(this)

  深拷贝需要重新声明一个变量(对象),遍历(递归)复制,详情见我的函数技巧,不贴出来了。

原型

  Javascript对象中有一个特殊的[[prototype]]内置属性,其实就是对于其他对象的引用。几乎所有的对象在创建时[[prototype]]属性都会被赋予一个非空的值。

    var f = {a: 1};// 创建一个对象 原型为fvar f2 = Object.create(f);// 通过原型链找到了属性aconsole.log(f2.a);

  使用for..in遍历对象的原理和原型链类似,任意可枚举在原型链上的属性都会被遍历。使用in操作符检查属性时也会查找对象原型链,无论是否可枚举。

  所有普通对象的原型最终指向Object.prototype。

  详细讲解一个对象赋值语句:

    var obj = {};obj.a = 1;

  这里有四种情况:

  1、obj中存在a属性,就会被修改。

    var obj = {a: 2};obj.a = 1;console.log(obj.a); //1

  2、obj的原型链不存在a属性,就会被直接添加到obj上。

    var obj = {};console.log('a' in obj); //falseobj.a = 1;console.log(obj.a); //1

  3、obj与obj的原型链都存在a属性,就会发生屏蔽,obj中的a会屏蔽原型链上的a。

    var obj2 = {a: 2};var obj = Object.create(obj2);obj.a = 1;console.log(obj.a); //1

  4、obj的原型链上存在a属性,而obj不存在时,会出现多种情况。

  在原型链上存在a属性且没有被标记为只读,那就会直接在obj添加一个a属性。(情况3)

  在原型链上存在a属性且被标记为只读,那么无法创建该属性,严格模式会报错,普通模式赋值语句会被忽略。

    // 在'use strict'模式下// Cannot assign to read only property 'a' of object '#<Object>'var obj2 = {};Object.defineProperty(obj2, 'a', {value: 2,configurable: true,enumerable: true,writable: false})var obj = Object.create(obj2);obj.a = 1; //无效console.log(obj.a); //2

  如果在原型链上存在a并且它是一个setter,那就一定会调用这个setter。a不会被添加到obj,也不会重新定义setter。

    var obj2 = {set a(val) {console.log(1);}};var obj = Object.create(obj2);obj.a = 1; // 执行set并输出1

  如果希望怎么样都添加属性,请使用Object.defineProperty(...)。

关于prototype

  所有函数默认都会拥有一个名为prototype的公有不可枚举属性,它会指向另外一个对象:

    function fn() {console.log(1);}console.log(fn.prototype); //Object{}

  这个对象通常被称为fn的原型,实际上不如叫fn.prototype。

    function fn() {console.log(1);}var f = new fn();console.log(f.__proto__ === fn.prototype); //true

  在调用new fn()时,会创建一个对象,并给一个内部[[prototype]]链接,连接到fn.prototype。个人感觉__proto__这个浏览器私有实现的属性叫原型比较好,毕竟原型链是通过这个属性向上查找的。

  实际上,new操作符实际上并没有直接创建关联,这只是一个副作用。

  通过Object.create()方法才是正规创建原型链接的方法。

  上一段代码很容易让人认为fn是一个构造函数,因为这里用new来调用它并构造出一个对象。

  实际上,fn和普通的函数没有区别。函数本身不是构造函数,当在普通的函数前面加上new时,就会把这个函数调用变成了一个‘构造函数调用’。实际上,new会劫持所有普通函数并用构造形式来调用它。

  

  考虑下面一段代码。

    function fn(a) {this.a = a;}fn.prototype.getA = function() {return this.a;}var f1 = new fn(1);var f2 = new fn(2);console.log(f1.getA()); //1console.log(f2.getA()); //2

  这段代码展示了两种面向类的技巧:

  1、this.name=name给每个对象都绑定了.name属性。

  2、fn.prototype.getA=...给原型添加了一个方法,现在,每一个实例都可以调用getA方法。

  看起来,似乎创建f1、f2时会把对象复制到这两个新对象中,然而实际上只是通过原型链向上查找调用了方法而已。

关于constructor

    function fn1() {};var f1 = new fn1();console.log(f1.constructor === fn1); //true//替换默认原型function fn2() {};fn2.prototype = {};var f = new fn2();console.log(f.constructor === fn2); //falseconsole.log(f.constructor === Object); //true

  当前用新对象替换fn原型时,new出来的新对象不会自动获得constructor属性。所以,不能说因为f.constructor===fn属性,就认为fn构造了对象f。

  实际上,new出来的对象f并没有.constructor属性,它会委托原型去查找该属性,默认的原型(fn.prototype)有construtor属性并且指向fn,所以f.constructor(实际上调用的是fn.prototype.constructor)会指向fn。但是如果替换了fn.prototype,新的原型对象并不会默认有.construtor,于是委托会一直提交到Object.prototype,恰好Object.prototype.constructor===Object,结果也在上面代码中展示出来了。

  可以手动给新原型添加constructor属性:

    function fn2() {};fn2.prototype = {};fn2.prototype.constructor = fn2; //修正原型链var f = new fn2();console.log(f.constructor === fn2); //trueconsole.log(f.constructor === Object); //false

  看,修复了!(实际上应该用Object.defineProperty来定义constructor,因为该属性应该是不可枚举的)

  所以说,constructor并不是一个不可变属性,它只是默认不可枚举,但是值可以被任意修改。

原型继承

  常见误用形式和正确使用方式:

    function fn1() {};function fn2() {};//不可以 只是复制引用//fn1.prototype = fn2.prototype;//可以实现 但是会执行fn2函数 可能出现额外问题//fn1.prototype=new fn2;//ES6前 需要抛弃fn1默认的prototype 可能还要修正constructor属性fn1.prototype = Object.create(fn2.prototype);//ES6语法 直接修正默认prototypeObject.setPrototypeOf(fn1.prototype, fn2.prototype);

  

  如何找出任意对象的原型链呢?有一个方法是instanceof。

    function fn() {}var f = new fn;console.log(f instanceof fn); //true

  instanceof操作符左边是一个对象,右边是一个函数。该操作解决的问题是:在f的原型链上,是否有fn.prototype对象?(通过bind强绑生成的函数没有prototype属性)

  如果要直接判断两个对象是否存在原型关系,可以用以下几个方法:

    function fn() {}var f = new fn;//是否是原型关系console.log(fn.prototype.isPrototypeOf(f)); //true//展示原型console.log(Object.getPrototypeOf(f)); //Object{}//浏览器私有实现console.log(f.__proto__); //Object{}

  绝大多数浏览器支持__proto__方法来访问[[prototype]]属性。(__开头的属性表明这不是ECMA标准,还有很多其他的属性也以__开头)

  现在ES6可以用Object.getPrototypeOf()与Object.setPropertyOf()来获取和设置原型,相当于原生支持了__proto__。

  

  Object.create()会创建一个对象,并关联到参数对象中,避免了new操作符与生成对应的constructor,prototype。

  如果旧浏览器不支持,可以用下面的代码模拟:

    if (!Object.create) {Object.create = function(o) {function f() {};f.prototype = o;return new f();}}

  关于new操作符和原型,如果下面的代码可以理解,那就没问题了~

    function fn(a) {this.a = a;}fn.prototype = {};Object.defineProperty(fn.prototype, 'a', {value: 1,configurable: true,enumerable: true,writable: false});//严格模式new会报错var f = new fn(3);console.log(f); //无效!console.log(f.a); //1

  完结撒花!

转载于:https://www.cnblogs.com/QH-Jimmy/p/6477143.html

读书笔记-你不知道的JS上-混入与原型相关推荐

  1. 读书笔记-你不知道的JS上-词法作用域

    JS引擎 编译与执行 Javascript引擎会在词法分析和代码生成阶段对运行性能进行优化,包含对冗余元素进行优化(例如对语句在不影响结果的情况下进行重新组合). 对于Javascript来说,大部分 ...

  2. 读书笔记-你不知道的js(上卷)

    你不知道的js 该书不是全面的讲解,这本书可以作为扫过基础知识后的提升和补充. 作者站在js原生语言的角度(而不是站在js营销的角度,营销使得js扭曲本身的含义去迎合其他语言的理解和使用习惯)去从新定 ...

  3. 读书笔记-你不知道的JavaScript(上)

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  4. ES6读书笔记--对js对象爱的深沉

    1.尾调用优化 允许某些函数的调用被优化,以保持更小的调用栈.使用更少的内存,并防止堆 栈溢出.当能进行安全优化时,它会由引擎自动应用.不过你可以考虑重写递归函数,以便 能够利用这种优化 // 尾调用 ...

  5. 读书笔记:线上性能问题初步排查方法

    线上性能问题初步排查方法  首发于并发网,作者:方腾飞 引言 有时候有很多问题只有在线上或者预发环境才能发现,而线上又不能Debug,所以线上问题定位就只能看日志,系统状态和Dump线程,本文只是简单 ...

  6. 【读书笔记】MSDN 上关于加密解密的一个例子

    MSDN上的一个不错的例子: 那从内存清除密码的句子有个问题. 需要再看看这个问题到底是怎么回事,怎么解决 cannot convert from Sytem.InPtr to ref string ...

  7. 《CLR via C#》读书笔记 之 泛型

    第十二章 泛型 2014-06-15 初始泛型 12.3 泛型基础结构 12.3.1 开放类型与封闭类型 12.3.2 泛型类型和继承 12.3.3 泛型类型同一性 12.3.4 代码爆炸 12.6 ...

  8. 《构建之法》读书笔记

    看<构建之法>这本书的目的源于我在软件开发中遇到的问题: (1)怎样在别人的代码基础上进行修改,对其它代码的影响最小 (2)对于修改几行代码,如何进行快速准确的测试--Review &am ...

  9. 《勋伯格和声学》读书笔记(八):转调

    前言 本文包含<勋伯格和声学>第六章--转调的相关读书笔记.如果说上一篇文章中所讨论的终止式的目的是明确一个调性,将有可能与相邻调式产生混淆的其他可能调式排除在外,那么转调的过程就需要首先 ...

最新文章

  1. filter与servlet对照
  2. 【DB2学习文档之七】SQL for DB2
  3. 漫步最优化六——数学规划
  4. 逻辑运算和作用域的问题
  5. 剪切粘贴时总是上次的内容_关于复制粘贴,还有一个鲜为人知的技巧!
  6. 为什么c语言运行了是cmd,为什么C语言的程式码执行都在命令提示符进行?而且学习的基本都是数学问题,跟开发软体有什么关系?...
  7. java窗口三栏布局_移动端的flex三栏布局的相关知识介绍(代码示例)
  8. 非平衡电桥电阻计算_直流双臂电桥使用方法,统统告诉你
  9. 网络安全专业名词解释
  10. CC2530天线发射功率与接收灵敏度——玩转ZigBee的高端操作(Zstack框架)
  11. php设置pdf下载加密文件,怎么解除pdf加密 被加密的pdf文件
  12. HTML5-CSS3-JavaScript(1)
  13. 可道云个人网盘-Docker安装
  14. 一种很神奇但是也很有意思的分组方式
  15. 极智开发 | ubuntu 安装有线网卡驱动
  16. 汇兑损益中间科目,系统情况
  17. 分享一个不知道从哪里下载的电子设计者的经验
  18. Graphite的安装与部署
  19. matlab 可视化界面,Matlab 的可视化界面设计(上)
  20. Cookie基础使用

热门文章

  1. 二次优化大招(由泰勒公式推出最值条件)
  2. Halcon学习笔记——机器视觉应用工程开发思路及相机标定
  3. 【黑金原创教程】【TimeQuest】【第二章】TimeQuest模型角色,网表概念,时序报告...
  4. DB2 9 底子(730 考试)认证指南,第 3 局部: 拜访 DB2 数据(3)
  5. 刚刚出炉的Asp.net网站部署视频教程
  6. docker 查看日志_8个优秀Docker容器监控工具,收藏了
  7. 反向输出dna序列_蛋白质序列反向(逆向)翻译成DNA序列-在线工具
  8. mysql or优化_MySQL 语句优化
  9. 深度linux 网络配置文件,solver及其配置 - Caffe 深度学习入门教程_Linux教程_Linux公社-Linux系统门户网站...
  10. AUTOSAR从入门到精通100讲(七十九)-AUTOSAR基础篇之DTC