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

继承

 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JUnit和Hamcrest:在assertEquals上进行改进

在我的博客文章中&#xff0c;Java越来越接受静态导入吗&#xff1f; &#xff0c;我讨论了在Java中越来越多地使用静态导入来使代码在某些情况下更流畅。 Java 单元测试特别受静态导入的影响&#xff0c;在此博客文章中&#xff0c;我提供了一个简单的示例&#xff0c;说明如何…

mysql delete temporary denied_这些错误是什么意思?djang中的mysql

我试着运行一个程序&#xff0c;我被给予了一个例子&#xff0c;它就像一个购物网站&#xff0c;使用MySQL数据库而不是Django提供的原始数据库&#xff01;我只是想看看有没有人理解这些错误的含义&#xff1f;任何信息都将不胜感激&#xff01;我本可以提供网页的代码&#x…

C语言 · 芯片测试

基础练习 芯片测试 时间限制&#xff1a;1.0s 内存限制&#xff1a;512.0MB问题描述有n&#xff08;2≤n≤20&#xff09;块芯片&#xff0c;有好有坏&#xff0c;已知好芯片比坏芯片多。每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时&#xff0c;能正确给出被测试…

Animation用法

测试代码及说明&#xff1a; <!DOCTYPE html> <html lang"en-US"> <head><meta charset"UTF-8"><title>Simple CSS3 Animation</title><style type"text/css">#demo {position: absolute;left: 30%;t…

mysql dese_MySQL 5.6-类似于DENSE_RANK的功能,无需订购

小编典典对于 MySQL版本<8.0(OP的版本是5.6)&#xff1a;问题陈述看起来需要DENSE_RANK功能groupVarian; 但是事实并非如此。正如 GordonLinoff解释的那样 &#xff1a;您似乎希望按它们在数据中出现的顺序来枚举它们。假设您的表名是t(请为您的代码相应地更改表名和字段名)…

Spring和JSF集成:动态导航

通常&#xff0c;您的JSF应用程序将需要超越基本的静态导航并开始做出动态导航决策。 例如&#xff0c;您可能想根据用户的年龄重定向他们。 大多数JSF教程建议通过将命令的action属性绑定到支持bean来实现动态导航&#xff1a; <h:commandButton action"#{bean.action…

通过富文本改变UITextFieldPlaceholder颜色

1、通过属性 a、 //文字属性(一般) NSMutableDictionary *attrs [NSMutableDictionary dictionary]; attrs[NSForegroundColorAttributeName] [UIColor blueColor]; NSAttributedString *placeholderStr [[NSAttributedString alloc] initWithString:"手机号" a…

阻塞/非阻塞/同步/异步方法和多线程的关系?没有任何关系,俩不挨着

1.阻塞非阻塞异步同步是针对方法说的&#xff0c;是评判一个方法运行状态的。和多线程完全两个级别。 2.阻塞非阻塞异步同步是针对方法说的&#xff0c;是评判一个方法运行状态的。和多线程完全两个级别。 3.阻塞非阻塞异步同步是针对方法说的&#xff0c;是评判一个方法运行状…

mysql备份 where_MySQL备份与还原

1.mysqldumpmysqlbinlog介绍mysqldump备份结合binlog日志恢复。MySQL备份一般采取全库备份加日志备份的方式&#xff0c;例如每天执行一次全备份&#xff0c;每小时执行一次二进制日志备份&#xff0c;这样在MySQL故障后可以使用全备份和日志备份将数据恢复到最后一个二进制日志…

JMeter:负载测试关系数据库

Apache JMeter是完全使用Java编写的性能测试工具。 可以在请求/响应模型上运行的任何应用程序都可以使用JMeter进行负载测试。 关系数据库也不例外&#xff1a;接收sql查询&#xff0c;执行它们并返回执行结果。 我将向您展示使用JMeter的图形用户界面设置测试方案有多么容易。…

new: Set up a window

Nehe的教程确实太老了&#xff0c;不过我认为它也能够让我了解OpenGL3.2以前的管线渲染模式&#xff0c;即使它在现在已经不常见了。因为想要了解&#xff0c;所以我还是会看完Nehe的教程。 现在这是一个新的教程 - JoeyDeVries的教程&#xff0c;可以说是网上最好的OpenGL教程…

Python全栈开发:socket

Socket socket通常也称作"套接字"&#xff0c;用于描述IP地址和端口&#xff0c;是一个通信链的句柄&#xff0c;应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 socket起源于Unix&#xff0c;而Unix/Linux基本哲学之一就是“一切皆文件”&…

oracle sga pga mysql_修改Oracle数据库SGA和PGA大小

SGA的大小&#xff1a;一般物理内存20%用作操作系统保留&#xff0c;其他80%用于数据库。SGA普通数据库可以分配40%-60%之间&#xff0c;PGA可以分配20%-40%之间。1、以dba身份登录并查看SGA信息&#xff1a;SQL>show parameter sga&#xff1b;查看PGA信息&#xff1a;SQL&…

NetBeans 7.1:创建自定义提示

我已经在帖子中介绍了一些我最喜欢的NetBeans提示 &#xff0c;这些信息是用于使Java代码现代化的七个NetBeans提示和七个不可或缺的NetBeans Java提示 。 这两个帖子中涉及的十四个提示仅占NetBeans支持的“即开即用”提示总数的一小部分。 但是&#xff0c;由于NetBeans 7.1使…

今年暑假不AC

Problem Description “今年暑假不AC&#xff1f;”“是的。”“那你干什么呢&#xff1f;”“看世界杯呀&#xff0c;笨蛋&#xff01;”“#$%^&*%...”确实如此&#xff0c;世界杯来了&#xff0c;球迷的节日也来了&#xff0c;估计很多ACMer也会抛开电脑&#xff0c;奔向…

qregexp括号匹配_转:Qt的正则表达式和QRegExp

考虑一下我们经常遇到的问题&#xff0c;比如gemfield想从青岛之光读书(www.civilnet.cn/book)中找一个关键的电话号码&#xff0c;通常第一步就是将书中所有的电话号码查找出来放在手边。那么怎么拟定查询条件呢&#xff1f;电话的格式有如下几种&#xff1a;01088888888010 8…

具有Tron效果的JavaFX 2 Form

这是一个具有TRON效果的简单JavaFX登录表单。 在此示例中&#xff0c;我使用CSS设置TextField和Button的样式。 这是CSS和Effect代码的片段&#xff1a; .text-field{-fx-background-color: transparent;-fx-border-color: #00CCFF;-fx-text-fill: white; }.password-field{-fx…

Spring注解Annotion详解

概述 注释配置相对于 XML 配置具有很多的优势&#xff1a; 它可以充分利用 Java 的反射机制获取类结构信息&#xff0c;这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时&#xff0c;我们就不需要指定 PO 的属性名、类型等信息&#xff0c;如果关系表字段和 PO…

CopyOnWrite容器

1.简介 1.CopyOnWrite是程序优化的策略,当共享的内容需要修改时,复制出去一份进行修改,然后将原来的引用指向修改完的 2.java并发包(java.util.concurrent)中CopyOnWriteArrayList和CopyOnWriteArraySet实现了这个并发容器 3.好处:因为写时是在复制的一份上操作,所以可以并发的…

Akka的字数统计MapReduce

在我与Akka的日常工作中&#xff0c;我最近写了一个字数映射表简化示例。 本示例实现了Map Reduce模型&#xff0c;该模型非常适合横向扩展设计方法。 流 客户端系统&#xff08;FileReadActor&#xff09;读取文本文件&#xff0c;并将每一行文本作为消息发送给ClientActor。…