javaScript OOP学习总结
一.创建对象的方式
1.构造型函数方式
1.1.可以创建多个对象
例如: function Stu(name,age){ this.name=name; this.age= age; } var stu = new Stu("lol",18); var stu2=new Stu("ldm",19);
1.2.函数里面是可以写代码的
例如: function Stu(name,age){ this.age=age; this.name=name; this.stu=function(){ if(age<18){ alert("未成年"); } } }
2. 对象字面量方式创建对象
2.1.对象字面量创建对象:对象字面量是创建对象最简单的一种形式,目的是在于简化创建包含大量属性的对象的过程。对象字面量由若干属性名(keys)和属性值(values)成对组成的映射表,key和value中间使用冒号(:)分隔,每对key/value之间使用逗号(,)分隔,整个映射表用花括号({})括起来。
例如: var stu={ name:"lok", age:19, study:function(){ alert("study"); } } 可以使用静态方法创建属性 stu.sex="男"; 调用对象 alert(stu.name); stu.study();
二、创建实例方法的方式
1.实例方法的3种创建方式
1.1实例方法的定义1:这里是利用javascript对象原型引用prototype来实现的。
例如: var BaseClass = function() {}; BaseClass.prototype.method1 = function(){ alert(' 通过prototype定义的实例方法'); }
var instance1 = new BaseClass();
instance1.method1();//实例方法
1.2.实例方法的定义2:method1即为通过prototype原型引用定义的实例方法,这里也可以在实例上直接定义方法(变量)
例如: var BaseClass = function() {}; var instance1 = new BaseClass(); instance1.method1 = function(){ alert(' 直接定义的实例方法 '); } instance1.method1();//直接定义方法(变量)
1.3.通过this指针来定义实例方法(变量)
例如: var BaseClass = function() { this.method1 = function(){ alert('通过"this"定义的实例方法"); } }; var instance1 = new BaseClass(); instance1.method1();//通过this指针来定义实例方法
2.那么同时在实例上、原型引用上和“this”上定义了相同名字的实例方法后,实例会优先调用那一个呢?
例如: var BaseClass = function() { this.method1 = function(){ alert('通过this指针来定义实例方法'); } }; var instance1 = new BaseClass(); instance1.method1 = function(){ alert('直接定义的实例方法'); } BaseClass.prototype.method1 = function(){ alert('通过prototype定义的实例方法 '); } instance1.method1();
结果是:直接定义在实例上的变量的优先级要高于定义在“this”上的,而定义在“this”上的又高于 prototype定义的变量。即直接定义在实例上的变量会覆盖定义在“this”上和prototype定义的变量,定义在“this”上的会覆盖prototype定义的变量。
三、创建静态方法
1.静态方法的定义
例如: var BaseClass = function() {}; // var BaseClass=new Function(); BaseClass.f1 = function(){ //定义静态方法 alert(' 这是静态方法'); } BaseClass.f1();//调用静态方法 //静态方法不能被实例对象调用 var instance1 = new BaseClass(); instance1.f1();//instance1.f1 is not a function
四、成员的访问
1.成员的访问方式
方式一:点语法 var stu ={ name : "lok1", age : 19, study :function(){ alert("study1"); } } alert(stu.name); stu.study(); 方式二:通过使用object[propertyName] (对象["属性名"]) alert(stu["name"]);
五、js两大特性
1.弱类型:弱类型语言也称为弱类型定义语言,弱类型语言允许将一块内存看做多种类型。比如直接将整型变量与字符变量相加。
2.动态性:运行时可变化,比如对象可以动态的添加成员。
六、instanceof
1. 因为使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object"。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。
2.instanceof的特性:instanceof用于判断某个对象是否被另一个函数构造。
例如: var oStringObject = new String("hello world"); console.log(oStringObject instanceof String); // 控制台输出 "true"
七、构造器(Constructor)
1.在JavaScript的世界里没有类的概念,JavaScript是一种基于对象的语言,它包含5中原生数据类型:
-
number
-
boolean
-
string
-
null
-
undefined
除此之外,其他所有的都是对象,函数也是一个对象
2.构造函数,就是一个普通的函数,与其他函数没有任何区别,可以理解为 函数==构造函数,它只是概念上的一个定义,使用它用来实例化对象。
对于JavaScript的内置对象,Object、Array、Date等等这些都是构造函数。
function Obj() { } var o = new Obj(); // 实例化
3.使用new运算符返回的对象并不一定是实例本身,也可以在构造函数用使用return改变返回值
function Obj() { this.a = 1; return { a: 2 }; } var o = new Obj(); // o并不是Obj的实例 console.log(o.a); // 输出2
前面说到了函数也是一个对象,在JavaScript的内置对象中,所有的函数对象都是Function构造函数的实例,比如:Object、Array等等,这是一个很有意思的事情。
4.使用 instanceof 这个运算符就可以校验
-
instanceof运算符返回一个指定的对象是否一个类的实例,格式如:A instanceof B。其中,左操作数必须是一个对象,右操作数必须是一个类(构造函数)。
-
判断过程:如果函数B在对象A的原型链中被发现,那么instanceof操作符将返回true,否则返回false。
alert(Function instanceof Function); // Function函数对象 本身就是自己的一个实例 alert(Object instanceof Function); // Object函数对象 是 Function构造函数的一个实例
八、new的简单理解
js可以创建并使用的对象有三种:本地对象、内置对象和宿主对象。本地对象就是ECMA-262定义的类(引用类型),应该都是可以new的。另外自己定义或继承的对象(函数)都是可以new的。ECMA-262把内置对象(built-inobject)定义为“由ECMAScript实现提供的、独立于宿主环境的所有对象,在ECMAScript程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。所有非本地对象都是宿主对象(hostobject),即由ECMAScript实现的宿主环境提供的对象。所有BOM和DOM对象都是宿主对象。
//例如: function SuperType() { this.prop = true; } SuperType.prototype.getSuperValue = function() { return this.prop; } var instance = new SuperType(); 个人目前的理解是: 1.开辟一块内存,标识为instance; 2.把SubType本身(不包括原型对象)包含的属性和值注入到instance里面; 3.添加__proto__属性,并且把值设置为SubType的prototype属性指向的那个原型对象。
九、JS预处理机制
1. 在预处理的阶段:
1.1 读取分析整个源代码
1.2 找出所有用var声明的变量以及用声明的方式创建的函数
1.3 第二步把找出来的东西添加到一个对象里面去(如果是全局代码,这个对象就是window)
1.4 如果是变量,那么值此时等于undefined如果是函数,此时的值就指向函数
2.全局代码的执行:(在我们的下面的案例里面)
2.1 把a的值从undefined改为1
2.2 调用f函数,以便f函数得到执行。
//所有用var声明的变量以及声明的函数 var a = 1; function f(){ alert(a); var a = 5; } f(); var a = 1; function f(){ alert(a); a = 8; } f();
当在函数内部:
var a = 1; function f(){ alert(a); var a = 5; alert(a); } f();
预处理阶段:
1.1把函数的参数添加到一个对象(词法对象)
1.2 把所有用var声明的变量以及声明的形式创建的函数添加到词法对象里面。变量的值也是为undefined
3.作用域:
for(var i = 0;i< 10;i++){ console.log(i); } alert(i); //js的作用域不是块级别的 //js的作用域是函数级别的 function f(){ var a = 8; } f(); alert(a); //------------ function f(){ a = 8; //在函数内部声明的变量如果不加var,自动成为window的成员 } f(); alert(a); alert(window.a);
十、JS OOP
1.封装
function Animal() { this.name="动物"; this.getName=function(){ return this.name; } this.setName=function(name){ this.name=name; } this.bark=function(){ console.log(this.name+"在叫..."); } } var animal=new Animal(); animal.setName("小狗"); animal.bark();
这里定义的一个构造函数,将name封装成属性,Animal函数本身用于封装动物的属性与行为
2.继承
JavaScript的继承的实现主要依靠prototype(原型)来实现。
创建一个person类 有工作方法 有一个使用工具的属性 默认true 名字属性
学生类 有学号属性 学习方法 学生类与person类实现继承关系,代码如下:
//第一步:创建父类 function Person(name,tools){ this.name=name || '人'; this.tools=tools || true; } //定义父类方法 Person.prototype.work=function(){ console.log(this.name+"正在工作!"); } Person.prototype.sleep=function(){ console.log(this.name+"正在睡觉!"); } //第二步:创建子类 function Stu(name,num){ Person.call(this,name); this.num=num; } //第三方桥接 //function Ps(){ //} //Ps.prototype=Person.prototype; //Stu.prototype=new Ps(); //第三步:确定继承关系。子类原型=Object.create(父类原型); Stu.prototype=Object.create(Person.prototype); Stu.prototype.study=function(){ console.log(this.name+"正在学习!"); } //第四步:改造构造器(不是很重要) Stu.prototype.constructor=Stu; var stu = new Stu('lok',20);
3.多态
java中的多态主要体现在重载与重写上,因为JavaScript是弱类型的,类方法参数是动态指定的所以并没有真正意义上的重载,只能在方法中判断参数达到目的。
多态基本概念:
多态是指一个引用(类型)在不同情况下的多种状态。也可以理解成:多态是指通过指向父类的引用,来调用在不同子类中实现的方法。
多态利于代码的维护和扩展,当我们需要使用同一类树上的对象时,只需要传入不同的参数就行了,而不需要再new 一个对象。
4.重载(方法名相同,参数个数不同,类型不同)
//例如: function prop(){ var firstP = document.getElementById("p"); if(arguments.length == 1){ var temp = arguments[0]; for(p in temp) { firstP.style[p] = temp[p]; } }else if(arguments.length == 2) { firstP.style[arguments[0]] = arguments[1]; } } prop("backgroundColor","black"); prop("fontSize","38px"); prop({ backgroundColor:"red", fontSize:"38px" });
5.回调函数
回调函数被认为是一种高级函数,一种被作为参数传递给另一个函数(在这称作"otherFunction")的高级函数,回调函数会在otherFunction内被调用(或执行)。回调函数的本质是一种模式(一种解决常见问题的模式),因此回调函数也被称为回调模式。
//例如: //自定义的forEach循环 function myForEach(eles,callback){ for(var i=0;i< eles.length;i++){ callback(i,eles[i]); } } //找出所有的p标签 var alls = document.getElementsByTagName("p"); //调用myForEach实现隔行变色 myForEach(alls,function(index,ele){ if(index % 2 == 0 ) { ele.style.backgroundColor = "yellow"; }else{ ele.style.backgroundColor = "green"; } });
6.立即执行的匿名函数
//立即执行的匿名函数 ( function(){ var a = 5; var b = 100; window.c = 200;//把c暴露出去 d = 300;//这行代码也可以做到公布 } )(); //console.log(c); var result = (function(m,n){ return m + n;})(10,20); //console.log(result); //---------------------------------- //封装get、set方法 function Person(){ var age = 1; this.getAge = function(){ return age ; } this.setAge = function(val){ age = val; } } var p = new Person(); p.setAge(20); console.log(p.getAge());
7.闭包
闭包概念:当一个内部函数被调用,就会形成闭包,闭包就是能够读取其他函数内部变量的函数,定义在一个函数内部的函,创建一个闭包环境,让返回的这个子程序抓住i,以便在后续执行时可以保持对这个i的引用。内部函数比外部函数有更长的生命周期;函数可以访问它被创建时所处的上下文环境。
Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量
闭包是什么?闭包是个对象,这个对象里面包含一个函数,里面的函数调用了闭包对象里的变量,以及被此函数捕获的东西(一般是变量)称为闭包。
function P(){ var a = 5; var b = 6; return function C(){ console.log(100); } } var result = P(); result();