js学习之面向对象

一、创建对象的方法


1、 {} 字面量创建

        var person ={
            name: "lisi",
            age: 21,
            say: function(){
                alert(this.name);
            }
        };


2、 new Object()

var person = new Object();
person.name = "lisi";
person.age = 21;
person.family = ["lida","lier","wangwu"];
person.say = function(){
       alert(this.name);
}

3: 用构造函数创建

function Person(name,age,family) {
    this.name = name;
    this.age = age;
    this.family = family;
    this.say = function(){
        alert(this.name);
    }
}
var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
var person2 = new Person("lisi",21,["lida","lier","lisi"]);
console.log(person1 instanceof Object); //true
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Object); //true
console.log(person2 instanceof Person); //trueconsole.log(person1.constructor);      //constructor 属性返回对创建此对象的数组、函数的引用


4:Object.create方法创建
创建完的对象有2个特点
1、 可以添加属性 (属性的值为非函数的任意数据类型)
2、 添加方法

const person = {
    isHuman: false,
    say: function () {
        console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
    }
};

const me = Object.create(person); //使用现有的对象来提供新创建的对象的__proto__

5、工厂模式

function createPerson(name,age,family) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.family = family;
    o.say = function(){
        alert(this.name);
    }
    return o;
}

var person1 =  createPerson("lisi",21,["lida","lier","wangwu"]);   //instanceof无法判断它是谁的实例,只能判断他是对象,构造函数都可以判断出
var person2 =  createPerson("wangwu",18,["lida","lier","lisi"]);console.log(person1 instanceof Object); //true

6、原型模式

function Person() {}

Person.prototype.name = "lisi";
Person.prototype.age = 21;
Person.prototype.family = ["lida","lier","wangwu"];
Person.prototype.say = function(){
    alert(this.name);
};
console.log(Person.prototype);   //Object{name: 'lisi', age: 21, family: Array[3]}

var person1 = new Person();        //创建一个实例person1
console.log(person1.name);        //lisi

var person2 = new Person();        //创建实例person2
person2.name = "wangwu";
person2.family = ["lida","lier","lisi"];P9
console.log(person2);            //Person {name: "wangwu", family: Array[3]}
// console.log(person2.prototype.name);         //报错
console.log(person2.age);              //21

7、混合模式(构造函数模式+原型模式)

构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性
function Person(name,age,family){
    this.name = name;
    this.age = age;
    this.family = family;
}

Person.prototype = {
    constructor: Person,  //每个函数都有prototype属性,指向该函数原型对象,原型对象都有constructor属性,这是一个指向prototype属性所在函数的指针
    say: function(){
        alert(this.name);
    }
}

var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
console.log(person1);
var person2 = new Person("wangwu",21,["lida","lier","lisi"]);
console.log(person2);


new的工作原理


  通过new创建对象经历4个步骤

  1、创建一个新对象;[var o = {};] //创建一个空对象obj,然后把这个空对象的__proto__设置为Person.prototype(即构造函数的prototype);

  2、将构造函数的作用域赋给新对象 (因此this指向了这个新对象);[Person.apply(o)] [Person原来的this指向的是window]

  3、执行构造函数中的代码(为这个新对象添加属性);

  4、返回新对象

  // 1)创建一个新的对象;
  // 2)将构造函数的 this 指向这个新对象;
  // 3)为这个对象添加属性、方法等;
  // 4)最终返回新对象。

什么是面向对象编程(OOP)?

面向过程与面向对象
  1)面向过程:面向过程专注于如何去解决一个问题的过程步骤。编程特点是由一个个函数去实现每一步的过程步骤,没有类和对象的概念。
  2)面向对象:专注于由哪一个对象来解决这个问题,编程特点是出现了一个类,从类中拿到对象,由这个对象去解决具体问题。 对于调用者来说,面向过程需要调用者自己去实现各种函数。而面向对象,只需要告诉调用者,对象中具体方法的功能,而不需要调用者了解方法中的实现细节。

  

