原型与继承学习笔记1

    浅谈对象

面向对象原型链继承这块,应该算是javascript中最难理解的部分了,小弟脑子比较难转弯,也是看了好久视频,博文,慢慢的才有了自己的理解,现在记录一下学习的内容和总结。首先第一节应该说说对象这个东西了,js中对象和其他语言还是有所不同的,现在切入正题,开始浅谈对象。

    什么是对象

定义(ECMA-262):无序属性的集合,其属性可以包含基本值、对象或者函数。

通过定义可以看出来,对象是属性的集合,这些属性又会是一个基本值,一个函数或者又是一个新的对象。记住,函数也是对象,了解这点以后原型链会很好理解。

    对象结构

大概解释一下这个图,var obj = {}; obj.x = 1; obj.y = 2;这段代码先定义了一个obj空对象,然后定义了两个属性x和y,每一个属性又都是一个键值对的对象。有writable,enumberable,configurable,value四个属性和一对get/set方法。一个对象又有三个默认的属性__proto__,__class__,__extensible__,其中__proto__属性是指向创建该对象的函数(方法)的prototype对象,如第二个obj的__proto__对象会指向fn的构造函数的prototype属性。好吧,有点绕,后续会绕出来的。。。

    创建对象

1.new

首先,需要说明的是,对象其实都是通过函数创建的,如上图中的var obj=new fn();,再比如这种:var obj={},arr=[];,其实这两种创建对象的方法的实质分别为var obj=new Object(),arr = new Array();,所以对象都是通过函数创建的这个话就不足为奇了。

上个模块我们知道了函数会默认有prototype这个属性,如下:

这个prototype的属性值是个对象,即属性的集合,该属性一般情况下只有一个constructor属性,指向函数本身。

我们也可以在自定义函数的prototype中添加一些属性,看代码:

1 function Fn(){
2
3 };
4 Fn.prototype.x=1;
5 var f1 = new Fn();

这时,实例化的f1对象就可以访问Fn()的原型属性x的值了。也就是说,f1对象是从Fn函数new出来的,这样f1对象就可以调用Fn.prototype中的属性了。这是因为每个对象都有一个__proto__属性(chrome将这个属性暴露了出来,大家可以在chrome浏览器上看一下这个属性),这个属性引用了创建该对象的函数的prototype属性,可以得到f1.__proto__===Fn.prototype.__proto__会在下节详细说明,这个算是原型链继承的关键(一条看不见的链条连接了所有有血缘关系的家族~)。本节还是继续扯函数的prototype属性。

那么原型这块大体上可以用下图来表示:

一句话概括:实例化出来的对象的__proto__属性连接实例函数的prototype属性,这样实例化对象就可以通过看不见的那根链条访问prototype属性。那么问题来了:怎么判断一个对象的属性值是原型上的属性还是自身的属性,js为我们提供了这么一个方法:hasOwnProperty()和in操作符,如上,使用in操作符可以判断属性是否存在(包含原型链上属性),hasOwnProperty()方法也是判断属性是否存在(不包含原型属性)。

2.Object.create()

根据代码对比来理解一下:

 1 function Person (name) {
 2     this.name=name
 3 };
 4 Person.prototype.sayName=function(){
 5     console.log(this.name)
 6 };
 7 function Teacher(name){
 8     this.name=name
 9 };
10 Teacher.prototype = Person.prototype;
11 var teacher = new Teacher("James");
12 teacher.sayName();       //James
13
14 Teacher.prototype.teach = function(course){
15     console.log("I teach "+course)
16 }
17 teacher.teach("English");   //I teach English
18
19 var person = new Person("Lebro");
20 person.teach("Chinese");    //I teach Chinese

如上第10行代码,将Person的原型直接赋值给Teacher的原型看似是没问题的,对象teacher会继承Person()的sayName()方法,但是给Teacher拓展方法时就会出现共享的问题,Teacher.prototype 会和 Person.prototype指向一处引用,这样拓展Teacher的原型方法就相当于给Person的原型添加了方法,显然不是我们想要的;

所以引入了Object.create()方法免除这个问题,实质还是对prototype属性的赋值:

 1 function Person (name) {
 2     this.name=name
 3 };
 4 Person.prototype.sayName=function(){
 5     console.log(this.name)
 6 };
 7 function Teacher(name){
 8     this.name=name
 9 };
10 Teacher.prototype = Object.create(Person.prototype);
11 var teacher = new Teacher("James");
12 teacher.sayName();       //James
13
14 Teacher.prototype.teach = function(course){
15     console.log("I teach "+course)
16 }
17 teacher.teach("English");   //I teach English
18
19 var person = new Person("Lebro");
20 person.teach("Chinese");    //Uncaught TypeError: person.teach is not a function

