Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS面向对象总结【封装,继承,多态,this,prototype】(笔记) #2

Open
Kelichao opened this issue Oct 20, 2016 · 4 comments

Comments

@Kelichao
Copy link
Owner

Kelichao commented Oct 20, 2016

了解面向对象三大特征之前,对于抽象的了解十分重要,在定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。

封装(encapsulation )

function Person(name, age) {
    this.name = name;
    var age = age;// 在实例中无法被调用
}
var p1 = new Person("Bob", 20);
console.log(p1) // Person ->{name: "Bob"}  无法访问到age属性,这就叫被封(装)起来了。

访问封装属性的方法--特权方法

function Person(age) {
    var age = age;// 私有变量
    this.showAge = function() {// 特权方法
        console.log(age);
    };
}
var p1 = new Person(20);// 新建对象p1
p1.showAge();// -> 20  这个20是闭包,在闭包笔记处会详解。
// 如果不理解闭包,按照我自己的思路很难去解释:
// 为什么这个函数体里面存了一份age的数据。

但是如果使用prototype来写的函数,无法访问私有变量

Person.prototype.myAge = function() {
    console.log(age);
};
var p1 = new Person(20);// 新建对象p1
p1.myAge();// 报错 age is not defined

其实这也印证了:闭包就是函数里面包函数,由于prototype是通过函数名,指到其他内存空间独立的函数体,因此没法取得闭包的作用域变量。

继承

将不同类的相同之处取出封装成独立的类

1.对象冒充方法 (有缺陷,在继承笔记详细介绍)

function Stu() {
    this.name = "学生";
}
Stu.prototype.free = function() {
    console.log("free");
};
function MidStu() {
    this.stu = Stu;// 将Stu函数体赋值给stu;

    /*
     * 执行stu里面的函数体
     * 就相当于执行了这句话 :this.name = "学生";
     */
    this.stu();// 通过对象冒充,来实现继承。
delete this.stu;// 删除对象的引用。
}

var stu1 = new MidStu();
console.log(stu1);  // 拥有这个属性 this.name = "学生";
stu1.free(); //prototype的free这个属性不存在

多态

所谓多态,就是指一个引用类型在不同情况下的多种状态。在java中多态是指通过指向父类的引用,来调用在不同子类中实现的方法。
js实际上是无态的,是一种动态语言,一个变量的类型是在运行的过程中由js引擎来决定的,所以说js天生就支持多态。

image

    // 主人类
    function Master() {
        // 主人玩耍动物
        this.feed = function(animal) {
            console.log("主人玩耍" + animal.name);
            console.log("类:" + animal.constructor);
        };
    }

    // 猫类
    function Cat(name) {
        this.name = name;
    }

    // 狗类
    function Dog(name) {
        this.name = name;
    }

    var cat = new Cat("小猫咪");
    var dog = new Dog("小狗狗");
    var master = new Master();

    master.feed(cat);
    master.feed(dog);
    // 这样做的优点在于Master不需要改变,如果要扩展加入其它的动物,
    // 只需要加一个猴子类就好了

Javascript-面向(基于)对象编程-介绍

  • Javascript-是采用基于对象(面向对象)来编程的。
  • Javascript-中没有Class类(原型对象) tip:有人直接就叫类了。

如果要得到一个cat1(猫1)对象

var cat1 = {};
cat1.age = 1;
cat1.name = "小白";
cat1.voice = "喵";
// 得到 cat1 = {age: 1, name: "小白",voice :"喵"};

但是要写出cat2,cat3则需要很多的代码

var cat2 = {};
cat2.age = 2;
cat2.name = "小白";
cat2.voice = "喵";
// 得到 cat2 = {age: 2, name: "小白",voice :"喵"};

var cat3 = {};
cat3.age = 3;
cat3.name = "小白";
cat3.voice = "喵";
// 得到 cat3 = {age: 3, name: "小白",voice :"喵"};

接着来描述下创建类(原型对象)的方式:5种

  1. 工厂方法--使用new Object创建对象并添加相关属性。
  2. 使用构造函数来定义类(原型对象)。
  3. 使用prototype
  4. 构造函数及原型混合方式
  5. 动态原型方式

重点是第二种方式写法

function 类名/原型对象名 (){

}
// 创建对象
var 对象名 = new 类名();

function aaa() {
    console.log(this.bbb);// 可以输出bbb这个函数,说明bbb函数也被提前执行
    this.a = console.log(111);
}

// 注意点,bbb这个函数在new的时候会被提前加载,在console.log(this.bbb)这句话中可以输出函数体
aaa.prototype.bbb = function() {
    console.log(222);
};

new aaa();

那么如何判断实例是属于什么类?

// 我自己定义的类
function Person() {}
var Bob = new Person();
console.log(Bob.constructor);
// function Person() {}
console.log(typeof Bob);
// object

// 系统的类number
var bbb = 12345; // -> var bbb = new Nmuber(12345);
console.log(bbb.constructor);
// function Number() { [native code] }
console.log(typeof bbb);
// number

