JS面向对象总结【封装,继承,多态,this,prototype】(笔记)
了解面向对象三大特征之前,对于抽象的了解十分重要,在定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。
封装(encapsulation )
function Person(name, age) {
this.name = name;
var age = age;// 在实例中无法被调用
}
var p1 = new Person("Bob", 20);
console.log(p1) // Person ->{name: "Bob"} 无法访问到age属性,这就叫被封(装)起来了。
访问封装属性的方法--特权方法
function Person(age) {
var age = age;// 私有变量
this.showAge = function() {// 特权方法
console.log(age);
};
}
var p1 = new Person(20);// 新建对象p1
p1.showAge();// -> 20 这个20是闭包,在闭包笔记处会详解。
// 如果不理解闭包,按照我自己的思路很难去解释:
// 为什么这个函数体里面存了一份age的数据。
但是如果使用prototype来写的函数,无法访问私有变量
Person.prototype.myAge = function() {
console.log(age);
};
var p1 = new Person(20);// 新建对象p1
p1.myAge();// 报错 age is not defined
其实这也印证了:闭包就是函数里面包函数,由于prototype是通过函数名,指到其他内存空间独立的函数体,因此没法取得闭包的作用域变量。
继承
将不同类的相同之处取出封装成独立的类
1.对象冒充方法 (有缺陷,在继承笔记详细介绍)
function Stu() {
this.name = "学生";
}
Stu.prototype.free = function() {
console.log("free");
};
function MidStu() {
this.stu = Stu;// 将Stu函数体赋值给stu;
/*
* 执行stu里面的函数体
* 就相当于执行了这句话 :this.name = "学生";
*/
this.stu();// 通过对象冒充,来实现继承。
delete this.stu;// 删除对象的引用。
}
var stu1 = new MidStu();
console.log(stu1); // 拥有这个属性 this.name = "学生";
stu1.free(); //prototype的free这个属性不存在
多态
所谓多态,就是指一个引用类型在不同情况下的多种状态。在java中多态是指通过指向父类的引用,来调用在不同子类中实现的方法。 js实际上是无态的,是一种动态语言,一个变量的类型是在运行的过程中由js引擎来决定的,所以说js天生就支持多态。

// 主人类
function Master() {
// 主人玩耍动物
this.feed = function(animal) {
console.log("主人玩耍" + animal.name);
console.log("类:" + animal.constructor);
};
}
// 猫类
function Cat(name) {
this.name = name;
}
// 狗类
function Dog(name) {
this.name = name;
}
var cat = new Cat("小猫咪");
var dog = new Dog("小狗狗");
var master = new Master();
master.feed(cat);
master.feed(dog);
// 这样做的优点在于Master不需要改变,如果要扩展加入其它的动物,
// 只需要加一个猴子类就好了
Javascript-面向(基于)对象编程-介绍
- Javascript-是采用基于对象(面向对象)来编程的。
- Javascript-中没有Class类(原型对象) tip:有人直接就叫类了。
如果要得到一个cat1(猫1)对象
var cat1 = {};
cat1.age = 1;
cat1.name = "小白";
cat1.voice = "喵";
// 得到 cat1 = {age: 1, name: "小白",voice :"喵"};
但是要写出cat2,cat3则需要很多的代码
var cat2 = {};
cat2.age = 2;
cat2.name = "小白";
cat2.voice = "喵";
// 得到 cat2 = {age: 2, name: "小白",voice :"喵"};
var cat3 = {};
cat3.age = 3;
cat3.name = "小白";
cat3.voice = "喵";
// 得到 cat3 = {age: 3, name: "小白",voice :"喵"};
接着来描述下创建类(原型对象)的方式:5种
- 工厂方法--使用new Object创建对象并添加相关属性。
- 使用构造函数来定义类(原型对象)。
- 使用prototype
- 构造函数及原型混合方式
- 动态原型方式
重点是第二种方式写法
function 类名/原型对象名 (){
} // 创建对象 var 对象名 = new 类名();
function aaa() {
console.log(this.bbb);// 可以输出bbb这个函数,说明bbb函数也被提前执行
this.a = console.log(111);
}
// 注意点,bbb这个函数在new的时候会被提前加载,在console.log(this.bbb)这句话中可以输出函数体
aaa.prototype.bbb = function() {
console.log(222);
};
new aaa();
那么如何判断实例是属于什么类?
// 我自己定义的类
function Person() {}
var Bob = new Person();
console.log(Bob.constructor);
// function Person() {}
console.log(typeof Bob);
// object
// 系统的类number
var bbb = 12345; // -> var bbb = new Nmuber(12345);
console.log(bbb.constructor);
// function Number() { [native code] }
console.log(typeof bbb);
// number
Javascript-中一切都是对象
function Person() {}
console.log(Person.constructor);
// 函数的类为 Function() { [native code] }
如何判断一个对象实例是不是Person类型
function Person() {}
var Bob = new Person();
// instanceof 实例
console.log(Bob instanceof Person) // true instanceof 还可以用来判断复杂类型对象的归属
console.log(Person === Bob.constructor); // true
delete 用于删属性 delete cat1.name 注:不能直接删cat1对象,不能删除window上面的属性。
this 的提出
function Person() {
}
var p1 = new Person();
p1.name = "顺平";
var p2 = new Person();
console.log(p2.name); // -> undefined
当我们创建一个对象后,希望该对象自动拥有某些属性,比如有个初始 name
function Person() {
this.name = "初始名"
}
var p1 = new Person();
var p2 = new Person();
console.log(p1.name + " : " + p2.name); // -> “初始名”,两个实例对象的name属性相互对立不影响。
我在这里先对比下有new 跟没有new的区别
function Person() {
this.name = "初始名";
console.log(this);
}
var p1 = Person(); // 打出的是window对象
var p1 = new Person(); //1 打出的是 新Person;2而且返回值为this。其他不同点暂时还没有发现。
有new下的this指向

