转自:http://www.jianshu.com/p/a81692ad5b5d

typeof obj 和 obj instanceof Type

在JavaScript中,我们经常用typeof obj和obj instanceof Type来识别类型,那么两者的区别在哪?先来看两段代码

<!--typeof obj的方式判断-->

<script>

   var str = "toby";

   console.log(typeof str);// string

 

   var num = 1;

   console.log(typeof num);// number

 

   var str2 = new String("toby");

   console.log(typeof str2);// object

 

   var num2 = new Number(1);

   console.log(typeof num2);// object

</script>

<!--obj1 instanceof obj2的方式判断-->

<script>

   var str = "toby";

   console.log(str instanceof String); // false

 

   var num = 1;

   console.log(num instanceof Number); // false

 

   var str2 = new String("toby");

   console.log(str2 instanceof String); // true

 

   var num2 = new Number(1);

   console.log(num2 instanceof Number); // true

</script>

这次就不卖关子,直接把输出结果和结论告诉大家,从这两段代码我们就能得出结论

  • typeof obj: 返回obj对象的类型的全小写的字符串,只针对基本类型有效,如果作用在引用类型上,都返回object字符串,无法判断变量的真实类型

  • obj instanceof Type : 判断obj是否属于Type类型,返回boolean,只能作用在引用类型上,如果作用在基本类型上,都是返回false的结果.

但是知其然必须知其所以然,我们接下来进一步探索

JavaScript中的原型链

JavaScript中的类 
JavaScript中是没有类的概念,创建对象是用构造函数来完成,或者直接用json格式{}来写对象

<script>

   //创建一个Person类,首字母要大写,这个function也是这个类的构造方法

   function Person(name, age) {

       this.name = name;

       this.age = age;

   }

 

   var p = new Person("toby", 24);

   console.log(p);

</script>

这个new的过程到底发生了什么,我们看一下文档的描述

When the code new Foo(…) is executed, the following things happen:

  1. A new object is created, inheriting from Foo.prototype.

  2. The constructor function Foo is called with the specified arguments, and with this bound to the newly created object. new Foo is equivalent to new Foo(), i.e. if no argument list is specified, Foo is called without arguments.

  3. The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn’t explicitly return an object, the object created in step 1 is used instead. (Normally constructors don’t return a value, but they can choose to do so if they want to override the normal object creation process.)

我们用代码描述一下new Person(“toby”, 24);

//1.方法new的瞬间,得到一个空对象{},它继承自Person.prototype

var p = {};

p.__proto__ = Person.prototype;

 

//2.方法的this,指向空对象

 

//3.运行构造方法

{}.name = toby;

{}.age = age;

 

//4.返回该对象

Person.call(p);

JavaScript对象中的内部结构

1.__proto__: 这个属性是JS对象上的隐藏属性,这个属性指向的是该对象对应类型的prototype对象

var p = new Person();

console.log(p.__proto__ == Person.prototype);//true

2.js中对象分为两部分,

一部分是原生部分,原生部分是在构造函数中定义的,或者是直接通过对象.属性=value赋值的; 
一部分是扩展部分,扩展部分的内容是通过类.prototype=value赋值的; 
JavaScript中的两种继承方式

普通继承

<script>

   function Person(name, age) {

       this.name = name;

       this.age = age;

   }

 

   Person.prototype.sayName = function () {

       console.log(this.name);

   };

 

   //创建一个Student类

   function Student(name, age, sn) {

       //调用父类的构造方法帮我们初始化属性

       Person.apply(this, [name, age]);

       this.sn = sn;

   }

 

   //复制Person原型中的所有方法

   for (var p in Person.prototype) {

       Student.prototype[p] = Person.prototype[p];

   }

 

   var s = new Student("toby", 24, 1);

   s.sayName();

 

   console.log(s instanceof Student);

   console.log(s instanceof Object);

   console.log(s instanceof Person);

</script>

又到了开心做题的时间了,根据开头的结论,请问这里会输出什么?可能我们认为输出为

  • toby

  • true

  • true

  • true

但是输出后发现,结果却为

  • toby

  • true

  • true

  • false

如果倒数第二个为false可能你还比较好理解,最后一个为false似乎和我们观念中的继承有太大冲突,那么,我们来看原理

instanceof的原理

obj instanceof Type的原理:沿着对象的原型链,判断一条原型链中是否有一个原型和Type的类型一样,如果找到,返回true,如果一直沿着原型链找下去都找不到,则返回false,那么我们就把这个当成一个公式,套上公式走一波

console.log(s.__proto__ == Student.prototype);//true

console.log(s.__proto__ == Object.prototype);//false

console.log(s.__proto__.__proto__ == Object.prototype);//true

console.log(s.__proto__ == Person.prototype);//false

console.log(s.__proto__.__proto__ == Person.prototype);//false

所以现在明白为什么前面两个输出为true,最后一个输出为false了吧.

但是如果就想让s instanceof Person结果为true,达到子类对象能被识别成父类类型实例的需求,那么怎么办呢?既然原理我们都知道了,那解决起来是很简单的

原型继承