如上代码,用Object.create()方法代替直接赋值就会避免这个问题,因此这个方法实际上就是先创建一个空对象,把参数Person.prototype的值有这个空对象进行传递给Teacher.prototype,这样就不会有原型共享的问题了,使用Object.create()方法时考虑到这一点就不会出错了(没有研究源码,只是本人暂时这么理解的,欢迎指正)。

    第一节就先说这么多,没有按照常用思维来写,因为本次执笔只是本人的一次学习总结,是按照我从不懂到慢慢缕清整个思路的一个过程来写的,可能不会满足所有人的学习模式,而且最基础的一些对象方面的知识也没提到,因为能看到原型继承这块我觉得最基本的基础应该是具有的,所以,请尽情吐槽吧~~~下节说一下对象的属性操作,包括读写,删除,枚举,检测。下节再见了。

时间: 2024-10-29 21:15:40

原型与继承学习笔记1的相关文章

原型与继承学习笔记4

经过前三节的研究,我们终于可以对js这门无法实现接口继承的语言进行实现继承,为了更好的面向对象..... 原型链继承 这个原型链我们上节引用了一下,用它实现继承的基本思想是利用原型让一个引用类型引用另一个引用类型的属性和方法.即把一个函数(狭义上来举例)的所有属性和方法(这个函数的实例)赋值给另一个函数的prototype,使一个函数的实例可以通过__proto__原型一层层的调用另一个函数的所有属性. 有点绕,简单的说就是把超类的实例赋值给子类的prototype.看个例子: 1 functi

原型与继承学习笔记2

上节我们讨论了对象的定义和对象的创建,知道了函数也是对象,知道了对象都是由函数创建的,知道了对象的原型和函数的原型属性的关系.这节说一下关于对象属性的操作,下节就可以切入正题了. 属性删除 1 var person = {age : 28, title : 'fe'}; 2 delete person.age; // true 3 delete person['title']; // true 4 person.age; // undefined 5 delete person.age; //

C#中面向对象编程机制之继承学习笔记

继承反应了类和类之间的关系. 世界上很多事物都是有共性的,共性的那一部分我们就抽象为基类,用于派生其它类,这样提高了代码的复用性,使得代码的结构清晰易读,而且易于代码的扩展和维护. C#的继承只能继承自一个基类,这一点不同于C++的继承. C#的继承具有传递性,即B继承自A,C继承自B,则C具有A的所有特性. C#的继承隐式为public的. 假如不在派生类构造器中显示调用一个基类构造器,编译器会自动插入对基类的默认构造器的一个调用,然后才会执行派生类构造器中的代码, 如果基类没有默认的构造器,

【转载】Javascript原型继承-学习笔记

阮一峰这篇文章写的很好 http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html 笔记如下: 一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(p

JavaScript继承学习笔记

JavaScript作为一个面向对象语言(JS是基于对象的),可以实现继承是必不可少的,但是由于本身并没有类的概念,所以不会像真正的面向对象编程语言通过类实现继承,但可以通过其他方法实现继承.(javascript中的继承是通过原型链来体现的http://www.cnblogs.com/amumustyle/p/5435653.html)实现继承的方法很多,下面就只是其中的几种. 一.原型链继承 1 function Person() { //被继承的函数叫做超类型(父类,基类) 2 this.

《C++ Primer Plus》14.2 私有继承 学习笔记

C++(除了成员变量之外)还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员.(如果使用保护继承,基类的公有成员和保护成员都将称为派生类的保护成员.)这意味着基类方法将不会称为派生类对象共有接口的一部分,但可以在派生类的成员函数中使用它们.14.2.1 Student类示例(新版本)Student类应从两个类派生而来,因此声明将列出这两个类:class Student : private std::string, private std

《C#高级编程》【第四章】继承 -- 学习笔记

计算机程序,在很大的程度上是为了描述和解决现实问题.在面向对象语言中的类很好的采用了人类思维中抽象和分类的方法,类和对象的关系很好的反映了个体与同类群体的共同特征的关系.但是在诸多共同点之下还是存在着些许差异.于是面向对象语言中设计了继承机制,允许我们在保持原有类特性的基础上,进行拓展.由于类的继承和派生机制的引入,使得代码的重用性和可扩充性大大提高.利用这个机制我们还可以站在巨人的肩膀上就行开发---利用别人写好的类进行扩充,这样又可以提高我们的开发效率.在派生新类的过程一般来说有三个步骤:吸

继承 学习笔记

package ctgu.java.java; public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this

《javascript高级程序设计(第二版)》学习(4)原型与继承

声明:这类属于学习笔记,主要是摘录书中内容,比较少的整理.内容经常是跳跃的,建议您阅读书本,收益更大. function Person(){} Person.prototype.name="tom"; //这里等于重写了原型对象 //切断了与构造函数之间的联系 Person.prototype={ name:"mike", age:22 }; //得到的不是Person了,而是Object console.log(Person.prototype.construct