在我目前看来,new 一个构造函数,返回的是一个this,本质上我觉得是重新开辟了一个内存空间给新生的Person然后通过给变量赋值,以及开辟了一个空间给原型对象prototype,以用来存储。比如p1 = 新Person,拿到新Person的地址,得到对象所拥有的方法。
function Person() {
this.name = "初始名";
}
console.log(new Person() ) // 返回值是this
p只是记录了这个引用对象的地址。
p记录的是ox1234的地址,所以在调用abc()的时候调用的是ox1234的abc,this指向的就是ox1234

如果将返回值改为引用类型,则会改变返回值,注:return 123;这种不生效
function Person() {
this.name = "初始名"
return [];
}
console.log(new Person()) // ->[ ]
this只能在类的内部使用。
总结一下,是什么决定this最终的指向,this最终的指向永远是离方法最近的那个引用类型的那个对象。
var name = "window";
var myname = function() {
console.log(this.name);
};
var value = {
a: {
name: "a",
myname: function() {
console.log(this.name);
},
b: {
name: "b",
myname: function() {
console.log(this.name);
}
}
}
};
/*
* window
* a
* b
* 这三者都是引用对象
*/
window.myname();// window
window.value.a.myname();// a
window.value.a.b.myname();//b
成员函数(成员方法)
function Person(name, age) {
/*
* 传入实际的参数去初始化属性时用到。
* 适用于每个对象都有的,但是里面的内容不一样的。
* 好处是可以在初始化对象(new)时使用传入的参数
* 缺点是每个对象都有自己的一份配置,不共用
*/
this.name = name;
this.age = age;
}
var p1 = new Person("林冲", 30);
var p2 = new Person("宋江", 40);
console.log(p1.name + ":" + p2.name); // -> 林冲:宋江
对于函数赋值, 之前没有尝试过这种方法,也是可以用的
var x = function aaa() {
console.log("good");
};
console.log(x);
// -> 打出的是有名字的函数,跟匿名函数不一样
//function aaa() {
// alert();
//}
x(); // -> good
// var x = aaa= function() {
// console.log()
// }
//等同
function aaa() {
console.log("good");
}
var x = aaa;
验证通过this制造的函数体是否独立
function Person() {
this.aaa = function(value) {};
}
var p1 = new Person();
var p2 = new Person();
console.log(p1.aaa === p2.aaa); // false
prototype 原型链 (也是成员方法)
通过shout函数名 来调用函数体,公用
验证通过this制造的函数体是否独立
function Person() {}
/*
* 缺点是不可以在初始化对象(new)时使用传入的参数
* 优点是每个对象都公用这有一份属性,节流
*
*/
Person.prototype.aaa = function(value) {};
var p1 = new Person();
var p2 = new Person();
console.log(p1.aaa === p2.aaa); // true
写得不错,star
了解面向对象三大特征之前,对于抽象的了解十分重要,在定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。
封装(encapsulation )
function Person(name, age) { this.name = name; var age = age;// 在实例中无法被调用 } var p1 = new Person("Bob", 20); console.log(p1) // Person ->{name: "Bob"} 无法访问到age属性,这就叫被封(装)起来了。访问封装属性的方法--特权方法
function Person(age) { var age = age;// 私有变量 this.showAge = function() {// 特权方法 console.log(age); }; } var p1 = new Person(20);// 新建对象p1 p1.showAge();// -> 20 这个20是闭包,在闭包笔记处会详解。 // 如果不理解闭包,按照我自己的思路很难去解释: // 为什么这个函数体里面存了一份age的数据。但是如果使用prototype来写的函数,无法访问私有变量
Person.prototype.myAge = function() { console.log(age); }; var p1 = new Person(20);// 新建对象p1 p1.myAge();// 报错 age is not defined其实这也印证了:闭包就是函数里面包函数,由于prototype是通过函数名,指到其他内存空间独立的函数体,因此没法取得闭包的作用域变量。
继承
将不同类的相同之处取出封装成独立的类
1.对象冒充方法 (有缺陷,在继承笔记详细介绍)
function Stu() { this.name = "学生"; } Stu.prototype.free = function() { console.log("free"); }; function MidStu() { this.stu = Stu;// 将Stu函数体赋值给stu; /* * 执行stu里面的函数体 * 就相当于执行了这句话 :this.name = "学生"; */ this.stu();// 通过对象冒充,来实现继承。 delete this.stu;// 删除对象的引用。 } var stu1 = new MidStu(); console.log(stu1); // 拥有这个属性 this.name = "学生"; stu1.free(); //prototype的free这个属性不存在多态
所谓多态,就是指一个引用类型在不同情况下的多种状态。在java中多态是指通过指向父类的引用,来调用在不同子类中实现的方法。 js实际上是无态的,是一种动态语言,一个变量的类型是在运行的过程中由js引擎来决定的,所以说js天生就支持多态。
// 主人类 function Master() { // 主人玩耍动物 this.feed = function(animal) { console.log("主人玩耍" + animal.name); console.log("类:" + animal.constructor); }; } // 猫类 function Cat(name) { this.name = name; } // 狗类 function Dog(name) { this.name = name; } var cat = new Cat("小猫咪"); var dog = new Dog("小狗狗"); var master = new Master(); master.feed(cat); master.feed(dog); // 这样做的优点在于Master不需要改变,如果要扩展加入其它的动物, // 只需要加一个猴子类就好了Javascript-面向(基于)对象编程-介绍
- Javascript-是采用基于对象(面向对象)来编程的。
- Javascript-中没有Class类(原型对象) tip:有人直接就叫类了。
如果要得到一个cat1(猫1)对象
var cat1 = {}; cat1.age = 1; cat1.name = "小白"; cat1.voice = "喵"; // 得到 cat1 = {age: 1, name: "小白",voice :"喵"};但是要写出cat2,cat3则需要很多的代码
var cat2 = {}; cat2.age = 2; cat2.name = "小白"; cat2.voice = "喵"; // 得到 cat2 = {age: 2, name: "小白",voice :"喵"}; var cat3 = {}; cat3.age = 3; cat3.name = "小白"; cat3.voice = "喵"; // 得到 cat3 = {age: 3, name: "小白",voice :"喵"};接着来描述下创建类(原型对象)的方式:5种
- 工厂方法--使用new Object创建对象并添加相关属性。
- 使用构造函数来定义类(原型对象)。
- 使用prototype
- 构造函数及原型混合方式
- 动态原型方式
重点是第二种方式写法
function 类名/原型对象名 (){ } // 创建对象 var 对象名 = new 类名();
function aaa() { console.log(this.bbb);// 可以输出bbb这个函数,说明bbb函数也被提前执行 this.a = console.log(111); } // 注意点,bbb这个函数在new的时候会被提前加载,在console.log(this.bbb)这句话中可以输出函数体 aaa.prototype.bbb = function() { console.log(222); }; new aaa();那么如何判断实例是属于什么类?
// 我自己定义的类 function Person() {} var Bob = new Person(); console.log(Bob.constructor); // function Person() {} console.log(typeof Bob); // object // 系统的类number var bbb = 12345; // -> var bbb = new Nmuber(12345); console.log(bbb.constructor); // function Number() { [native code] } console.log(typeof bbb); // numberJavascript-中一切都是对象
function Person() {} console.log(Person.constructor); // 函数的类为 Function() { [native code] }如何判断一个对象实例是不是Person类型
function Person() {} var Bob = new Person(); // instanceof 实例 console.log(Bob instanceof Person) // true instanceof 还可以用来判断复杂类型对象的归属 console.log(Person === Bob.constructor); // truedelete 用于删属性 delete cat1.name 注:不能直接删cat1对象,不能删除window上面的属性。