Javascript-中一切都是对象

function Person() {}
console.log(Person.constructor);

//  函数的类为 Function() { [native code] }

如何判断一个对象实例是不是Person类型

function Person() {}
var Bob = new Person();
// instanceof  实例
console.log(Bob instanceof Person) // true   instanceof 还可以用来判断复杂类型对象的归属
console.log(Person === Bob.constructor);   // true

delete 用于删属性 delete cat1.name 注:不能直接删cat1对象,不能删除window上面的属性。

@Kelichao
Copy link
Owner Author

Kelichao commented Oct 20, 2016

this 的提出

function Person() {

}
var p1 = new Person();
p1.name = "顺平";

var p2 = new Person();
console.log(p2.name); // -> undefined

当我们创建一个对象后,希望该对象自动拥有某些属性,比如有个初始 name

function Person() {
    this.name = "初始名"
}
var p1 = new Person();
var p2 = new Person();
console.log(p1.name + " : " + p2.name); // -> “初始名”,两个实例对象的name属性相互对立不影响。

我在这里先对比下有new 跟没有new的区别

function Person() {
        this.name = "初始名";
        console.log(this);
} 

var p1 = Person(); // 打出的是window对象
var p1 = new Person();  //1 打出的是 新Person;2而且返回值为this。其他不同点暂时还没有发现。

有new下的this指向
image

在我目前看来,new 一个构造函数,返回的是一个this,本质上我觉得是重新开辟了一个内存空间给新生的Person然后通过给变量赋值,以及开辟了一个空间给原型对象prototype,以用来存储。比如p1 = 新Person,拿到新Person的地址,得到对象所拥有的方法。

function Person() {
        this.name = "初始名";
}
console.log(new Person() ) // 返回值是this

p只是记录了这个引用对象的地址。
image
p记录的是ox1234的地址,所以在调用abc()的时候调用的是ox1234的abc,this指向的就是ox1234
image

如果将返回值改为引用类型,则会改变返回值,注:return 123;这种不生效

function Person() {
        this.name = "初始名"
        return [];
}
console.log(new Person()) // ->[ ]

this只能在类的内部使用。

总结一下,是什么决定this最终的指向,this最终的指向永远是离方法最近的那个引用类型的那个对象。

var name = "window";
var myname = function() {
    console.log(this.name);
};
var value = {
    a: {
        name: "a",
        myname: function() {
            console.log(this.name);
        },
        b: {
            name: "b",
            myname: function() {
                console.log(this.name);
            }
        }
    }
};

/*
* window
* a
* b
* 这三者都是引用对象
*/
window.myname();// window
window.value.a.myname();// a
window.value.a.b.myname();//b

@Kelichao
Copy link
Owner Author

Kelichao commented Oct 20, 2016

成员函数(成员方法)

function Person(name, age) {

    /*
     * 传入实际的参数去初始化属性时用到。
     * 适用于每个对象都有的,但是里面的内容不一样的。
 * 好处是可以在初始化对象(new)时使用传入的参数
 * 缺点是每个对象都有自己的一份配置,不共用 
     */
    this.name = name;
    this.age = age;
}

var p1 = new Person("林冲", 30);
var p2 = new Person("宋江", 40);
console.log(p1.name + ":" + p2.name); // -> 林冲:宋江

对于函数赋值, 之前没有尝试过这种方法,也是可以用的

var x = function aaa() {
   console.log("good");
};
console.log(x);
// -> 打出的是有名字的函数,跟匿名函数不一样
//function aaa() {
//   alert();
//}
x(); // -> good
// var x = aaa= function() {
//  console.log()
// }

//等同
function aaa() {
   console.log("good");
}
var x = aaa;

验证通过this制造的函数体是否独立

function Person() {
    this.aaa = function(value) {};
}

var p1 = new Person();
var p2 = new Person();
console.log(p1.aaa === p2.aaa);  // false

prototype 原型链 (也是成员方法)

通过shout函数名 来调用函数体,公用
image
验证通过this制造的函数体是否独立

function Person() {}
/*
 *  缺点是不可以在初始化对象(new)时使用传入的参数
 * 优点是每个对象都公用这有一份属性,节流 
*
*/
Person.prototype.aaa = function(value) {};

var p1 = new Person();
var p2 = new Person();
console.log(p1.aaa === p2.aaa); // true

@Kelichao Kelichao changed the title JS面向对象总结(笔记) JS面向对象总结【this,prototype】(笔记) Oct 21, 2016
@Kelichao Kelichao changed the title JS面向对象总结【this,prototype】(笔记) JS面向对象总结【封装,继承,多态,this,prototype】(笔记) Oct 28, 2016
@hufans
Copy link

hufans commented Jun 13, 2018

写得不错,star

@WriteProtectX
Copy link

了解面向对象三大特征之前,对于抽象的了解十分重要,在定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。

封装(encapsulation )

function Person(name, age) {
    this.name = name;
    var age = age;// 在实例中无法被调用
}
var p1 = new Person("Bob", 20);
console.log(p1) // Person ->{name: "Bob"}  无法访问到age属性,这就叫被封(装)起来了。

