面向对象是一种编程思想编程
对象:能够添加属性(变量)和方法(函数);
面向对象写法特色:数组
一、把功能写成一个函数; 二、函数必须写在对象身上,调用的时候直接拿对象.方法名(); 三、对象身上的功能能够继承; 四、this指向,在事件或者定时器里面是访问不到真正的this的,须要在外面存一下;
写法示例: function 构造函数 (){ this.属性=??; } 构造函数.prototype.方法=??; var 实例=new 构造函数(); 实例.方法();
一元运算符,后面只能接函数,用来调用函数;数据结构
用new调用函数的过程:模块化
一、构建一个空对象; 二、把函数内部的this指向建立的对象; 三、在函数执行完之后自动返回刚才建立的那个对象,即便函数里面没有return;假如函数后面有return的话会有两种状况: A 、return后面是对象的话,则返回这个对象; B 、return后面是非对象的话,则返回一开始new建立的对象;注意:函数
一、用new调用的函数永远返回一个对象,无论有没有返回值; 二、用new调用函数,这个函数必定是用来建立对象的,叫作构造函数;
建立并初始化对象的函数,而且必须用new调用,否则和普通函数没有区别;性能
functon Person(name,age){ this.name=name; this.age=age; this.say=function{ console.log("my name is"+this.name); }; };
new出来的都是构造函数的实例,构造函数就是实例化的过程;
构造函数的问题:性能问题会形成资源浪费;this
概念:函数身上的属性,每一个函数都有,它的值是一个对象;prototype
用途:由于它是一个对象,因此身上能够放属性和方法,若是与构造函数相结合,经过构造函数建立的对象就会具备原型身上的属性和方法;code
建议把一些共用的属性和方法放在构造函数的原型身上;对象
对象身上的属性,每一个对象都有这个属性;它的值也是一个对象,它的值就是它对应的构造函数的prototype的值;
实例.__proto__===构造函数.prototype;这句话解释了为何实例可以继承构造函数身上的属性和方法;
functon Person(name,age){ this.name=name; this.age=age; }; this.prototype.say=function{ console.log("my name is"+this.name); }; var p1=new Person("peter",18);
在这个例子中:p1.__proto__=Person.prototype;因此p1才能继承Person构造函数身上的属性和方法;
对象与原型之间的关系(连接)
原型链查找规则:
包装对象有:
注意:
做用:判断一个属性是否是本身对象身上的;
语法:对象.hasOwnProperty(属性);
参数:要检测的属性;
返回值:
**true** *自身属性* **false** *非自身属性*
注意:
一、这个方法是Object身上的方法 二、不会顺着原型链往外面去查找属性,只查找自身
概念: 每一个对象身上都会有这个属性,默认指向该对象对应的构造函数; 这个属性不是放在对象身上,放在对应的原型对象身上;
做用:查看对象的构造函数;
语法:对象.constructor;
返回值:对象的构造函数;他能够用来作数据类型的判断;
constructor的问题 :constructor的值是能够修改的; function Person(name){ this.name=name; } var p1=new Person('kaivon'); console.log(p1); console.log(p1.constructor==Person); //true p1.constructor=Array; console.log(p1.constructor==Array); //true
做用:把对象类型转成字符串;
注意:系统对象身上的这个方法都是在对应的原型身上;而本身写的构造函数这个方法在达的Object原型身上
它能够用来作类型判断:
Object.prototype.toString.call( );
//用toString作类型判断 var num=0; //[object Number] var str='kaivon'; //[object String] var b=true; //[object Boolean] var n=null; //[object Null] var u=undefined; //[object Undefined] var arr1=[]; //[object Array] var obj1={}; //[object Object] var fn=function(){}; //[object Function] var d=new Date(); //[object Date] var re=new RegExp(); //[object RegExp] console.log(Object.prototype.toString.call(num));
基本数据类型复制:
var num1=123; var num2=num1;//那么num2和num1就是同样的,**复制了值**
var arr1=[1,2,3]; var arr2=arr1; arr2.push(4); //注意这个时候arr1和arr2的值; console.log(arr2); //[1,2,3,4] console.log(arr1); //[1,2,3,4]
arr1和arr2同样的缘由:复杂数据类型复制的时候不只仅是复制了值,还复制了引用地址,因此修改arr2时,那么arr1的地址和arr2其实仍是同样的,因此arr1的值也相应改变了;
浅拷贝;
var obj1={a:10,b:20}; //如何复制呢? function copy(obj){ var newObj={}; for(var attr in obj){ newObj[attr]=obj[attr]; } return newObj; } var obj2=copy(obj1); //这时候的obj2和obj1看起来是同样的,可是实际上是不一样的,有不一样的引用地址;
深拷贝
深拷贝和浅拷贝的区别:
一、当要复制的那个对象里面全部的值都是非对象的时候,用浅拷贝;
二、当要复制的那个对象里面有对象的时候,用深拷贝;
var obj1={ a:10, b:{ c:20 //这时候对象里面还有对象;这时候怎么办呢? } } //若是这时候还用上面的浅拷贝的话,那么修改复制后的值,原来对象里面的值也仍是会改变,因此要用下面的办法; function deepCopy(obj){ if(typeof obj!=="object"){ return obj; } //上面的代码是给了一个跳出条件,当传入的条件不是对象的时候就不须要递归了; if(obj instanceof Array){ var newObj=[]; }else{ var newObj={}; } for(var attr in obj){ newObj[attr]=deepCopy(obj[attr]); //递归;当对象里面的值仍是对象的时候须要用到; } return newObj; }
让一个对象拥有另外一个对象的属性和方法,而且本身添加的属性和方法不会影响原来的对象;
经过call的方法调用构造函数来继承属性;
function Person(name,age){ this.name=name; this.age=age; } Person.prototype.say=function(){ console.log('我叫'+this.name); } //Person至关于一个大类,Coder至关于一个小类,他们是有共同的地方的; function Coder(name,age,job){ this.name=name; this.age=age; this.job=job; } Coder.prototype.say=function(){ console.log('我叫'+this.name); } //经过属性继承,咱们能够将小类和大类共同的部分简化以下: function Coder(name,age,job){ Person.call(this,name,age); //若是不用call的话,那么this的指向就是window了,因此要用call将指向指到当前的this上面; this.job=job; }
经过for in 想要继承的构造函数的原型的方法去去继承;
参考属性继承?的代码:
for (var attr in Person.prototype){ if(Person.prototype.hasOwnProperty(attr)){ Coder.prototype[attr]=Person.prototype[attr]; } }
把一个效果或者方法用面向对象的方法封装起来,只提供给用户一些相关的方法和数据接口;(模块化)
易扩展、易维护、相互之间没有影响
放在初始化函数里;
function Drag(obj){ this.disX=0; this.disY=0; //下面的就是默认参数,下面的函数都要用下面的参数; this.settings={ id:"", //这是必传的; downFn:function{}, moveFn:function{}, upFn:function{} } } //下面这个叫作初始化函数; Drag.prototype.init=function (opt) { //在初始化函数里面,拿用户输入来的参数覆盖默认参数; for(var attr in this.settings){ if(this.settings.hasOwnProperty(attr)){ //若是默认参数里面有这个属性的话,才会去覆盖; this.settings[attr]=opt[attr]; } } this.obj=document.getElementById(this.settings.id); } //用户传进来的就叫作配置参数;是一个对象;
放在原型里的函数;
概念:
自定义事件三要素:
key:value
键值对的方式去把事件名和事件处理函数联系起来; 把多个函数放到一个数组里面,循环数组里面的每一个函数;//定义事件 object.events={ "事件名1":[fn1,fn2], "事件名2":[fn3,fn4,fn5] } //调用事件(循环去调用)
//事件绑定器,添加自定义事件; function customEvent(obj,eventName,fn){ /* obj 对象名; * eventName 对象的一个事件名,它的值是一个数组; * fn 事件调用函数,它在数组里面; */ //这里的"||"逻辑符号的意思是左边为真走左边,左边为假走右边; obj.events=obj.events||{}; obj.events[eventName]=obj.events[eventName]||[]; obj.events[eventName].push(fn);//push方法把函数添加到数组; } //事件触发器; function(obj,eventName){ //触发的时候要看看对象身上有没有这个事件; if(obj.events[eventName]){ for(var i=0;i<obj.events[eventName].length;i++){ obj.events[eventName][i].call(obj); //注意this的指向,要指向这个obj; } } }