JavaScript 面向对象
1.面向对象概论:
面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
- 一切事物皆对象
- 对象具有封装和继承特性
- 对象与对象之间使用消息通信,各自存在信息隐藏
2.创建对象的几种常用方式
1.使用Object或对象字面量创建对象
2.工厂模式创建对象
3.构造函数模式创建对象
4.原型模式创建对象
2.1使用Object或对象字面量创建对象
JS中最基本创建对象的方式:
var student = new Object();
student.name = "easy";
student.age = "20";
或者来一个对象字面量方式创建对象
var sutdent = {
name : "easy",
age : 20
};
但当我们要创建同类的student1,student2,…,studentn时,我们不得不将以上的代码重复n次…会导致代码冗余,所以有了第二个创建方式“工厂模式创建对象”。
2.2工厂模式创建对象
JS中没有类的概念,那么我们不妨就使用一种函数将以上对象创建过程封装起来以便于重复调用,同时可以给出特定接口来初始化对象
function createStudent(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var student1 = createStudent("easy1", 20);
var student2 = createStudent("easy2", 20);
...
var studentn = createStudent("easyn", 20);
但是工厂函数也有一个弊端:无法判断对象属于哪一个类型。
2.3构造函数模式创建对象
在上面创建Object这样的原生对象的时候,我们就使用过其构造函数:
var obj = new Object();
在创建原生数组Array类型对象时也使用过其构造函数:
var arr = new Array(10); //构造一个初始长度为10的数组对象
构造函数的弊端:每个实例的调用的方法应该是一致的,但是实际上在生成实例时都各自创建了自己的方法,消耗了内存。
2.3-1构造函数和普通函数有什么区别
1、实际上并不存在创建构造函数的特殊语法,其与普通函数唯一的区别在于调用方法。对于任意函数,使用new操作符调用,那么它就是构造函数;不使用new操作符调用,那么它就是普通函数。
2、按照惯例,我们约定构造函数名以大写字母开头,普通函数以小写字母开头,这样有利于显性区分二者。
例如上面的new Array(),new Object()。
3、使用new操作符调用构造函数时,会经历
(1)创建一个新对象;
(2)将构造函数作用域赋给新对象(使this指向该新对象);
(3)执行构造函数代码;
(4)返回新对象;4个阶段。
4.new的含义
在内容中开辟一块储存空间 并返回他的地址,堆(内存)中开辟储存空间。
2.3-2构造函数中的this
指向实例对象
2.4原型的模式创建对象
- 原型对象上的属性和方法能被实例所访问
- 原型本身就是一个对象,所有的函数都拥有原型对象
- 箭头函数没有原型对象,并且箭头函数不能当做构造函数使用
- 在原型中的属性,所有实例对象都可以访问,节省内存空间
- 属性放在构造函数里,方法放到原型对象上
function Student() {
this.name = 'easy';
this.age = 20;
}
Student.prototype.alertName = function(){
alert(this.name);
};
var stu1 = new Student();
var stu2 = new Student();
stu1.alertName(); //easy
stu2.alertName(); //easy
alert(stu1.alertName == stu2.alertName); //true 二者共享同一函数
3.instanceof运算符
3.1 instanceof概述:
instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上
3.2 instanceof语法:
obj instanceofObject;//true 实例obj在不在Object构造函数中
3.2 instanceof描述:
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
3.2 instanceof实例:
3.2-1.instanceof的普通的用法,obj instanceof Object 检测Object.prototype是否存在于参数obj的原型链上。
Person的原型在p的原型链中
functionPerson(){};
var p =new Person();
console.log(p instanceof Person);//true
3.2-2.继承中判断实例是否属于它的父类
Student和Person都在s的原型链中
functionPerson(){};
functionStudent(){};
var p =new Person();
Student.prototype=p;//继承原型var s=new Student();
console.log(s instanceof Student);//trueconsole.log(s instanceof Person);//true
4.js原型链是什么
4.1作用:原型链的存在,主要是为了实现对象的继承。
###4.2关于原型链的几个概念:
4.2-1、函数对象
在JavaScript中,函数即对象。
4.2-2、原型对象
当定义一个函数对象的时候,会包含一个预定义的属性,叫prototype,这就属性称之为原型对象。
//函数对象
function F(){};
console.log(F.prototype)
4.2-3、proto
JavaScript在创建对象的时候,都会有一个[[proto]]的内置属性,用于指向创建它的函数对象的prototype。原型对象也有[[proto]]属性。因此在不断的指向中,形成了原型链。
//函数对象
function F(){};
F.prototype = {
hello : function(){}
};
var f = new F();
console.log(f.__proto__)
4.2-4、new
当使用new去调用构造函数时,相当于执行了
var o = {};
o.__proto__ = F.prototype;
F.call(o);
因此,在原型链的实现上,new起到了很关键的作用。
4.2-5、constructor
原型对象prototype上都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用。
出现在构造函数原型中,它是一个指针,指向固定构造函数。
作用:检测数据类型。
function F(){};
F.prototype.constructor === F;
在实际运用中,经常会有下列的写法
function F(){};
F.prototype = {
constructor : F,
doSomething : function(){}
}
这里要加constructor是因为重写了原型对象,constructor属性就消失了,需要自己手动补上。
4.2-6、原型链的内存结构
function F(){
this.name = 'zhang';
};
var f1 = new F();
var f2 = new F();
总结:每一个构造函数都有一个原型对象,每一个原型对象上都有一个指向构造函数的指针(constructor),每一个实例上有一个指向这个原型对象的内部指针__proto__原型对象上的属性和方法能被实例所访问到。