面向对象的三大特征

  面向对象的三大特征是继承封装多态。JS可以模拟实现继承和封装,但是无法模拟实现多态,所以我们说JS是一门基于对象的语言,而非是面向对象的语言。

  封装:封装就是指利用抽象数据类型将数据和基于数据的操作封装在一起,数据被保护在抽象类型的内部,系统的其他部分只有通过包裹在数据外面的被授权的操作,才能够与这个抽象数据类型交流与交互!

  继承:继承实际上是存在于面向对象程序中的两个类之间的关系。当一个类拥有另一个类的所有数据和操作时,就称这两个类之间具有继承关系!

  多态:多态是指一个程序中同名的不同方法共存的情况。面向对象的程序中多态的情况有多种,可以通过子类对父类方法的覆盖实现多态,也可以利用重载在同一个类中定义多个同名的不同方法!
 

  1、封装

   什么是Js封装,就是当你需要隐藏一些属性和方法是,就可以将这些属性和方法封装起来,然后通过一个外部可以调用的特定接口(也可以说是一个公共的方法)进行调用。

  2、继承
    原型,原型链

  3、多态
    多态是指一个程序中同名的不同方法共存的情况。

  

function Person(name, age, sex) {
    this.name = name; //共有变量 
    var age = age; //私有变量
    var sex = sex; //私有变量
    this.show = function () {
        console.log(age + "====" + sex);
    }
}
var person = new Person('Sunshine', 18, ''); console.log(person.age); // undefined console.log(person.name); // Sunshine console.log(person.show()); // 18====女

  注:this指向的都是共有的属性和方法,而直接通过var声明的则属于私有变量(即外部不可访问变量),然后通过一个共有的show方法将私有的age和sex输出。当然show方法也要通过this声明才可以哟,否则的话show方法也是不可访问的。

类和对象
1、:一类具有相同特征(属性)和行为(方法)的集合。
比如,人类具有身高、体重等属性,吃饭、大笑等行为,所以,我们可以把人划分为一类。


2、对象:从类中,拿出具有确定属性值和方法的个体。
比如,张三-->属性:身高180体重180 方法:说话-->我叫张三,身高180

3、类和对象的关系

①类是抽象的,对象是具体的(类是对象的抽象化,对象是类的具体化)

②类是一个抽象的概念,只能说类有属性和方法,但是不能给属性赋具体的。比如,人类有姓名,但是不能说人类的姓名叫什么。
  对象是一个具体的个例,是将类中的属性进行具体赋值而来的个体。
  比如,张三是一个人类的个体。可以说张三的姓名叫张三。也就是张三对人类的每一个属性进行了具体的赋值,那么张三就是由人类产生的一个对象。

4、使用类和对象的步骤:
1)创建一个类(构造函数):类名必须使用大驼峰法则。即每个单词首字母都要大写

function 类名(属性1){
    this.属性1=属性1;
    this.方法=function(){
    //方法中要调用自身属性,必须使用this.属性
    }
}


2)通过类实例化(new)出一个对象。

var obj=new 类名(属性1的具体值);
obj.属性; 调用属性
obj.方法; 调用方法


3)注意事项:
①通过类名,new出一个对象的过程,叫做"类的实例化"。
②类中的this,会在实例化的时候,指向新new出的对象。
  所以,this.属性 this.方法实际上是将属性和方法绑定在即将new出的对象上面。
③在类中,要调用自身属性,必须使用this.属性名。如果直接使用变量名,则无法访问对应的属性。

function Person(name,age){
    this.name=name;
    this.age=age;
    this.say=function(content){
        //在类中,访问类自身的属性,必须使用this.属性调用。
        alert("我叫"+this.name+",今年"+this.age+"岁,我说了一句话:"+content);
    }
}
var zhangsan=new Person("姐姐",18);
zhangsan.say("你好呀");

