JS中关于构造函数、原型链、prototype、constructor、instanceof、__proto__属性

在Javascript不存在类(Class)的概念,javascript中不是基于类的,而是通过构造函数(constructor)和原型链(prototype chains)实现的。但是在ES6中引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让原型对象的写法更加清晰、更像面向对象编程的语法而已。

 

1.构造函数的简单介绍

  构造函数就是提供了一个生成对象的模板并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。总的来说,构造函数就是对象的模板,对象就是构造函数的实例。

  构造函数的特点有:

    a:构造函数的函数名首字母必须大写。

    b:内部使用this对象,来指向将要生成的对象实例。

    c:使用new操作符来调用构造函数,并返回对象实例。

function Person(){this.name = 'keith';
} 
var boy = new Person();
console.log(boy.name); //'keith'

2.构造函数的缺点

所有的对象实例都可以继承构造函数中的属性和方法。但是,同一个对象实例之间,无法共享属性。

function Person(name,height){this.name=name;this.height=height;this.hobby=function(){return 'watching movies';}
} 
var boy=new Person('keith',180);
var girl=new Person('rascal',153); 
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //false

上面代码中,一个构造函数Person生成了两个对象实例boy和girl,并且有两个属性和一个方法。但是,它们的hobby方法是不一样的。也就是说,每次使用new来调用构造函数生成一个对象实例的时候,都会创建一个hobby方法。这既没有必要,又浪费资源,因为所有hobby方法都是同样的行为,完全可以被两个对象实例共享。

所以,构造函数的缺点就是:同一个构造函数的对象实例之间无法共享属性或方法。

 

3.prototype属性

为了解决构造函数的对象实例之间无法共享属性的缺点,JS 提供了prototype属性。

函数有一个特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。通过prototype定义的属性及方法能被所有对象实例所共享,这就是prototype的意义。

通过构造函数生成对象实例时,会将对象实例的原型指向构造函数的prototype属性。每一个构造函数都有一个prototype属性,这个属性就是对象实例的原型对象。

function Person(name,height){this.name=name;this.height=height;
} 
Person.prototype.hobby=function(){     //这样声明构造函数的方法可以实现对象实例共享方法return 'watching movies';
}
var boy=new Person('keith',180);
var girl=new Person('rascal',153); 
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //true

上面代码中,如果将hobby方法放在原型对象上,那么两个实例对象都共享着同一个方法。对于构造函数来说,prototype是作为构造函数的属性;对于对象实例来说,prototype是对象实例的原型对象。所以prototype即是属性,又是对象。

原型对象的属性不是对象实例的属性。对象实例的属性是继承自构造函数定义的属性,因为构造函数内部有一个this关键字来指向将要生成的对象实例。对象实例的属性,其实就是构造函数内部定义的属性。只要修改原型对象上的属性和方法,变动就会立刻体现在所有对象实例上。

Person.prototype.hobby=function(){return 'swimming';
}
console.log(boy.hobby===girl.hobby); //true
console.log(boy.hobby()); //'swimming'
console.log(girl.hobby()); //'swimming'

上面代码中,当修改了原型对象的hobby方法之后,两个对象实例都发生了变化。这是因为对象实例其实是没有hobby方法,都是读取原型对象的hobby方法。也就是说,当某个对象实例没有该属性和方法时,就会到原型对象上去查找。如果实例对象自身有某个属性或方法,就不会去原型对象上查找。

boy.hobby=function(){return 'play basketball';
}
console.log(boy.hobby()); //'play basketball'
console.log(girl.hobby()); //'swimming'

上面代码中,boy对象实例的hobby方法修改时,就不会在继承原型对象上的hobby方法了。不过girl仍然会继承原型对象的方法。

  总结如下:

  a:原型对象的作用,就是定义所有对象实例所共享的属性和方法。

  b:prototype,对于构造函数来说,它是一个属性;对于对象实例来说,它是一个原型对象。

 

4.原型链(prototype chains)

对象的属性和方法,有可能是定义在自身,也有可能是定义在它的原型对象。由于原型对象本身也是对象,它也有自己的原型,所以形成了一条原型链(prototype chain)。比如,b对象是a对象的原型,c对象是b对象的原型,以此类推。所有一切的对象的原型顶端,都是Object.prototype,即Object构造函数的prototype属性指向的那个对象。

当然,Object.prototype对象也有自己的原型对象,那就是没有任何属性和方法的null对象,而null对象没有自己的原型。

console.log(Object.getPrototypeOf(Object.prototype)); //null
console.log(Person.prototype.isPrototypeOf(boy)) //true

原型链(prototype chain)的特点有:

  a:读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。

  b:如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。

  c:一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。

var arr=[1,2,3]; 
console.log(arr.length); //3
console.log(arr.valueOf()) //[1,2,3]
console.log(arr.join('|')) //1|2|3

上面代码中,定了一个数组arr,数组里面有三个元素。我们并没有给数组添加任何属性和方法,可是却在调用length,join(),valueOf()时,却不会报错。

length属性是继承自Array.prototype的,属于原型对象上的一个属性。join方法也是继承自Array.prototype的,属于原型对象上的一个方法。这两个方法是所有数组所共享的。当实例对象上没有这个length属性时,就会去原型对象查找。valueOf方法是继承自Object.prototype的。首先,arr数组是没有valueOf方法的,所以就到原型对象Array.prototype查找。然后,发现Array.prototype对象上没有valueOf方法。最后,再到它的原型对象Object.prototype查找。

来看看Array.prototype对象和Object.prototype对象分别有什么属性和方法。

console.log(Object.getOwnPropertyNames(Array.prototype))
//["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf", "forEach", "map", "filter", "reduce", "reduceRight", "some", "every", "find", "findIndex", "copyWithin", "fill", "entries", "keys", "values", "includes", "constructor", "$set", "$remove"]
 console.log(Object.getOwnPropertyNames(Object.prototype))// ["toSource", "toString", "toLocaleString", "valueOf", "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__proto__", "constructor"]

 

5.constructor属性

对象实例的constructor属性返回对象实例的构造函数。

function A(){};
var a = new A(); 
console.log(a.constructor); //A

constructor 属性实际上是原型对象的属性,这个属性包含了一个指针,指回原构造函数,它被所有实例对象继承。

function A(){};
var a = new A();
console.log(A.prototype.constructor === A) //true  通过原型对象访问constructor属性返回的是原型对象所处的构造函数
console.log(a.constructor === A.prototype.constructor);//true

 

console.log(A.hasOwnProperty('prototype')); //true
console.log(A.prototype.hasOwnProperty('constructor')); //true

5.1:constructor属性的作用

  a:判断对象实例的构造函数

function A(){};
var a = new A(); 
console.log(a.constructor === A)    //true
console.log(a.constructor === Array) //false

  b:从实例新建另一个实例

function A() {};
var a = new A();
var b = new a.constructor();  //从a.constructor间接调用构造函数。
console.log(b instanceof A); //true

 

6.instanceof运算符

instanceof 判断对象是否为某个构造函数的实例。

function A() {};
var a = new A();
console.log(a instanceof A); //true
console.log(a instanceof Object); //true   对整个原型链上的对象都有效

 

注意,instanceof对象只能用于复杂数据类型(数组,对象等),不能用于简单数据类型(布尔值,数字,字符串等)。而且 null 和 undefined 都不是对象,所以instanceof 总是返回false。

console.log([1] instanceof Array); //true
console.log({} instanceof Object); //true
console.log(true instanceof Boolean); //false
console.log('aaa' instanceof String); //false

console.log(null instanceof Object); //false 
console.log(undefined instanceof Object); //false


利用instanceof运算符,还可以巧妙地解决,调用构造函数时,忘了加new命令的问题。

function Keith(name,height) {if (! this instanceof Keith) {return new Keith(name,height);
}
this.name = name;
this.height = height;
}

 

7、__proto__属性(注意两边都是两个_符号)

属性 __proto__ 返回对象实例的原型对象,通过该属性可以访问原型对象的所有方法。

var Person = function(name){this.name = name;
}
var a = new Person('jack');
console.log(a.__proto__  === Person.prototype);    //true  同理,Person也有原型对象,通过Person的 __proto__ 属性也可以访问到它的原型对象,以此类推,可以实现原型链的向上追溯。

可以通过 __proto__ 属性继承其他对象的属性,但非常不建议这么做,对性能影响非常大。详情查看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

var Person = function (name) {this.name = name;
}
var a = new Person('jack');
console.log(a.name);     //jack
var b = {age: 10
}
a.__proto__ = b;
console.log(a.name,a.age);   //jack 10

相对于通过 __proto__ 属性继承其他对象的属性而言,Object.create() 方法是一个更加值得推荐的方法。该方法接收一个对象作为参数,返回一个以该对象为原型对象的新对象,即继承了作为参数的对象的属性及方法。

let b = {age: 10
}
let a = Object.create(b);
console.log(a.age);     //10

8、Function.prototype和Object.prototype

Function 和 Object 其实就是一个构造函数。

function Person(a,b){this.a = a;this.b = b;
}
let man = new Person('a','b');
console.log(Person.constructor);    //ƒ Function() { [native code] }
console.log(Person.constructor.constructor);    //ƒ Function() { [native code] }
console.log(Function == Person.constructor);    //true
console.log(Function.prototype == Person.__proto__);     //true
let obj = {}
console.log(obj.constructor);    //ƒ Object() { [native code] }
console.log(Object == obj.constructor);    //true
console.log(Object.prototype == obj.__proto__);    //true

面试题:是否所有的对象都继承 Object

不是,js中不是所有对象都继承Object,也有特例,null 和 undefined 不是继承自 Object。

 

转载于:https://www.cnblogs.com/wenxuehai/p/10178865.html

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

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

相关文章

asp 下载函数

N久没搞ASP啦,今天一个网友问到这个问题.就在网上找了下. 也不知道这个有没有错误. 下载的基本思路是这个样子的. 代码如下: <%Const USE_STREAM 0 0.不用流(Adodb.Stream)下载 1.用流下载Const ALLOW_FILE_EXT "rar,zip,chm,doc,xls,swf,mp3,gif,jpg,jpeg,png,bmp&q…

如何实现按键的短按、长按检测?

在电子产品中经常用到按键&#xff0c;尤其是经常需要MCU判断短按和长按这两种动作&#xff0c;本篇我们来专门聊下这个话题。只谈理论太无聊&#xff0c;我们还是结合着实际应用来说明。之前写过一篇关于《CH573第一篇&#xff1a;实现自拍杆蓝牙遥控器1》的文章&#xff0c;例…

ECC内存简介

ECC内存&#xff0c;即应用了能够实现错误检查和纠正技术&#xff08;ECC&#xff09;的内存条。一般多应用在服务器及图形工作站上&#xff0c;这将使整个电脑系统在工作时更趋于安全稳定。ECC是“Error Checking and Correcting”的简写&#xff0c;中文名称是“错误检查和纠…

HTTP与HTTPS的安全性讨论

转载文章&#xff1a;http://blog.csdn.net/xifeijian/article/details/54667989 1、http为什么不安全&#xff1f; http协议属于明文传输协议&#xff0c;交互过程以及数据传输都没有进行加密&#xff0c;通信双方也没有进行任何认证&#xff0c;通信过程非常容易遭遇劫持、…

使用NVM管理Node - Windows

安装 NVM NVM 下载&#xff1a;https://github.com/coreybutler/nvm-windows 安装 Node 注意&#xff1a;如果没有FQ默认源可能安装npm失败&#xff0c;请参考下一节“安装 NPM”修改镜像源地址。 查看可用版本&#xff1a; nvm ls available 安装Node&#xff1a; nvm install…

博士也会毕业吗?

怪我读书少&#xff0c;一直以来我都认为博士是一种很神奇的物种&#xff0c;他们能学会很多我们学不会的东西&#xff0c;那些奇奇怪怪的数学题&#xff0c;还有那种要背上几天的思想政治课文&#xff0c;以及要听懂那种像鸟儿一样呼唤的讲课&#xff0c;所以&#xff0c;我一…

3C趋势价值对云计算发展的驱动作用

日前&#xff0c;AMD总裁邓元鋆在参加云博会时&#xff0c;向来访的媒体透露了AMD在云计算方面的相关策略及计划&#xff1b;邓元鋆表示&#xff0c;未来AMD将以用户最为关心的Consumerization&#xff08;消费导向&#xff09;、Cloud&#xff08;云计算&#xff09;、Converg…

工作笔记

数据类型向下转换&#xff0c;精度丢失&#xff0c;可能会出现错误结果&#xff1a; public class SimpleFormat {public static void main(String[] args) {int a1111111;short b(short)a;System.out.println(b);//输出&#xff1a;-3001 } } 工具类DateFormatUitls转载于:htt…

国外出差见闻之印度

前段时间到印度的马德拉斯市出差了3个月(4月到6月)&#xff0c;今天终于有时间将自己的出差心得和见闻记录下来&#xff0c;可能以后就会忘记。下午16:00时在深圳坐车到香港机场&#xff0c;上车没多久会让填一个入境香港的单子&#xff0c;然后是过海关&#xff0c;过海关时会…

雷军的演讲以及产品发布

8月11号是小米的发布会&#xff0c;还有雷军的年度演讲。因为工作冲突我没看直播&#xff0c;晚上回来看了公众号文章和知乎上的内容讨论&#xff0c;也看了发布的新产品。雷军那个年代能够做上程序员一定是非常牛逼的人&#xff0c;而雷军是这些牛逼人的公司总经理&#xff0c…

候,一片天空

考完试了,也放假了.想知道自己能做什么更想知道自己要做什么曾经多么想好好努力好好看书现在才发现是该好好努力好好看书时间过得太快了,快得让人害怕只是睡觉,只是跑来跑去只是不明白什么时候才能真正自己靠自己只是不知道怎么样才能过得充实而有意义只是不晓得如何才能守住现…

轻松理解UML用例图时序图类图的教程

摘自https://zhuanlan.zhihu.com/p/29874146 写在前面 当你老大扔给你这样的图&#xff0c;或者你需要完成某些功能而去看文档的时候发现以下类似这样的图会不会不&#xff08;一&#xff09;知&#xff08;脸&#xff09;所&#xff08;懵&#xff09;措&#xff08;逼&#x…

[Winodows Phone 7控件详解]控件拾遗

1.Panorama控件和Pivot控件前面讲过&#xff0c;没有必要再重复一遍了。参见我的博文&#xff1a;http://www.cnblogs.com/DebugLZQ/archive/2012/03/19/2406284.html 2.DeepZoom DeepZoom 是silverlight的特色功能之一&#xff0c;也同样被加到了windows phone 7中来。这个功能…

这个工具替代Notepad++,我很满意

用过notepad的人并且还一直坚持使用它的人一定觉得它是一个非常优秀的软件&#xff0c;这个软件用来看日志&#xff0c;看代码和文档非常方便&#xff0c;而且里面还集成了一个HEX分析的工具&#xff0c;当然还有列模式等等。不吹牛啊&#xff0c;很多软件只做到了功能&#xf…

c#实现Stack

1 publicclassNodes //结点类2 {3 publicNodes Next;4 publicobjectValue;5 publicNodes(objectvalue) : this(value, null) { }6 publicNodes(objectvalue, Nodes next)7 {8 Next next;9 Value value;10 }11 }1 publicclassStack2 {3 privateintcount 0;4 privateNodes first …

Kubectl 部署有状态应用(下)

接上文 《Kubectl 部署有状态应用&#xff08;上&#xff09;》创建完StatefulSet后&#xff0c;本文继续介绍StatefulSet 扩展、更新、删除等内容。 StatefulSet 中的 Pod 验证序数索引和稳定的网络身份 StatefulSet 中的 Pod 具有唯一的序数索引和稳定的网络身份。 查看 …

收集的50家国产MCU信息

全球MCU市场多为欧美、日本和台湾地区企业占据&#xff0c;仅欧企恩智浦、美企Microchip、美企ST、欧企英飞凌就占据超80%的份额&#xff0c;TI、Nuvoton、罗姆、三星、东芝五家企业占据11.4%&#xff0c;而中国大陆企业所占份额6.5%不到。这意味着&#xff0c;留给中国本土供应…

解决文件路径的问题的总结

构建路径:    os.path 模块用来管理文件路径问题&#xff0c;它中包含了很多用以构建路径的函数&#xff0c;其中最常用的便是 join&#xff0c;abspath 以及 expanduser 函数&#xff1a; join&#xff1a;拼接路径&#xff08;不同的操作系统使用不同的分隔符拼接&#x…

进程间的数据共享

////TITLE:// 进程间的数据共享//AUTHOR:// norains//DATE:// Friday 20-June-2008//Environment:// WINCE5.0 VS2005 MIPS SDK// 同一进程的不同线程间共享数据不是难事&#xff0c;并且方式也很多&#xff0c;不胜枚举&#xff1b;而不同的进程间需要共享数据…