You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var Robot= function(id, name) {
this.id= id;
this.name = name;
this.getName = function() {
console.log(this.name)
}
}
var Mary = new Robot('85756', 'Mary')
var Bob= new Robot('85756', 'Bob')
var Robot= function(id, name) {
this.id= id;
this.name = name;
}
Robot.prototype.getName = function() {
console.log(this.name)
}
var Mary = new Robot('85756', 'Mary')
var Bob= new Robot('85756', 'Bob')
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name
}
function Children(name) {
this.name = name;
}
Children.prototype = new Father() //继承了person
Children.prototype.playGame = function() {
return "let's play Game"
}
var man = new Person('man');
var bob = new Children('bob');
bob.getName() // bob
bob.playGame() // let's play Game
起
在学习JavaScript的道路中,面向对象总是处于一种若即若离的状态。想要说清楚却也总是觉得说不清楚,回头看资料又有恍然大悟的感觉。所以今天就整理了下对象的奥秘。
首先,对象是什么?
在ECMAScript-262中,对象被定义为“无序属性的集合,其属性可以包含基本值,对象或者函数”。
所以我们可以把ECMAScript的对象想象成散列表,无非就是一组名值对,这其中的值可以是数据也可以是函数。
话不多说,我们用例子来了解对象。在控制台里输入:
对没错,你已经创建了一个对象了。是不是还有点小激动,但是光有个对象还不行呀,还得有属性才行,通过这样的方式去设置它的属性。
这样我们就为People添加了三个属性和一个方法。当然这么写肯定很麻烦,我们可以用对象字面量语法来写
完成了对象的赋值,那么接下来我们就可以对他进行读取了,以及执行对象中的方法了。
新增有了,查看有了,那接下来就删和改了。
通过上面的操作就能完成对对象数据的修改和删除了。增删改查也算是都有了。那么是所有的数据都可以改,也可以删除吗?这就涉及到对象的属性了。
属性
在ECMAScript中,有两种属性:数据属性和访问器属性。
先说说数据属性,数据属性是指包含数据值的位置,可以有读取和写入值的操作。上面也说到了是不是所有的都可以读取和写入呢?这就数据属性的4个特性来起作用了。这四个属性分别是[[Configurable]]、[[Enumerable]]、[[Writabel]]和[[Value]]。为啥用[[]]给他括起来呢?这是为了表示特性是内部置,作为规范给他们御赐了宝座。毕竟特性是为了实现JavaScript引擎用的,不可以在JavaScript中直接访问他们。所以你在控制台里面是看不到他们的。既然他们位高权重,我们就来分析下他们到底有什么作用。
先看下官方的描述:
官方的描述总是让人有点半知半解,通过代码,就能很清楚的了解这特性具体用法。
通过代码,就很清楚了。具体每一值的特性的用途。不过还需要注意的是以上的代码是在非严格模式下进行的,如果在严格模式下,进行就会抛出错误。另外还有一点就是,如果你将configurable属性设置成false了,多次调用Object.defineProperty方法就会收到限制,也不能再次修改configurable的值,会抛出错误。
访问器属性
访问器属性是不包含数据值,它们包含一对getter和setter函数(不过都不是必须的)。在读取访问器属性时,会调用getter函数;在写入访问器属性时,会调用setter函数并传入新值。同时,访问器属性也有四个特性。[[Configurable]]、[[Enumerable]]、[[Get]]和[[Set]]。
[[Configurable]]和[[Enumerable]]特性与数据属性是一样的就不重复。[[Get]],[[Set]]分别是在读取和写入属性时调用的函数。默认值都是undefined。
还是通过代码来了解:
构造函数
在对对象的属性以及属性的特性都有了一定的了解,我们就可以随意的创建和使用对象了。可有时候我们希望我们自己定义的对象有一些私有的属,就可以不用每次都写复制一遍,这就涉及到了构造函数了。比如说工程在制造机器人,每个机器人都会打招呼,但是他们的编号都不一样。如果按照这样的方式肯定是很蠢的!
我们可以这么写:
原型
先看看官方对于原型的解释:JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
这么说肯定有点懵逼,试着在控制台输出一个对象。
![image](https://user-images.githubusercontent.com/21165482/37574916-1bb37d80-2b5f-11e8-9e89-7f5e1eae9db6.png)
我们就能看到对象中除了我们自己定义的属性和方法之外,还有一个
![image](https://user-images.githubusercontent.com/21165482/37575157-a397582e-2b60-11e8-936a-826545f7da69.png)
_proto_
的属性。对象就是通过_proto_
去连接它的原型的。我们可以在_proto_
属性中看到来自以Object对象的方法与属性。这样,原型对象的方法与属性就变成了共有方法与属性。例如我们查看
obj.valueOf
和Object.valueOf
是一样的。现在我们可以用新的方式去实现构造函数中实现的功能。
这样不同的写法有什么区别吗?回顾构造函数中的方式,每创建一个对象就有一个
getName
的方法被创建,由于属于不同的实例,就得不停地为这个函数而分配空间,这显然是不合理的。通过原型,我们只需在原型中添加一个getName
的方法就能解决这个问题了。肯定又会有人问为什么能通过prototype为构造函数添加方法呢?
这里很关键!
我们必须理解原型对象。无论在什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下。所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个执行prototype属性所在函数的指针。
可以通过一个例子来了解。借用 这波能反杀的博客 (如侵必删!画图实在是麻烦!!!)
通过图表我们就能一目了然了。
![image](https://user-images.githubusercontent.com/21165482/37577385-d5290db8-2b6c-11e8-9d4c-be5ebfceea12.png)
我们再来看下,通过构造函数生成的实例对象。
![image](https://user-images.githubusercontent.com/21165482/37579666-7d33796e-2b7a-11e8-9839-6c10b866eb65.png)
可以看到实例对象的
_proto_
是指向构造函数的。这样就可以通过实例去调用构造函数的方法。如果再看构造函数的_proto_
,它是指向对象的。所以function其实是基于对象的一个实例。通过_proto_
你会发现,不管是Array、Object、Sting、Number,最终都是指向同一个东西,那就是Object。所以万物皆对象啊!!!明白了这一点,你知道对象的重要性了吧!
这样就又会涉及一个问题,就是调用先后的问题。
在我们访问实例对象的属性和方法时,会先从实例的属性和方法上寻找,如果寻找不到,就会从原型上去找,如果还是找不到会返回undefined。为啥呢?因为在对象的特性里,value的默认值就是undefined啊!
原型链
说完了原型,那接下来肯定就是原型链了。
原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
先看一个例子
这样我们再来看看bob是怎么样的。
![image](https://user-images.githubusercontent.com/21165482/37582107-344364b0-2b86-11e8-8326-eb2ad669aa31.png)
首先bob是Children的实例,name是bob。Children的原型又指向Person,同时原型方法playGame。Person又有原型方法getName。所以在调用
bob.getName()
方法时,现在bob中找该方法,没有找到则会从原型Children中找,仍没找的,继续从原型Children的原型Person中找,找到了该方法,然后调用。这时我们再通过控制台看Children创建的prototype属性是指向什么?
![image](https://user-images.githubusercontent.com/21165482/37582941-1646cde0-2b8a-11e8-8995-35e974959fc3.png)
毫无疑问 Children的prototype属性是指向Person
通过原型对象等于另一个类型的实例,另一个原型又是另一个类型的实例。这样一层一层的递进,就形成了原型链。
从对象创建、属性、特性,然后再是构造函数、原型和原型链。有点啰嗦,但是总算是基本上梳理了下对象的基本知识。写文章还查了下之前的书,收货还是蛮多的,不知道你们对于对象的理解是不是更加清晰了。
The text was updated successfully, but these errors were encountered: