学习Javascript,最难的地方是什么?
我觉得,Object
(对象)最难。因为Javascript的Object
模型很独特,和其他语言都不一样,初学者不容易掌握。
下面就是我的学习笔记,希望对大家学习这个部分有所帮助。我主要参考了以下两本书籍:
《面向对象的Javascript》(Object-Oriented JavaScript)
《Javascript高级程序设计(第二版)》(Professional JavaScript for Web Developers, 2nd Edition)
它们都是非常优秀的Javascript读物,推荐阅读。
笔记分成三部分。今天的第一部分是讨论"封装"(Encapsulation),后面的第二部分和第三部分讨论"继承"(Inheritance)。
============================
Javascript 面向对象编程(一):封装
作者:阮一峰
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class
(类)。
那么,如果我们要把"属性"(property)和"方法"(method),封装成一个对象,甚至要从原型对象生成一个实例对象,我们应该怎么做呢?
一、 生成实例对象的原始模式
假定我们把猫看成一个对象,它有"名字"和"颜色"两个属性。
var Cat = {name : '',
color : ''
}
现在,我们需要根据这个原型对象的规格(schema),生成两个实例对象。
var cat1 = {}; // 创建一个空对象
cat1.name = "大毛"; // 按照原型对象的属性赋值
cat1.color = "黄色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
好了,这就是最简单的封装了,把两个属性封装在一个对象里面。但是,这样的写法有两个缺点,一是如果多生成几个实例,写起来就非常麻烦;二是实例与原型之间,没有任何办法,可以看出有什么联系。
二、 原始模式的改进
我们可以写一个函数,解决代码重复的问题。
function Cat(name,color) {
return {
name:name,
color:color
}
}
然后生成实例对象,就等于是在调用函数:
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");
这种方法的问题依然是,cat1
和cat2
之间没有内在的联系,不能反映出它们是同一个原型对象的实例。
三、 构造函数模式
为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
所谓"构造函数",其实就是一个普通函数,但是内部使用了this
变量。对构造函数使用new
运算符,就能生成实例,并且this
变量会绑定在实例对象上。
比如,猫的原型对象现在可以这样写,
function Cat(name,color){
this.name=name;
this.color=color;
}
我们现在就可以生成实例对象了。
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色
这时cat1
和cat2
会自动含有一个constructor
属性,指向它们的构造函数。
alert(cat1.constructor == Cat); //true
alert(cat2.constructor == Cat); //true
Javascript还提供了一个instanceof
运算符,验证原型对象与实例对象之间的关系。
alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true
四、构造函数模式的问题
构造函数方法很好用,但是存在一个浪费内存的问题。
请看,我们现在为Cat
对象添加一个不变的属性type
(种类),再添加一个方法eat
(吃)。那么,原型对象Cat
就变成了下面这样:
function Cat(name,color){
this.name = name;
this.color = color;
this.type = "猫科动物";
this.eat = function(){alert("吃老鼠");};
}
还是采用同样的方法,生成实例:
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat ("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
表面上好像没什么问题,但是实际上这样做,有一个很大的弊端。那就是对于每一个实例对象,type
属性和eat()
方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。
alert(cat1.eat == cat2.eat); //false
能不能让type
属性和eat()
方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的。
五、 Prototype模式
Javascript规定,每一个构造函数都有一个prototype
属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype
对象上。
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};
然后,生成实例。
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
这时所有实例的type
属性和eat()
方法,其实都是同一个内存地址,指向prototype
对象,因此就提高了运行效率。
alert(cat1.eat == cat2.eat); //true
六、 Prototype模式的验证方法
为了配合prototype
属性,Javascript定义了一些辅助方法,帮助我们使用它。,
6.1 isPrototypeOf()
这个方法用来判断,某个proptotype
对象和某个实例之间的关系。
alert(Cat.prototype.isPrototypeOf(cat1)); //true
alert(Cat.prototype.isPrototypeOf(cat2)); //true
6.2 hasOwnProperty()
每个实例对象都有一个hasOwnProperty()
方法,用来判断某一个属性到底是本地属性,还是继承自prototype
对象的属性。
alert(cat1.hasOwnProperty("name")); // true
alert(cat1.hasOwnProperty("type")); // false
6.3 in运算符
in
运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
alert("name" in cat1); // true
alert("type" in cat1); // true
in
运算符还可以用来遍历某个对象的所有属性。
for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); }
未完,请继续阅读这个系列的第二部分《构造函数的继承》和第三部分《非构造函数的继承》。
(完)
shimu 说:
直白易懂!逐步深入~这篇对于我这种初学者很有用啊!
2010年5月17日 18:24 | # | 引用
Astro 说:
崇拜中。。阮兄知识面让我情何以堪啊。。。
2010年5月17日 18:36 | # | 引用
ciciはLuckyD 说:
不错的note,最近我在看pro Javascript Design Patterns这本书,三、四章的封装、继承这块讲的非常好
2010年5月17日 21:12 | # | 引用
fan 说:
《javascript: the good part》中Dauglas不推荐用new的这种方法构造对象,因为如果忘记加上new,“即没有编译时警告,也没有运行时警告”。他推荐的是函数化的方法,不使用prototype。
2010年5月18日 07:46 | # | 引用
某人 说:
好多年不写程序了,不过还是觉得javascript是挺复杂的。
2010年5月18日 08:44 | # | 引用
laoguo 说:
喜欢这篇。
越来越能看出,今后,这种娓娓道来的知识描述形式,将把至今为止的,逻辑严谨机械正确但却难懂的知识描述方式打入历史的垃圾箱里。
人,是有灵性的,是非线性的,是量子性的。
至今为止所谓的“线性严谨二元逻辑性的学术描述方式”,只不过是一种违反人类本质天性的东西,必将在完成其历史使命之后,退出历史舞台。
2010年5月18日 08:59 | # | 引用
Ruan YiFeng 说:
虽然这个意见是正确的。但是,Douglas提出的方法,需要自己写一个函数,在函数里再使用prototype,我觉得很不符合直觉。
2010年5月18日 09:24 | # | 引用
resun 说:
很简洁实用的文章,里面有不少重来没有看过的用法,如:alert("name" in cat1);
没想到还能用 in 这样做判断
2010年5月18日 10:18 | # | 引用
牙牙学语 说:
非常实用易懂的文章!
最近看《Object Oriented JavaScript》,看完第六章讲12种对象封装构造的方法,彻底晕菜。。看了您的文章决定继续去读完这本书,的确是本很好的JS参考书啊
2010年5月18日 11:16 | # | 引用
axu 说:
这么一段代码,ruan兄猜猜是啥结果?我觉得这是封装中最容易犯的错误
var a=function(){
//empty
}
a.prototype.var1=[1,2,3];
var b=new a();
b.var1.push(4);
var c=new a();
alert(c.var1.join(","))
2010年5月18日 11:19 | # | 引用
Ruan YiFeng 说:
所以只能把不变的属性和方法,绑在prototype对象上,而不能把可变属性绑上去。
2010年5月18日 13:31 | # | 引用
清风剑 说:
我始终觉得javascript是一门函数式编程语言,这种OO的封装应该只是一种临时的workaround
2010年5月18日 18:21 | # | 引用
richard 说:
这时所有实例的type属性和eat()方法,其实都是一个内存地址,指向prototype对象,因此就提高了运行效率。
也增大了风险,因为一个地方改变了,其他地方都变了。和他带来的好处相比,风险更大,不应该推荐。
ruan兄应该是有点“完美主义”的偏执吧
2010年5月19日 10:51 | # | 引用
多志郎 说:
会不会连载,如果连载的话,就跟着你学了!
2010年5月19日 11:51 | # | 引用
ethantsien 说:
这个“如果“有点苍白
2010年5月21日 15:51 | # | 引用
netwjx 说:
js的水很深很深 特别是用js尝试模仿oo的风格
还是喜欢使用简单的 名称空间+函数
2010年5月21日 17:20 | # | 引用
nil 说:
苍白与否暂且搁置,为了避免忘记加 new,最好的办法是类名首字母大写。
2010年5月24日 09:50 | # | 引用
lee 说:
不错!是一篇好文章!
2010年6月29日 12:17 | # | 引用
textbox 说:
这篇文章绝对要顶,学js多年,像中国唯一一个能把问题讲的这么直白透彻的。
2010年7月 2日 12:59 | # | 引用
bill chen 说:
这篇文章分析得十分仔细清楚,绝对经典啊!!!!
2010年11月11日 10:11 | # | 引用
1w 说:
这就涉及到对象的继承机制了. 更直白一点, 涉及到 JS 语言的变量赋值与引用的区分.
2011年1月12日 10:35 | # | 引用
czg 说:
var parent = function(name){
var that = {};
that.name = name;
return that;
};
var child = function(name,age){
var that = parent(name);
that.age = age;
return that;
};
函数化不难
2011年6月 1日 10:16 | # | 引用
yisheng 说:
Ruan兄, 文章易懂,不错,Mark~~~!
2011年6月 9日 11:46 | # | 引用
wells 说:
第五点应该是构造函数+原型 的混合模式吧。
2011年6月20日 09:54 | # | 引用
jaclon 说:
简单易懂,对像我一样的初学者来说很好
2011年6月21日 17:03 | # | 引用
anoymous 说:
这么入门级的文章,被这么多人“捧”,真够汗的~~
2011年6月24日 11:33 | # | 引用
michael 说:
好文章,深得深入浅出的精髓
2011年7月 1日 13:28 | # | 引用
初学者 说:
我个人认为:javascript 只是脚本语言,它和c++或java等语言所肩负的任务不同, 因此关于“继承”等功能不是重点,无需太复杂。
我不赞同依靠javascript大量创建UI界面,构建UI的基础应该是html+css。
当然javascript也可以写得很复杂和高明,那是高手们喜欢做的事。但不代表非要这样不可。
现在的电脑设备速度越来越快,内存越来越大,无需太计较,简单易懂、安全(prototype的做法易出错,风险大,使用时要很小心。)才是重点。
2011年7月10日 13:18 | # | 引用
argb 说:
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。
不明白为什么这么说,没有class就不是真正的面向对象?面向对象是一种编程思想,有没有class只是一种对这种思想的具体实现与体现,但没有class也未必不是面向对象。
ecmascript规范里如是说:
ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment.
----Ecmascript262 v5 page 1
2011年7月20日 16:28 | # | 引用
forget 说:
初学者看了您的文章受益匪浅,已经购买推荐的书籍正在学习中.感谢...
2011年7月25日 14:48 | # | 引用
Ora 说:
第5部分里的 alert(cat1.eat == cat2.eat); 是否改为===更恰当些?
2011年7月29日 15:49 | # | 引用
胡营 说:
看了几个星期的书,还不如看着几个例子,浅显易懂!
2011年8月 2日 15:44 | # | 引用
Yoya 说:
OOP的人看JS真的是很变恋,你说Cat.prototype.type = "猫科动物";这个东西看上去像模仿类的静态方法吧,但访问时又不是直接通过类而是通过类的实例cat1.type;。这让初学编程的人是学面向过程还是面向对向啊?
2011年11月29日 17:36 | # | 引用
xxx 说:
访问时通过类或是通过类的实例不能作为判断是否面向对象的依据,其实都是访问一块公共内存而已
2011年12月25日 21:35 | # | 引用
Azrael 说:
我的问题跟Yoya的一样 ,OOP的人看JS真的是很变恋,你说Cat.prototype.type = "猫科动物";这个东西看上去像模仿类的静态方法吧,但访问时又不是直接通过类而是通过类的实例cat1.type;搞不清楚到底是不是共享的了
2011年12月28日 09:48 | # | 引用
xyz 说:
循序渐进 适合学习
2012年2月14日 12:31 | # | 引用
Dada 说:
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat ("二毛","黑色");
alert(cat1.type); // 猫科动物
这里两个对象的type显然不是一个内存地址,可以写一个代码跑一下啊,我试了,不再同一内存地址,如果在同一内存地址不就成了静态变量。
2012年2月20日 16:51 | # | 引用
Dada 说:
刚才我说的也不准确,下面是摘自一个博客,我感觉挺准确的,你文章里写的有点歧义,容易让人以为prototype中所定的属性是静态方法。
话说每一个方法对象被创建时,都会自动的拥有一个叫 prototype 的属性。这个属性并无什么特别之处,它和其他的属性一样可以访问,可以赋值。不过当我们用 new 关键字来创建一个对象的时候,prototype 就起作用了:它的值(也是一个对象)所包含的所有属性,都会被复制到新创建的那个对象上去。
2012年2月20日 17:15 | # | 引用
Dada 说:
我昨天的留言,感觉太草率了,今天又读了一些,发现博主说的还是比较准确的,虽然给我造成了一定的误解,不过博主说还是对的,我上面说的那个根本不正确。。。。
2012年2月21日 14:43 | # | 引用
Zz 说:
阮大哥,你这篇刚刚写出来的时候我就看过了,当时看了半天没看懂,直到今天才看懂,我是个超级初级入门者,入门了两年啊,哈哈哈,我实在是太笨了。
谢谢你,终于看明白了,而且原来是那么的浅显易懂啊
2012年2月22日 10:06 | # | 引用
路街道 说:
阮老大,javascript现在面相对象编程是一个大趋势啊。我搜遍了国内的网上书店都没有买到将关于javascript面相对象编程的书籍。国内的专家写的什么垃圾书,在就过时了。javascript面相对象的时代到来了。封住继承是必须的了。求javascript面相对象的书啊。。网上就您的这几篇稿子经典,跪添了。
2012年2月28日 16:01 | # | 引用
shuiren 说:
所以,我是不喜欢这个风格。
特别是,这种风格带来的如果只是内存节约的话
2012年3月 7日 10:58 | # | 引用
lovejjhao 说:
文章非常好,加深理解!!!感谢作者!
2012年3月15日 11:14 | # | 引用
zhaoyou 说:
从原型拿来的东西,只是能查询,检索到,更新不会影响到原型的值。这样理解好些?
2012年5月21日 23:13 | # | 引用
那个妹子 说:
很好懂,谢谢啦!
2012年7月11日 21:42 | # | 引用
Hodor 说:
2012年7月12日 10:06 | # | 引用
赵荣娇 说:
Cat.prototype.isPrototypeOf(cat1)//true——原来构造函数的原型才是与实例的原型一致,也就是说原型一致;
Cat.constructor == cat1.constructor //false——不知道为什么构造函数与构造函数为什么不一致?
Cat == cat1.constructor //true
2012年7月17日 11:39 | # | 引用
iliveido 说:
Cat和cat1都有两个子对象:constructor和prototype
cat1.constructor就是Cat
cat1.prototype就是Cat.prototype
问题是,Cat的另一个子对象Cat.constructor是什么呢?
2012年8月11日 23:57 | # | 引用
lazy2009.iteye.com 说:
[QUOTE]
我们现在就可以生成实例对象了。
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色
这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。
alert(cat1.constructor == Cat); //true
alert(cat2.constructor == Cat); //true
[/QUOTE]
----------------------------------
cat1和cat2自身是没有constructor属性的,而是通过原型链找到Cat.prototype.constructor属性
2012年9月 6日 08:41 | # | 引用
eagle 说:
alert(cat1.eat == cat2.eat); //false
为什么这一句我测试的结果是true?
2012年9月22日 16:13 | # | 引用
xiaoxiehang 说:
阮哥 前面都看的懂了 但是最后一句不太明白
for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); }
希望你能解释一下
2012年9月25日 17:54 | # | 引用
beebe 说:
果然是你写的.....
2012年12月 3日 21:17 | # | 引用
路人甲 说:
我擦,评论好多见解是错的。。。把原型链先搞清楚就不会错了
2013年3月 5日 13:03 | # | 引用
杨易 说:
Prototype模式 还有一点没有说到,
className.Prototype.method(){
//这里不能使用构造里的私有属性
}
2013年5月14日 12:00 | # | 引用
phplaber 说:
Prototype模式虽然能减少内存使用,提高应用性能,但是会使代码变得冗长,增加维护难度。更好的做法应该是使用“继承”的方法,将相同的属性和方法封装在另外的对象中。
2013年7月 2日 19:09 | # | 引用
fn_c 说:
console.log(cat1.type == cat2.type); 和 console.log(cat1.type === cat2.type);
返回的都是 true,求解惑
2013年7月19日 11:59 | # | 引用
东方小白 说:
终于懂了prototype了
2013年7月25日 10:39 | # | 引用
雅蠛蝶 说:
alert(cat1.eat == cat2.eat); //false
alert(cat1.eat() == cat2.eat()); //true
2013年8月25日 23:35 | # | 引用
蒋雪峰 说:
真的不错的文章,经久不衰啊,这是我看过的最好的一篇讲解这个的
2013年8月30日 18:40 | # | 引用
phper08 说:
2013年9月27日 10:02 | # | 引用
ww 说:
刚才试了一下发现,prototype方式添加的属性在new 出来的对象中是可以修改的而且不影响别的对象和对象原型,貌似每个new出来的对象都存在prototype里面的属性,那用prototype方式添加的属性和直接在函数里面添加的属性有什么区别了。。。求解
2013年10月15日 15:07 | # | 引用
唐加利 说:
虽然是10年的文章,但看起来还是有很多启发。但是关于这段代码,窃以为不是属性可不可变的问题,而是,因为[1,2,3]是一个对象,所以var1属性也只是对这个对象的一个地址引用,所以任何实例对象改变这个对象时,其它对象再去访问该属性,都是通过引用找到的内容,因此拿到的都是改变后的属性值。如果var1赋值为基本类型,则不会出现这个问题。
2014年2月25日 13:00 | # | 引用
think2011 说:
回头再看的时候,发现很容易就理解的,简单明了!
2014年3月17日 11:44 | # | 引用
owen 说:
今天重新看了阮老师写的文章,感觉收获很大,每次在不同的水平下看,总有不同体会,看到一条有意思的评论,上面这个人的在实例化后c居然可以改变a中的数组,按理不应这样,求解答这是什么原理?
2014年3月19日 18:09 | # | 引用
pds 说:
之前也一直是看到 JavaScript 面向对象这块真是头大了,其实很多地方看起来很好理解,但是如果用自己的语言去组织这一部分内容,又什么都记不得了。如果一开始先开看简单浅显的文章,然后在去看这部分就很连贯了。
2014年4月 1日 14:16 | # | 引用
redspear 说:
prototype有一个注意点,如果是方法,可以共用内存,如果是一个像name这样的属性,还是会新开内存的。
2014年7月 3日 14:42 | # | 引用
塔拉 说:
简单明了,确是好文呀。
2014年7月13日 22:17 | # | 引用
biaobiaoqi 说:
赞,ruanyifeng老师果然是入门级指导的大师~
2014年7月17日 05:30 | # | 引用
jack 说:
略显简单吧
2014年8月21日 11:10 | # | 引用
游客 说:
不太理解 函数 和 函数相等 是空间相等 还是弹出的 值相等?
2014年8月27日 15:16 | # | 引用
tshk 说:
简单明白,终于知道js的对象了
2014年11月28日 22:52 | # | 引用
Justin 说:
讲到很清楚,个人看法是,属性绑定在this上面,方法绑定在prototype上面。
2014年12月 9日 21:33 | # | 引用
shuaiagain 说:
我们组长推荐的你的文章,果然不错,浅显易懂,又不缺乏内涵,赞一个!
2014年12月27日 11:14 | # | 引用
lee 说:
个人感觉,阮老师的博客受众是非常非常初级入门的程序员,或者说,应该是邻家大哥这种类型的,能帮一个不懂的孩子入门,或者产生兴趣,这个阶段不能深究晦涩的原理性知识。
主要是因为文字里面有大量的原理性错误,软件公司的员工或者硕士以上学历的朋友建议还是带着批判的眼光去学习比较好。
但是不得不承认,阮老师的文字功底很好,就像有个人在你旁边跟你聊天一样,容易让新手进入状态,这方面必须赞。
2015年1月21日 12:19 | # | 引用
天魔人心 说:
var1是a原型是的数组 b修改了原型导致var1成了[1,2,3,4] c继承下来了,不是c可以改变a中的数组
2015年1月23日 15:39 | # | 引用
netlibo 说:
其实,关键还是javascript这门语言入门太简单了,所以后面很多人都按自己的理解去做了,都不去看ECMA了,包括我,也包括阮老师!
重新回头看看语言权威的描述,根本没有这些疑问,人家都说的很明白。
2015年1月26日 16:37 | # | 引用
justme_cq 说:
你写的这个不就是那个javascript高级编程里面的么(没错,就是你那参考资料),也没有太大差别。其实这些 在javascript高级编程第3版写的都很详细。
2015年2月 1日 10:02 | # | 引用
mythshuazi 说:
对于一个跨行学编程的小白来说,您的这篇文章对我太有意义了!
2015年2月11日 10:54 | # | 引用
railsbug 说:
写的简洁有力 通俗易懂 牛!
2015年4月16日 20:27 | # | 引用
小明 说:
入门级的,很适合初学者,简单易懂!
2015年6月 2日 16:53 | # | 引用
rr_rr 说:
好文,能提供一个支付宝捐款链接吗?我想donate!
2015年6月17日 04:50 | # | 引用
ChuaNG 说:
老师,您的这段代码应该在name 和 color后面加上分号。很好的文章,让我一下子就理解了
/*二、 原始模式的改进
我们可以写一个函数,解决代码重复的问题。
function Cat(name,color){
return {
name:name,
color:color
}
}
*/
2015年7月 6日 12:13 | # | 引用
23 说:
很棒的文章,感谢,茅塞顿开,看了你的文章再去看这个书更容易理解书了,因为书好晦涩
2015年7月14日 12:03 | # | 引用
小何 说:
深入浅出。
2015年7月23日 10:07 | # | 引用
李建轩 说:
好文章,太通俗易懂了!
2015年8月 6日 15:27 | # | 引用
洋 说:
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert(name)};
如果在eat方法中用Cat中的name啊
2015年10月 9日 14:56 | # | 引用
天上蹲 说:
写的真好 浅显易懂
2015年11月11日 11:25 | # | 引用
muller_zhang 说:
所以说要把不变的属性和方便绑在prototype对象上,可变的单独封装,作为私有属性或方法。
2015年11月12日 15:42 | # | 引用
roger 说:
写的真好 浅显易懂
2015年11月20日 16:48 | # | 引用
南蛮妈妈 说:
2015年12月15日 17:29 | # | 引用
unhum 说:
写js也有一年多了~对于面向对象还是一知半解,没有投入过真正的使用里面,一直搞不明白,有什么建议吗,ruan大哥
2015年12月27日 20:26 | # | 引用
瑞瑞爸爸 说:
不太同意阮老师的标题“封装”,封装(encapsulation)又叫隐藏实现(Hiding the implementation)。就是只公开代码单元的对外接口,而隐藏其具体实现。我们脑子里面很容易想到的是类似java里面的Public, Protected, Private 等访问控制符,来控制成员变量的访问权限,但是这篇文章只是在讲创建一个类型,而不是讲怎么控制属性的访问权限。
2016年1月 4日 15:17 | # | 引用
海天鹰 说:
写得太好了,把复杂的东西简单讲明白了!
请允许我永久收藏。
2016年1月 7日 12:35 | # | 引用
李 说:
写的好,作为后端开发。对js知识了解皮毛。最近接触到js的面向对象,看到这篇文章,感觉很有兴趣
2016年1月20日 09:30 | # | 引用
卢泰祥 说:
封装的意思不是这个吧?
封装,即隐藏对象的属性和实现细节,仅对外公开接口 这才对吧
2016年1月24日 22:50 | # | 引用
zoho 说:
非常适合入门!多谢分享!
2016年2月23日 10:55 | # | 引用
it民工 说:
浅显易懂,而且逐步深化,非常感谢!
2016年3月 1日 00:10 | # | 引用
迹忆 说:
我写了一篇关于Javascript中Prototype的文章,希望阮老师多多指教
2016年3月 3日 15:26 | # | 引用
科科 说:
爲了通俗而通俗,爲了容易理解而理解,只會使得讀者同樣流於表面,自以爲理解,實際上根本不懂。一旦難度稍微加大,舊有的思維不再好用,就難以提升了。
反之一開始就接受抽象思維的訓練而不是套用舊有的思維,雖然一開始艱難,而後必會突飛猛進。
建議这位朋友不要看任何低水平的「科普」文章,直接看英文維基百科、MDN、ECMAScript 草案比較好。
真正的入門往往就是在一瞬間,過了這道坎,你就入門了。盲目地看再多低水平的文章,照樣毫無幫助。
2016年5月24日 20:35 | # | 引用
玖头 说:
很喜欢,谢谢写出这么好的文章
2016年5月26日 11:18 | # | 引用
cw 说:
在网上找了很多相关的内容,阮老师说的真的很好,很好理解,非常感谢阮老师分享!
2016年5月27日 19:02 | # | 引用
请叫我衡哥 说:
很好的文章,阮兄真的深入浅出。期待js方面更深的东西
2016年6月12日 10:54 | # | 引用
布里茨 说:
真的是言简意赅,我这种菜鸟都能理解 ,感谢分享
2016年6月29日 11:24 | # | 引用
小明 说:
6.1 isPrototypeOf()
这个方法用来判断,某个“proptotype”对象和某个实例之间的关系。这个单词写错了。
2016年7月12日 09:29 | # | 引用
爱喝白开水 说:
var a=function(){
//empty
}
a.prototype.var1=[1,2,3];
a.prototype.var2 = "猫科动物";
var b=new a();
var d = new a();
b.var1.push(4);
b.var2 = "昆虫";
var c=new a();
console.log(b.var2);
console.log(c.var2);
console.log(d.var2);
console.log("--------------");
console.log(c.var1.join(","));
console.log(d.var1.join(","));
不太理解,为什么var1影响了后续实例的对象,var2没有影响到呢?
2016年7月12日 18:15 | # | 引用
TJ 说:
@爱喝白开水:
b.var1.push(4);b.var2 = "昆虫"; 主要在这两句的区别,js寻址的规则是先在对象的本地属性下去找,如果找不到在去该对象的proto(不同浏览器的实现可能不一样)中去找,proto指向的是a的prototype。
第一句b.var1.push(4);首先在b的本地属性(也就是上文提出的hasOwnProperty相关)找,没找到,再去b的proto中去找,找到了,然后push一下,这里b.var1和a.prototype.var1引用的是同一个,修改了b.var1中的内容,也相当于修改了a.prototype.var1的内容。
b.var2 = "昆虫"; 这里不是改变了b.var2,而是新定义了b的本地属性var2,你可以用hasOwnProperty判断下,这里的var2是b的本地属性。
2016年8月22日 14:56 | # | 引用
zhangenming 说:
@爱喝白开水:
某个实例改变var1,var2都不会改变之后实例的值
那么var1怎么从[1,2,3]变成[1,2,3,4]了呢?
这里说的"改变"是指"指针(引用)"的改变
不能改变指针的值 但能改变指针的值的值
而var1的指针确实没变 都指向这个数组(指针的值)
只不过是这个数组改变了(指针的值的值)
a.prototype.var1 = [1,2,3,4];(修改指针的值,不生效)
b.var1.push(4);(修改指针的值的值,生效)
不知道你明白没 同学生 正在学JS
2016年8月22日 15:46 | # | 引用
晨曦 说:
太棒啦,解答我不少的困惑。
另外请教一下:Cat.prototype.type = "猫科动物";改写成var type = "猫科动物";应该也是指向统一内存空间吧???
2016年8月27日 02:23 | # | 引用
罗Q 说:
老师把高级程序设计中的内容总结起来非常好,让我很快就理解了
2016年9月11日 09:16 | # | 引用
Jessie_CateatRats 说:
厉害啊!浅显易懂!
2016年11月22日 18:39 | # | 引用
~\(≧▽≦)/~啦啦啦 说:
一下看懂了,表白老师( ̄3 ̄)
2016年11月29日 11:17 | # | 引用
williams 说:
对我这样的小白来说很有用,啃不懂大部头,但是还得使用js做一些东西。这篇文章讲解的很清楚。
2016年12月 3日 11:37 | # | 引用
超超 说:
对提高自我的技术修养很是有用!
2016年12月10日 12:32 | # | 引用
狗蛋 说:
比老师讲的易理解
2016年12月20日 15:40 | # | 引用
asina 说:
阮老师真是我学习的榜样,很耐心。
2017年2月10日 21:14 | # | 引用
哈哈哈 说:
真的是通俗易懂
2017年3月 3日 10:41 | # | 引用
一只小白 说:
好文,豁然开朗的感觉
2017年3月 8日 14:17 | # | 引用
Bubble Andy 说:
其实在看这篇文章前我就懂这一块了,但是还是想过来看看峰峰大神是如何讲解原型对象和构造函数的,没想到峰峰大神讲的如此通俗易懂,膜拜大神!!!
2017年3月13日 15:04 | # | 引用
zj 说:
讲的很明白,谢谢大神!
2017年3月22日 17:15 | # | 引用
ajian 说:
这个主要是自有属性和继承属性之间的来源差异
2017年4月12日 09:45 | # | 引用
细节撩妹 说:
茅塞顿开 只能说很幸运看到这篇文章
2017年5月11日 22:00 | # | 引用
qnlz 说:
很好理解,如果阮兄能用图表示下每个内存块里面的东西就更好啦
2017年6月 8日 09:33 | # | 引用
ymlh 说:
通俗易懂 受益匪浅
2017年6月16日 14:03 | # | 引用
啊啊啊 说:
还是不太明白封装在具体案例的时候怎么用
2017年7月31日 16:17 | # | 引用
朱振伟 说:
全部是JavaScript高级程序设计的内容。
2017年8月23日 17:46 | # | 引用
itzhu 说:
@axu:
简单的理解的话,这个var1可以认为是a的静态变量。
a类的实际定义如果用java体现的话,大概是下面这样的。
JAVA --
class A{public static int[] var1 = new int[]{1,2,3};}
//本人js小白,以上理解不代表正确
2017年9月 8日 15:58 | # | 引用
itzhu 说:
@爱喝白开水:
刚才理解错了,看到这个才大致明白啊。内存地址引用值的改变...不是全局变量的意思
2017年9月 8日 16:18 | # | 引用
飘飞的夏秋 说:
话说,留言部分能不能分页啊,一进来就留意到滚动条老长老长。。。。。。
2017年10月23日 18:27 | # | 引用
sxm 说:
为什么要滚到最下面才能留言,好麻烦
2017年10月26日 18:05 | # | 引用
wwz 说:
实在话,现在2017年11月7日,这篇文章对我用处还是会很大
2017年11月 7日 12:50 | # | 引用
魔君君主 说:
用prototype方式添加的属性,是构造函数用于继承的,也就是说,这些属性是实例化对象所继承的属性;
但是在函数内部添加的属性如:this.name = name;这种方式添加的属性是实例化对象创建后自身的直系属性。
说白了就是 继承属性和直系属性的区别。
2017年11月26日 18:51 | # | 引用
lionking 说:
的确,看号称最适合初学者的《JavaScript编程精解》也是云里雾里,阅读了本篇后茅塞顿开。
2017年11月27日 12:06 | # | 引用
ztt 说:
2017年11月28日 17:09 | # | 引用
run 说:
大道至简,把一个自己理解清楚的内容,用别人都容易理解的语言组织起来不是一件容易的事情
2017年12月 7日 12:08 | # | 引用
云 说:
谢谢教程!真是循序渐进,浅显易懂,条理非常清晰,多谢 /抱拳
2017年12月17日 06:46 | # | 引用
瓦力 说:
function Cat(name, color) {
this.name = name;
this.color = color;
this.type = "我是猫";
this.eat = function () {
console.log("猫吃老鼠")
}
}
var cat1 = new Cat("小白", "white");
var cat2 = new Cat("小黑", "black");
console.log(cat1.type);
cat1.eat();
console.log(cat1.eat == cat2.eat);//false
console.log(cat1.type == cat2.type);//true
为什么方法是false,属性是true呢
2018年1月 4日 10:19 | # | 引用
满 说:
@瓦力:
两个对象相比较的时候,如果不是指向同一个对象,就返回false。但使用prototype模式里的方法都引用的都是同一个,所以返回true
2018年1月 8日 09:41 | # | 引用
陈豪 说:
太简单了点吧。
2018年3月 3日 20:17 | # | 引用
JasonWei 说:
阮大神2010年写的,你2010年在干嘛?
2018年3月 8日 18:31 | # | 引用
python 说:
2010年的你在干什么?你只是别人学的久一些,请别用一种比别人优越的感觉评价,搞技术需要的是不断的学习
2018年3月21日 16:09 | # | 引用
罗大大 说:
在第三点构造函数模式那里"这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。"这句应该是cat1和cat2自己本身没有constructor属性,这个是在他们的构造函数的原型上也就是Cat.prototype上的构造函数,准确的说:应该是Cat.prototype.constructor === Cat
2018年4月10日 10:10 | # | 引用
熊大 说:
第6.1 行 下面有个prototype 好像有个笔误
2018年4月26日 10:34 | # | 引用
tomoya06 说:
一直对object的概念有点模糊,还是来看阮老师的博客学习
2018年5月10日 11:57 | # | 引用
ed 说:
几年前初学js,当时看原型链这块看的云里雾里。就是因为讲的时候对面向对象没有一点了解。
当时的材料也只直说原型链,执行上下文 bla bla bla... 没有实际应用完全不知道在说什么。
最近项目中遇到复杂的东西需要复用,以前简单的封装不能满足需求了。
再一看阮老师的js面向对象把以前初学时用不到的js原型链、构造函数都串了起来。
真是逻辑清晰,简单易懂。
2018年6月 2日 09:25 | # | 引用
噜噜噜 说:
阮老师,大写的服!通俗易懂,特别好理解!
2018年6月 7日 14:02 | # | 引用
李晓玲 说:
我有一个问题想请教一下:
console.log()方法 和 alert()的方法在输出cat对象的时候,
前者输出的是对象中的具体内容,后者输出的是[object object],
function catFun(name,color) {
this.name=name;
this.color=color;
}
var cat1 = new catFun("张三","黄色");
console.log(cat1);
alert(cat1);
为什么输出的是这样子?
我查到的资料是alert()输出的是string类型,而console.log()是任何类型,
执行console.log(cat1.toString())时,对象转字符串的时候他会和alert()一致,不是很明白这一步为什么可以一致?
希望得到解答,谢谢
2018年7月 2日 09:33 | # | 引用
anye 说:
看了那么多原型、原型链文章都看不懂。看了这个才看懂,那些人也不知道写的什么玩意,还敢写文章。
2018年7月 3日 15:23 | # | 引用
宋秉徽 说:
cat1有prototype吗?你打印看看。
2018年8月 8日 11:23 | # | 引用
王迪 说:
2018年8月31日 16:27 | # | 引用
Thinker 说:
这篇文章确实通俗易懂,有种茅塞顿开的感觉
2018年8月31日 22:53 | # | 引用
zj 说:
function F(){}
F.prototype.name = 'jy'
var _obj = new F()
_obj.name 此时name属性是调用的是从其构造函数F原型上继承来的 属性name
而我们现在给_obj的name属性赋值时
_obj.name = 'ly'
此时的name便是通过字面量创建对象的属性
现在的_obj具有本地name属性,_obj的原型__prop__也具有一个name属性
2018年11月 7日 19:01 | # | 引用
姜 说:
破局,文章写得很好。我这样的小白都感觉自己学到了很多的东西。感谢阮一峰老师
2018年11月28日 15:48 | # | 引用
大表哥 说:
阔以撒!!!写的很明白,对于初学者学习面向对象有帮助的.............
2019年1月24日 20:31 | # | 引用
wlq 说:
真的牛,非常的通俗易懂
2019年6月 4日 23:35 | # | 引用
liuyufang 说:
@Ruan YiFeng:
额,我运行了这段代码,结果是1,2,3,4有什么不对吗?本人小白,请不吝赐教
2019年7月30日 10:05 | # | 引用
花怠叶慢 说:
看了别人的文章,写了一堆字,看的云里雾里的,还是阮大神讲的浅显易懂
2019年12月12日 14:21 | # | 引用
Silence 说:
受益匪浅,感谢感谢!✿✿
2019年12月26日 19:52 | # | 引用
ddd 说:
阮一峰老师这篇文章,让我茅舍顿开
2020年1月 7日 16:51 | # | 引用
webcyh 说:
阮一峰老师很强、之前我都没好好理解过什么情况将方法写在构造方法上、什么时候将方法放在构造方法的原型上面,今天算是理解了很多很多,比如一个插件 我们构造一个插件 对象 如果有多个对象 ,但他们配置参数是不同的所以应该将参数放在构造方法当中 然后比如钩子函数、初始化方法等是这些对象共有的所以应该放在原型对象上面、这样有哪些优点?
1、这样每次创建对象时候 虽然不同的对象占用不同的内存 而且参数也不同但是 公用的同一个原型 也就是他们的钩子函数、初始化方法是共用一个的这样节省了很多内存
2020年1月 8日 11:28 | # | 引用
Jack 说:
这时 cat1 和cat2会自动含有一个constructor属性,指向它们的构造函数。
---------------
cat1 和 cat2 中其实并没有包含 constructor 属性,它们只有一个非标准的 __proto__ 属性,该属性指向 Cat.prototype ,真正包含 construtor 属性的是 Cat.prototype.
2020年12月17日 10:32 | # | 引用
我的大名 说:
很基础,适合小白理解
2021年7月20日 14:01 | # | 引用
雒喑 说:
看一遍没看懂,但是直觉这已经是比较浅显易懂的object解释了,继续!
2021年8月 3日 19:49 | # | 引用
Uaena 说:
对于小白来说简单易懂,多点这种容易理解的就好了,老师厉害
2021年8月30日 16:45 | # | 引用
小周周 说:
十一年再看阮老师的文章,还是很适用,阮老师的文章真滴是小白入门的标准指南哈
2021年11月24日 09:21 | # | 引用
aa要转码 说:
2022了 这个2010写得内容依旧值得看,老师niu!
2022年7月 6日 11:10 | # | 引用
群除我佬 说:
大佬牛,说得非常明白,不过我有个小小建议,评论区可不可加个分页器,下拉到发表看法区域得滑好久呢
2023年4月 6日 15:06 | # | 引用