类名必须使用大驼峰法则,注意与普通函数区分。

面向对象的两个重要属性

1)constructor:返回当前对象的构造函数。

2)instanceof:检测一个对象是不是一个类的实例;

>>>lisi instanceof Person          //true √ lisi是通过Person类new出的
>>>lisi instanceof Object          //true √ 所有对象都是Object的实例
>>>Person instanceof Object        //true √ 函数本身也是对象


成员属性、静态属性和私有属性
1、在构造函数中,使用this.属性声明。或者在实例化出对象以后,使用"对象.属性"追加的,都属于"成员属性或成员方法"。也叫"实例属性或实例方法"。
  成员属性/方法,是属于由类new出的对象的。
  需要使用"对象名.属性名"调用。

【静态属性与静态方法】
2、通过“类名.属性名”、“类名.方法名”声明的属性和方法,称为静态属性、静态方法。也叫类属性和类方法。
  类属性/类方法,是属于类的(属于构造函数的)
  通过"类名.属性名"调用。

3、成员属性是属于实例化出的对象的,只能使用对象调用。
  静态属性是属于构造函数的,只能使用类名调用。

[私有属性和私有方法]


4、在构造函数中,使用var声明的变量称为私有属性;
  在构造函数中,使用function声明的函数,称为私有方法;

function Person(){
    var num=1;//私有属性
    function func(){}//私有方法
}

私有属性和私有方法的作用域,只在构造函数内容有效。即只能在构造函数内部使用,在构造函数外部,无论使用对象名还是类名都无法调用。

JavaScript中的this指向详解

1、谁最终调用函数,this最终指向谁(记住!)

①this指向谁,不应考虑函数在哪声明,而应该考虑函数在哪调用!!!
②this指向的永远只可能是对象,而不可能是函数。
③this指向的对象,叫做函数的上下文context,也叫函数的调用者。


2、this指向的规律!!!(跟函数的调用方式息息相关,记住这点,相信你一定会分清this指向哒)
①通过函数名()调用的,this永远指向window
②通过对象.方法调用的,this指向这个对象。
③函数作为数组中的一个元素,用数组下标调用的,this指向这个数组
④函数作为window内置函数的回调函数使用,this指向window。 setInterval setTimeout 等。
⑤函数作为构造函数,使用new关键字调用,this指向新new出的对象。

var fullname = 'John Doe';
var obj = {
    fullname: 'Colin Ihrig',
    prop: {
        fullname: 'Aurelio De Rosa',
        getFullname: function () {
            return this.fullname;
        }
    }
};

console.log(obj.prop.getFullname()); //Aurelio De Rosa
// 函数的最终调用者 obj.prop 

var test = obj.prop.getFullname;
console.log(test()); //John Doe
// 函数的最终调用者 test()  this-> window

obj.func = obj.prop.getFullname;
console.log(obj.func()); //Colin Ihrig
// 函数最终调用者是obj

var arr = [obj.prop.getFullname, 1, 2];
arr.fullname = "JiangHao";  //JiangHao
console.log(arr[0]()); // 函数最终调用者数组

class 与构造函数的区别?

  构造函数

function Circle (x, y, r, color) {
        this.x = x
        this.y = y
        this.r = r
        this.color = color
      }
 
      Circle.prototype.render = function () {
        ctx.beginPath()
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true)
        ctx.fillStyle = this.color
        ctx.fill()
      }
 
      Circle.prototype.update = function () {
        this.x += 1
      }

  class

class Circle {
        constructor (x, y, r, color) {
          this.x = x
          this.y = y
          this.r = r
          this.color = color
        }
        render () {
          ctx.beginPath()
          ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true)
          ctx.fillStyle = this.color
          ctx.fill()
        }
        update () {
          this.x += 1
        }
      }
原文地址:https://www.cnblogs.com/zjz666/p/11349226.html