访问封装属性的方法--特权方法

function Person(age) {
    var age = age;// 私有变量
    this.showAge = function() {// 特权方法
        console.log(age);
    };
}
var p1 = new Person(20);// 新建对象p1
p1.showAge();// -> 20  这个20是闭包,在闭包笔记处会详解。
// 如果不理解闭包,按照我自己的思路很难去解释:
// 为什么这个函数体里面存了一份age的数据。

但是如果使用prototype来写的函数,无法访问私有变量

Person.prototype.myAge = function() {
    console.log(age);
};
var p1 = new Person(20);// 新建对象p1
p1.myAge();// 报错 age is not defined

其实这也印证了:闭包就是函数里面包函数,由于prototype是通过函数名,指到其他内存空间独立的函数体,因此没法取得闭包的作用域变量。

继承

将不同类的相同之处取出封装成独立的类

1.对象冒充方法 (有缺陷,在继承笔记详细介绍)

function Stu() {
    this.name = "学生";
}
Stu.prototype.free = function() {
    console.log("free");
};
function MidStu() {
    this.stu = Stu;// 将Stu函数体赋值给stu;

    /*
     * 执行stu里面的函数体
     * 就相当于执行了这句话 :this.name = "学生";
     */
    this.stu();// 通过对象冒充,来实现继承。
delete this.stu;// 删除对象的引用。
}

var stu1 = new MidStu();
console.log(stu1);  // 拥有这个属性 this.name = "学生";
stu1.free(); //prototype的free这个属性不存在

多态

所谓多态,就是指一个引用类型在不同情况下的多种状态。在java中多态是指通过指向父类的引用,来调用在不同子类中实现的方法。
js实际上是无态的,是一种动态语言,一个变量的类型是在运行的过程中由js引擎来决定的,所以说js天生就支持多态。

image

    // 主人类
    function Master() {
        // 主人玩耍动物
        this.feed = function(animal) {
            console.log("主人玩耍" + animal.name);
            console.log("类:" + animal.constructor);
        };
    }

    // 猫类
    function Cat(name) {
        this.name = name;
    }

    // 狗类
    function Dog(name) {
        this.name = name;
    }

    var cat = new Cat("小猫咪");
    var dog = new Dog("小狗狗");
    var master = new Master();

    master.feed(cat);
    master.feed(dog);
    // 这样做的优点在于Master不需要改变,如果要扩展加入其它的动物,
    // 只需要加一个猴子类就好了

Javascript-面向(基于)对象编程-介绍

  • Javascript-是采用基于对象(面向对象)来编程的。
  • Javascript-中没有Class类(原型对象) tip:有人直接就叫类了。

如果要得到一个cat1(猫1)对象

var cat1 = {};
cat1.age = 1;
cat1.name = "小白";
cat1.voice = "喵";
// 得到 cat1 = {age: 1, name: "小白",voice :"喵"};

但是要写出cat2,cat3则需要很多的代码

var cat2 = {};
cat2.age = 2;
cat2.name = "小白";
cat2.voice = "喵";
// 得到 cat2 = {age: 2, name: "小白",voice :"喵"};

var cat3 = {};
cat3.age = 3;
cat3.name = "小白";
cat3.voice = "喵";
// 得到 cat3 = {age: 3, name: "小白",voice :"喵"};

接着来描述下创建类(原型对象)的方式:5种

  1. 工厂方法--使用new Object创建对象并添加相关属性。
  2. 使用构造函数来定义类(原型对象)。
  3. 使用prototype
  4. 构造函数及原型混合方式
  5. 动态原型方式

重点是第二种方式写法

function 类名/原型对象名 (){
}
// 创建对象
var 对象名 = new 类名();

function aaa() {
    console.log(this.bbb);// 可以输出bbb这个函数,说明bbb函数也被提前执行
    this.a = console.log(111);
}

// 注意点,bbb这个函数在new的时候会被提前加载,在console.log(this.bbb)这句话中可以输出函数体
aaa.prototype.bbb = function() {
    console.log(222);
};

new aaa();

那么如何判断实例是属于什么类?

// 我自己定义的类
function Person() {}
var Bob = new Person();
console.log(Bob.constructor);
// function Person() {}
console.log(typeof Bob);
// object

// 系统的类number
var bbb = 12345; // -> var bbb = new Nmuber(12345);
console.log(bbb.constructor);
// function Number() { [native code] }
console.log(typeof bbb);
// number

Javascript-中一切都是对象

function Person() {}
console.log(Person.constructor);

//  函数的类为 Function() { [native code] }

如何判断一个对象实例是不是Person类型

function Person() {}
var Bob = new Person();
// instanceof  实例
console.log(Bob instanceof Person) // true   instanceof 还可以用来判断复杂类型对象的归属
console.log(Person === Bob.constructor);   // true

delete 用于删属性 delete cat1.name 注:不能直接删cat1对象,不能删除window上面的属性。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants