面向对象入门
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题 的步骤中的行为。
1、面向对象是一种思维方法
2、面向对象是一种编程方法
3、面向对象并不只针对某一种编程语言
数ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。正因为这样(以及其他将要讨论的原因),我们可以把 ECMAScript 的对象想象成散列表:无非就是一组名值对,其中值可以是数据或函。
<script type="text/javascript">
//用大括号括起来的一系列的键值对,就构成了JavaScript对象。这种对象称之为字面量对象。
var person = {
name : "张三", // 一个键值对
age : 20,
sex : "男",
eat : function () { //属性的值是函数,这个时候我们更喜欢把这样的属性称之为方法。
alert("吃东西");
}
}
</script>
说明
name : “张三” 一个键值对表示JavaScript对象的一个属性。 name是属性名, “张三” 属性值。
属性可以是任意类型的。可以包括我们以前学的简单数据类型,也可以是函数,也可以是其他的对象。
当一个属性的值是函数的时候,我们更喜欢说这个属性为方法。(如果函数不和对象关联起来的时候,应该叫函数不应该叫方法。只是一种称呼,你完全可以不用理会)。 我们一般说person对象具有了一个方法eat. 将来访问eat的时候,也和调用一个函数一样一样的。
访问对象的属性
alert(person.name); // 访问person对象的 name属性值
person.age = 30; //修改person对象的 age 属性
person.eat(); //既然是调用方法(函数) 则一定还要添加 ()来表示方法的调用
alert(person["name"]); //
给对象添加属性
//给person对象的属性 girlFriend 赋值。在赋值的过程中,首先会判断这个属性在JavaScript中是否存在,如果存在就对这个
//属性重写赋值。如果不存在,就给这个对象添加这个属性,并赋值。
person.girlFrient = "小丽";
//给对象添加方法
person.play = funcion(){
alert("打击high起来");
}
删除对象属性
// 使用delete操作关键字,删除person对象的属性age
delete person.age;
alert(person.age); //弹出undefined。表示这个属性没有定义
修改对象属性
// 把person对象的sex属性的值修改为 女
person.sex = "女";
person.eat = funcion(){
alert("吃货");
}
person.eat(); //吃货
使用for…in遍历对象的属性
// 在用for...in遍历的时候, in前面的变量pn指的是属性的名称。
for (pn in person) {
alert(pn + " " + person[pn]);
}
创建对象的方式
工厂模式的创建
虽然object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个借口创建很多对象,会产生大量的重复代码。为了解决这个问题,人们开始使用工厂模式的一种变体。
工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程,考虑到在ECMAscript中无法创建类,开放人员就发明了一种函数,用函数来风装以特定借口创建对象的细节。
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
};
return o;
}
var person1 = createPerson("张三", 29, "js开发者");
var person2 = createPerson("李四", 27, "java开发者");
构造函数模式创建
为了解决对象类型识别问题,又提出了构造函数模式。这种模式,其实在我们创建一些原生对象的时候,比如Array、Object都是调用的他们的构造函数。
>
看下面的代码
function Person (name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.eat = function () {>
alert(this.name + "在吃东西");
}
}
var p1 = new Person("张三", 20, "男");
p1.eat(); //张三在在吃东西
var p1 = new Person("李四", 30, "男");
p1.eat(); //李四在在吃东西
alert(p1 instanceof Person); //
说明:
使用构造函数创建对象,必须使用关键字new ,后面跟着构造函数的名,根据需要传入相应的参数。
其实使用 new 构造函数() 的方式创建对象,经历了下面几个步骤。
创建出来一个新的对象
将构造函数的作用域赋给新对象。意味着这个时候 this就代表了这个新对象。
执行构造函数中的代码。 在本例中就是给新对象添加属性,并给属性初始化值。
构造函数执行完毕之后,默认返回新对象。 所以外面就可以拿到这个刚刚创建的新对象了。
三级联动实例
面向对象版本html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="地域.js"></script>
</head>
<body>
<select></select>省
<select></select>市
<select></select>县
<script type="text/javascript" src="面向对象版本.js"></script>
</body>
</html>
面向对象版本js代码
var change = {
init:function () {
this.sel = document.querySelectorAll('select');
this.fillProvince();
this.fillCities(1);
this.fillcounties(1);
var self = this;
this.sel[0].onchange = function() {
var ProID = this.value;
self.fillCities(ProID);
self.fillcounties(self.sel[1].value);
}
this.sel[1].onchange = function () {
var CityID = this.value;
self.fillCounties(CityID);
}
},
// 获取省
fillProvince:function () {
var province = ld.provinceList;
for(var sheng of province){
var ProName = sheng.ProName;
var ProID = sheng.ProID;
var opt = this.createOption(ProName, ProID);
this.sel[0].appendChild(opt);
}
},
// 获取市
fillCities:function (ProID) {
this.sel[1].innerHTML = "";
var cities = ld.cityList;
for(var city of cities){
if(ProID == city.ProID){
var opt = this.createOption(city.CityName,city.CityID);
this.sel[1].appendChild(opt);
}
}
},
// 获取县
fillcounties:function (CityID) {
this.sel[2].innerHTML = "";
var counties = ld.countyList;
for(var county of counties ){
if (CityID == county.CityID){
var opt = this.createOption(county.DisName,county.ID)
this.sel[2].appendChild(opt);
}
}
},
createOption: function (text, value){
var option = document.createElement("option");
option.value = value;
option.innerHTML = text;
return option;
}
}
change.init();
面向对象过程版本html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="地域.js"></script>
</head>
<body>
<select></select>省
<select></select>市
<select></select>县
<script type="text/javascript" src="面向过程版本.js"></script>
</body>
</html>
面向对象过程js代码
var sel = document.querySelectorAll('select');
fillProvinces();
fillCities(1);
fillCounties(1);
sel[0].onchange = function () {
var ProID = this.value;
fillCities(ProID);
fillCounties(sel[0].value);
}
sel[1].onchange = function () {
var CityID = this.value;
fillCounties(CityID);
}
function fillProvinces() {
var province = ld.provinceList;
for(var sheng of province){
var ProName = sheng.ProName;
var ProID = sheng.ProID;
var opt = this.createOption(ProName,ProID);
sel[0].appendChild(opt);
}
}
//获取市
function fillCities(ProID) {
sel[1].innerHTML = "";
var cities = ld.cityList;
for(var city of cities){
if(ProID == city.ProID){
var opt = this.createOption(city.CityName,city.CityID);
sel[1].appendChild(opt);
}
}
}
//获取县
function fillCounties(CityID) {
sel[2].innerHTML = "";
var counties = ld.countyList;
for(var county of counties){
if(CityID == county.CityID){
var opt = this.createOption(county.DisName,county.ID);
sel[2].appendChild(opt);
}
}
}
function createOption(text,value) {
var option = document.createElement("option");
option.value = value;
option.innerHTML = text;
return option;
}
三级联动省、市、县所需代码
构造函数
使用new的方式来调用函数的时候, 这个时候, 这样的函数就叫构造函数作为构造函数使用:
- 首先创建一个对象, 这个对象的类型就是构造函数的名字
- 最后会把创建这个对象自动的返回
在构造函数中,this就是指代创建这个对象
<script>
function Person(name, age, sex){
console.log(this);
//给创建的对象初始化
this.name = name;
this.age = age;
this.sex = sex;
this.speak = function (){
console.log(this.name, this.age);
}
}
var p1 = new Person("李四", 20, "男");
var p2 = new Person("志玲", 40, "女");
console.log(p1);
console.log(p2);
p1.speak();
p2.speak();
<script>
构造函数与普通函数的区别
他们调用方式不同
构造函数:new 函数()
默认返回创建的那个对象
所有单词首字母大写
尽量不要手动添加return语句
普通函数:函数()
默认返回undefined
原型理解
1.在原型中固定义的属性和方法对所有对象都是共享的
2.通过对象只能读取到原型中的数据,但是不能直接去修改
创建对象的问题
1.使用原型创建对象的问题:
缺点:原型上的属性是所有对象所共有
优点:方法共享
2.构造函数的创建对象的问题:
优点:属性没有共享
缺点:方法没有共享
组合方式创建对象
<script>
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function (){
console.log("吃" + this.name);
}
Person.prototype.speak = function (){
console.log("说" + this.age);
}
var p1 = new Person("联想", 41);
var p2 = new Person("联想", 41);
p1.eat();
p2.eat();
</script>
继承
函数借调
function foo(age,name,address) {
this.age = age;
this.name = name;
this.address = address;
}
var obj = {};
函数借调 ,借用Call
foo.call(obj,20,"流亡平","内良乡");
console.log(obj);
组合继承
function Animal(name,color) {
this.name = name;
this.color = color;
}
Animal.prototype.eat = function(){
console.log("汪平在吃" + this.name);
}
Pig.prototype = new Animal();
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
function Dog(name,color,weight) {
Animal.call(this,name,color);
this.weight = weight;
}
function Pig(name,color,weight) {
Animal.call(this,name,color)
this.weight = weight;
}
var dog = new Dog("汪平","绿色","200斤");
var pig = new Pig("猪平","黑色","500斤")
console.log(pig instanceof Animal);
console.log(pig);
pig.eat();
console.log(dog instanceof Animal);
console.log(dog);
dog.eat();
作用域与闭包
变量的作用域
变量的作用域指的是:变量起作用的范围。
>
javascript 的变量依据作用域的范围分为:
>
1.全局变量
>
2.局部变量
全局变量
定义在函数外的变量都是全局变量
>
<script>
alert(a);
var a = 10;
<script>
局部变量
在函数内声明的变量是局部变量,所以形参的变量也是局部变量
>
在函数的外部不能访问局部变量
<script>
function f(){
alert(v);//没有声明,所以结果为underfind
var v = "abc";//声明变量
alert(v);//弹出"abc"
}
alert(v)//报错,在函数外部不能访问局部变量
<script>
关于执行环境
在全局变量的执行环境中,有一个变量对象,这个变量对象把这个执行环境中定义的变量存储为这个变量对象的一个属性,访问变量,就相当于访问变量对象的一个属性。
>
在全局的执行环境中,变量对象就是window。
>
任何的函数都有一个属性:[[scope]]
<script>
function foo(){
var a = 20;
console.log(a);
}
var s = "hello World"
console.log(s.replace(/[ ](\w)/gi, " $1".toUpperCase()));
<script>
作用域链
作用域链与一个执行环境有关,作用域用于在变量查找
!C:\Users\Administrator\Desktop\JS-面向对象\Day5 作用域和闭包\Advanced_Day05
闭包
闭包可以分为广义上的闭包,也可以是狭义上的闭包。
>
广义上的闭包:
>
只要一个函数,访问过这个函数外的变量,那这个函数就是闭包。
>
狭义上的闭包:
>
如果一个函数,访问过它的外部函数的局部变量,那这个函数就是闭包
>
闭包的特点
>
闭包能够访问外部函数作用域内的所有变量,而且访问的变量是最新的变量,即使外部的函数执行结束了,它依然能够访问外部的局部变量。
<script>
var a = 10;
function foo(){
var = 20;
function f()
return b;
}
b = 30;
return f();
}
var b = foo()();
console.log(b);
<script>
使用闭包封装对象
<script>
function foo(){
name:"李四";
age:20;
}
return {
getName:function(){
return p.name;
},
getAge:function(){
return 20;
},
setName:function(name){
p.name = name;
},
setArrt:function(key,value){
p[key] = value;
},
getArrt:function(key){
return p[key];
}
}
var p = foo();
p.setName("滴滴答");
console.log(p.getName());
p.setArrt("sex","男");
console.log(p.getArrt("sex"));
<script>
闭包 常见的for循环问题
常见的循环赋值问题
<button>按钮1<button>
<button>按钮1<button>
<button>按钮1<button>
<script>
var btn = document.querySelectorAll('button');
for(let i=0;i<btn.length;i++){
btn[i].onclick = function(){
console.log(i);
}
}
<script>
常见的高阶函数
高阶函数, 是函数式编程语言的一个非常重要的特点。
如果一个高阶函数接受一个或多个函数作为参数, 或者可以返回一个函数, 则这样的函数就叫高阶函数。
map:
<script>
var arr = [1,2,3,4,5];
var a1 = arr.map(function(x){
return x*x;
})
console.log(arr.map(Matn.sqrt));
console.log(a1)
<script>
reduce:
>
10!的阶乘
<script>
var arr = [1,2,3,4,5];
var a1 = arr.reduce(function(a,ele){
return a *ele;
},1)
console.log(a1);
<script>
filter: 过滤
<script>
var arr = [1,2,3,4,5,6,7,8,9,10];
var a1 = arr.filter(function(ele,index,arry){
return ele%2==1;
})
console.log(a1);
<script>
面对对象的综合
this的使用总结
一 默认绑定:
当直接调用一个函数的时候,就叫做默认绑定
1.非严格模式下,默认绑定到window上
2.严格模式下,this默认绑定到underfined
二 隐式绑定
当使用对象.方法()的时候,这种方式调用.我们称之为隐式绑定
this绑定到前面那个对象上
三 new绑定
使用new来调用构造函数的方式,new绑定
this是绑定在创建的那个对象上
四 显示绑定
call,apply(除接受参数不一样外,几乎一样)
都是一锤子买卖,仅仅这一次调用的时候使用了显示绑定,对原函数没有任何的影响
call和apply的区别,就是参数的传递方式
call的函数式是一个一个的传递
apply是吧要传递的参数封装到一个数组去传递
bind 固定绑定
调用函数对象bind方法,返回一个固定this绑定的新的函数
对原来的函数没有影响
bind > apply,call > new > 隐式
this绑定的丢失问题
<script>
var name = "zs";
var obj = {
name : ["张三","李四"],
// show:function () {
// var self = this;
// setInterval(function () {
// console.log(self.name);
// },1000)
// }
show:function () {
setInterval(function () {
document.write(this.name);
}.bind(this),1000);
}
}
obj.show();
</script>