<script>

   function Person(name, age) {

       this.name = name;

       this.age = age;

   }

 

   Person.prototype.sayName = function () {

       console.log(this.name);

   };

 

   function Student(name, age, sn) {

       Person.apply(this, [name, age]);

       this.sn = sn;

   }

 

   for (var p in Person.prototype) {

       Student.prototype[p] = Person.prototype[p];

   }

 

   //在Student原型中添加Person原型

   Student.prototype = Object.create(Person.prototype);

 

   var s = new Student("toby", 24, 1);

 

   console.log(s);

   console.log(s instanceof Student);

   console.log(s instanceof Object);

   console.log(s instanceof Person);

</script>

那最后输出的结果究竟是不是我们想要的呢?我们分析照着公式分析一波

console.log(s.__proto__ == Student.prototype);//true

console.log(s.__proto__ == Object.prototype);//false

console.log(s.__proto__.__proto__ == Object.prototype);//false

console.log(s.__proto__.__proto__.__proto__ == Object.prototype);//true

console.log(s.__proto__ == Person.prototype);//false

console.log(s.__proto__.__proto__ == Person.prototype);//true

从这里我们就知道,输出的结果为

  • true

  • true

  • true

原型链的分析

那么,我们用两个图来描述一下这两种继承中的原型链

图解JavaScript中的原型链的更多相关文章

  1. 一张图搞懂 Javascript 中的原型链、prototype、__proto__的关系 转载加自己的总结

    1. JavaScript内置对象 所谓的内置对象 指的是:JavaScript本身就自己有的对象 可以直接拿来就用.例如Array String 等等.JavaScript一共有12内置对象    ...

  2. JavaScript中的原型链原理

    工作中经常解除到prototype的概念,一开始错误的认为prototype是对象的原型链,其实prototype只能算是JavaScript开放出来的原型链接口,真正的原型链概念应该是__proto ...

  3. JavaScript中的原型链和继承

    理解原型链 在 JavaScript 的世界中,函数是一等公民. 上面这句话在很多地方都看到过.用我自己的话来理解就是:函数既当爹又当妈."当爹"是因为我们用函数去处理各种&quo ...

  4. Javascript中的原型链、prototype、__proto__的关系

    javascript  2016-10-06  1120  9 上图是本宝宝用Illustrator制作的可视化信息图,希望能帮你理清Javascript对象与__proto__.prototype和 ...

  5. Javascript中的原型链,__proto__和prototype等问题总结

    1.js中除了原始数据类型 都是对象. 包括函数也是对象,可能类似于C++函数对象把 应该是通过解释器 进行()操作符重载或其他操作, 用的时候把它当函数用就行 但是实际上本质是一个对象 原型也是一个 ...

  6. JavaScript中的原型、原型链、原型模式

    今天,咱来聊聊JavaScript中的原型跟原型链 原型跟原型模式 这一块的知识,主要是设计模式方面的. 首先,我们知道JavaScript是面向对象的.既然是面向对象,那它自然也有相应的类跟对象等概 ...

  7. 前端知识体系:JavaScript基础-原型和原型链-理解原型设计模式以及 JavaScript中的原型规则

    理解原型设计模式以及 JavaScript中的原型规则(原文地址) 1.原型对象:我们创建的每一个函数(JavaScript中函数也是一个对象)都有一个原型属性 prototype,原型属性实质上是一 ...

  8. 【转】JavaScript中的原型和继承

    请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...

  9. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

随机推荐

  1. APUE第八章-进程控制

    一.进程标识 二.函数fork 1.写时复制,copy-on-write 2.文件共享,父进程等待子进程完成,子进程结束后,它对任一共享描述符的读写操作的文件偏移量已做相应的更新,同时操作时,可以考虑 ...

  2. 洛谷P2679 子串

    放题解 题目传送门 放代码

  3. 压缩感知(CS)

    总结一下最近看的压缩感知(Compressed Sensiong)的内容. 它是在采样过程中完成了数据压缩的过程. 一. 将模拟信号转换为计算机能够处理的数字信号,必然要经过采样的过程.问题在于,应该 ...

  4. codeforces1097D Makoto and a Blackboard 数学+期望dp

    题目传送门 题目大意: 给出一个n和k,每次操作可以把n等概率的变成自己的某一个因数,(6可以变成1,2,3,6,并且概率相等),问经过k次操作后,期望是多少? 思路:数学和期望dp  好题好题!! ...

  5. nodejs fs读取静态json文件

    let fs = require('fs'),stream = fs.createReadStream('./obd.json'),data = ""; stream.on('da ...

  6. 地牢逃脱----DFS搜索最优解

    https://www.nowcoder.com/practice/0385945b7d834a99bc0010e67f892e38?tpId=85&tqId=29831&tPage= ...

  7. linux系统编程之(一) 信号量

    信号量 一.什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明 它被占用,测 ...

  8. 认识HTML中表格、列表标签以及表单控件

    前端之HTML,CSS(二) HTML标签 列表标签 无序列表:闭标签,由<ul><li></li>...</ul>组合而成,效果成纵向列表.格式:&l ...

  9. 剑指offer——面试题14:剪绳子

    // 面试题14:剪绳子 // 题目:给你一根长度为n绳子,请把绳子剪成m段(m.n都是整数,n>1并且m≥1). // 每段的绳子的长度记为k[0].k[1].…….k[m].k[0]*k[1 ...

  10. TT 安装之 Windwos

    WINDOWS在 控制面板-〉管理工具-〉本地安全策略-〉本地策略-〉用户权限分配-〉锁定内存页-〉添加用户或组-〉高级查找 然后确定 然后安装 (WINDOWS在 控制面板-〉管理工具-〉ODBC工 ...