美文网首页
JavaScript-9面向对象

JavaScript-9面向对象

作者: 想成为大牛的程旭元 | 来源:发表于2020-10-12 16:59 被阅读0次
    JavaScript对象
    1. JavaScript中提供了一个默认的类Object, 我们可以通过这个类来创建对象
    2. 由于我们是使用系统默认的类创建的对象, 所以系统不知道我们想要什么属性和行为, 所以我们必须手动的添加我们想要的属性和行为
    3. 如何给一个对象添加属性
    对象名称.属性名称 = 值;
    
    1. 如何给一个对象添加行为
    对象名称.行为名称 = 函数;
    

    5.1 创建对象的第一种方式

    let obj = new Object();
    obj.name = "lnj";
    obj.age = 33;
    obj.say = function () {
        console.log("hello world");
    }
    console.log(obj.name);
    console.log(obj.age);
    obj.say();
    

    5.2 创建对象的第二种方式

    let obj = {}; // let obj = new Object();
    obj.name = "lnj";
    obj.age = 33;
    obj.say = function () {
        console.log("hello world");
    }
    console.log(obj.name);
    console.log(obj.age);
    obj.say();
    

    5.3 创建对象的第三种方式

    属性名称和取值之间用冒号隔开, 属性和属性之间用逗号隔开

    let obj = {
        name: "lnj",
        age: 33,
        say: function () {
            console.log("hello world");
        }
    };
    console.log(obj.name);
    console.log(obj.age);
    obj.say();
    
    函数和方法区别
    1. 什么是函数?
    • 函数就是没有和其它的类显示的绑定在一起的, 我们就称之为函数
    function demo() {
        console.log("hello demo");
    }
    demo();
    
    1. 什么是方法?
    • 方法就是显示的和其它的类绑定在一起的, 我们就称之为方法
    let obj = {
          name: "lnj",
          test: function () {
              console.log(this);  //{name: "lnj", test: ƒ} 打印当前obj对象
          }
    obj.test();
    
    1. 函数和方法的区别
    • 函数可以直接调用, 但是方法不能直接调用, 只能通过对象来调用
    • 函数内部的this输出的是window, 方法内部的this输出的是当前调用的那个对象
    查看1和2打印this 的结果,就知道了
    
    1. 无论是函数还是方法, 内部都有一个叫做this的东东
    • this是什么? 谁调用了当前的函数或者方法, 那么当前的this就是谁

    构造函数

    1. 什么是构造函数?
      构造函数和工厂函数一样,都是用来创建对象的,构造函数本质上是工厂函数的缩写。
    2. 构造函数和工厂函数区别
    • 构造函数的函数名首字母大写
    • 构造函数只能通过new来调用
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script>
            function Person(myName,myAge){
                this.myName = myName;
                this.myAge = myAge;
                this.say = function(){
                    console.log("hello word")
                }
            }
            let obj1 = new Person('张三',33)    //Person {myName: "张三", myAge: 33, say: ƒ}
            let obj2 = new Person('李四',44)    //Person {myName: "李四", myAge: 44, say: ƒ}
    
            console.log(obj1)
            console.log(obj2)
        </script>
    </head>
    <body>
        
    </body>
    </html>
    

    逻辑说明

    1. 当我们new Person('张三',33)的时候,系统做了什么?
      1.1 会在构造函数中自动创建一个对象
    let obj = new Object();  // 系统自动添加的
    

    1.2 会自动将刚才创建的对象赋值给this

    let this = obj; // 系统自动添加的
    

    1.3 会在构造函数的最后自动添加return this;

    this.say = function(){
          console.log("hello word")
    }
    return this;
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script>
            function Person(myName,myAge){
                this.myName = myName;
                this.myAge = myAge;
                this.say = function(){
                    console.log("hello word")
                }
            }
            let obj1 = new Person('张三',33)    //Person {myName: "张三", myAge: 33, say: ƒ}
            let obj2 = new Person('李四',44)    //Person {myName: "李四", myAge: 44, say: ƒ}
    
            console.log(obj1)
            console.log(obj2)
            //由于两个对象中的say方法的实现都是一样的, 但是保存到了不同的存储空间中
            console.log(obj1.say === obj2.say); // false
    
        </script>
    </head>
    <body>
        
    </body>
    </html>
    
    • 通过三个等号来判断两个函数名称, 表示判断两个函数是否都存储在同一块内存中
    prototype(pro tou type)
    1. prototype特点
    • 存储在prototype里面的方法可以被对应构造函数创建出来的所有对象共享
      写法:
    对象名称(大写). prototype = {}
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script>
            function Person(myName,myAge){
                this.myName = myName;
                this.myAge = myAge;
            }
            Person.prototype = {
                say(){
                    console.log("hello word")
                }
            }
            let obj1 = new Person('张三',33)
            let obj2 = new Person('李四',44)
    
            console.log(obj1.say === obj2.say)  // true
        </script>
    </head>
    <body>
        
    </body>
    </html>
    
    obj1.say === obj2.say是同一个地址,所以返回true
    
    • 除了存储方法外,还可以存储属性
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script>
            function Person(myName,myAge){
                this.myName = myName;
                this.myAge = myAge;
            }
            Person.prototype = {
                currentType:"人",
                say(){
                    console.log("hello word")
                }
            }
            let obj1 = new Person('张三',33)
            let obj2 = new Person('李四',44)
    
            console.log(obj2.currentType)  // 人
            console.log(obj2.currentType)  // 人
        </script>
    </head>
    <body>
        
    </body>
    </html>
    
    currentType就是属性
    
    • prototype中如果出现了和构造函数中同名的属性和方法,对象在访问的时候,访问到的 是构造函数中的数据
    对象三角恋关系
    • 每个构造函数中都有一个默认的属性, 叫做prototype, prototype属性保存着一个对象, 这个对象我们称之为原型对象
    • 每个"原型对象"中都有一个默认的属性, 叫做constructor,constructor指向当前原型对象对应的那个构造函数
    • 通过构造函数创建出来的对象我们称之为"实例对象",每个"实例对象"中都有一个默认的属性, 叫做__proto____proto__指向创建它的那个构造函数的 原型对象
    Prototype-三角恋关系.png
    function Person(myName, myAge) {
        this.name = myName;
        this.age = myAge;
    }
    let obj1 = new Person("lnj", 34);
    
    console.log(Person.prototype);      //  {constructor: ƒ}
    console.log(Person.prototype.constructor);
    /*
    上面打印结果
     Person(myName, myAge) {
                this.name = myName;
                this.age = myAge;
            }
    */
    
    console.log(obj1.__proto__);
    /*
    上面打印结果
    {constructor: ƒ}
    constructor: ƒ Person(myName, myAge)
    __proto__: Object
    */
    

    感谢大牛分享
    帮你彻底搞懂JS中的prototype、proto与constructor(图解)
    详解JavaScript中的new操作符

    Function函数
    • JavaScript中函数是引用类型(对象类型), 既然是对象,所以也是通过构造函数创建出来的,"所有函数"都是通过Function构造函数创建出来的对象
    • JavaScript中只要是"函数"就有prototype属性,"Function函数"的prototype属性指向"Function原型对象"
    • JavaScript中只要"原型对象"就有constructor属性,"Function原型对象"的constructor指向它对应的构造函数
    • Person构造函数是Function构造函数的实例对象, 所以也有__proto__属性,Person构造函数的__proto__属性指向"Function原型对象"
    function Person(myName, myAge) {
        this.name = myName;
        this.age = myAge;
    }
    let obj1 = new Person("lnj", 34);
    
    console.log(Function);
    
    console.log(Function.prototype);
    
    console.log(Function.prototype.constructor);
    
    console.log(Function === Function.prototype.constructor); // true
    
    console.log(Person.__proto__);
    
    console.log(Person.__proto__ === Function.prototype); // true
    
    Object函数
    ƒ Object() { [native code] }
    
    1. 所有函数都是Function函数的实例,Object构造函数,就是Function构造函数的实例对象,只要是对象就有__proto__,
    console.log(Object.__proto__);   ------> ƒ () { [native code] }
    
    console.log(Object.__proto__ == Function.prototype);  ------>true
    
    
    1. Object的原型对象,里面的__proto__指向的为null
    console.log(Object.prototype.__proto__);  -------> null
    
    Object函数.png
    函数对象完整关系图
    1. Function函数是所有函数的祖先函数
    2. 所有构造函数都有一个prototype属性,所有prototype属性都指向自己的原型对象
    3. 所有构造函数都有一个constructor属性,所有constructor属性都指向自己的构造函数
    4. 所有函数都是对象,包括Function构造函数
    5. 所有对象都有一个__proto__属性
    6. 普通对象的__proto__属性指向创建它的那个构造函数对应的"原型对象"
    7. 所有对象的__proto__属性最终都会指向"Object原型对象"
    8. "Object原型对象"的__proto__属性指向NULL
    function Person(myName, myAge) {
        this.name = myName;
        this.age = myAge;
    }
    let obj1 = new Person("lnj", 34);
    
    //Function构造函数的原型对象的,原型对象
    console.log(Function.prototype.__proto__);
    //Person构造函数的原型对象的,原型对象
    console.log(Person.prototype.__proto__);
    //Person构造函数的原型对象的,原型对象和Function构造函数的原型对象的,原型对象,是不是指向同一个,指向的是同一个
    console.log(Function.prototype.__proto__ === Person.prototype.__proto__);  //true
    //Object构造函数的原型对象的,原型对象和Function构造函数的原型对象的,原型对象,是不是指向同一个,指向的是同一个
    console.log(Function.prototype.__proto__ === Object.prototype);  //true
    //Object构造函数的原型对象的,原型对象和Person构造函数的原型对象的,原型对象,是不是指向同一个,指向的是同一个
    console.log(Person.prototype.__proto__ === Object.prototype);  //true
    
    函数对象完整关系图.png

    注意点:为了不破坏原有的关系,在给protorype赋值的时候,需要在自定义的对象中手动的添加constructor属性,手动的添加需要指向谁。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>函数对象关系</title>
        <script>
            function Person(myName, myAge) {
                this.name = myName;
                this.age = myAge;
            }
            Person.prototype = {
                currenType:'哈哈',
                say:function(){
                    console.log('hello word')
                }
            }
            let obj1 = new Person("lnj", 34);
            console.log(Person.prototype.constructor); ------>ƒ Object() { [native code] }
        </script>
    </head>
    <body>
    
    </body>
    </html>
    

    上看的代码打印可以看出,Person.prototype.constructor指向的是Object函数,指向错了。破坏了原来的指向关系,手动添加一个指向,修改成下面的代码,

    //原型对象
    Person.prototype = {
         constructor:Person,
         currenType:'哈哈',
         say:function(){
            console.log('hello word')
        }
    }
    

    再执行上面的打印结果为,

    ƒ Person(myName, myAge) {
          this.name = myName;
          this.age = myAge;
    }
    

    对象查找方法和属性是怎么查找的---原型链

    1. 什么叫原型链
    • 对象中__proto__组成的链条我们称之为原型链
    1. 对象查找方法和属性是怎么查找的
    • 对象在查找属性和方法的时候, 会先在当前对象查找
      如果当前对象中找不到想要的, 会依次去上一级原型对象中查找
      如果找到Object原型对象都没有找到, 就会报错
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>原型链</title>
        <script>
            function Person(myName, myAge) {
                this.name = myName;
                this.age = myAge;
                this.currentType = "构造函数中的type";
                this.say = function () {
                    console.log("构造函数中的say");
                }
            }
    
            Person.prototype = {
                // 注意点: 为了不破坏原有的关系, 在给prototype赋值的时候, 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁
                constructor: Person,
                 currentType: "人",
                 say: function () {
                    console.log("hello world");
                 }
            }
            let obj1 = new Person("lnj", 34);
            obj1.say();      //构造函数中的say
            console.log(obj1.currentType);    //构造函数中的type
            // console.log(Person.prototype.constructor);
        </script>
    </head>
    <body>
    
    </body>
    </html>
    
    obj1.say(); 和 console.log(obj1.currentType); 
    如果把function Person(myName, myAge) {}这里面的say和currentType注释掉,那么就会打印prototype里面的,如果把prototype里面的注释掉,就会报错,因为prototype里再往上查找,就到Object里面的了
    

    注意点:在给一个对象不存在的属性设置值的时候,不会去原型对象中查找,如果当前对象没有,就会给当前对象新增一个不存在的属性。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>属性注意点</title>
        <script>
            function Person(myName, myAge) {
                this.name = myName;
                this.age = myAge;
            }
            Person.prototype = {
                constructor: Person,
                currentType: "人",
                say: function () {
                    console.log("hello world");
                }
            }
            let obj = new Person("lnj", 34);
            // console.log(obj.currentType); // "人"
            // console.log(obj.__proto__.currentType); // "人"
    
            // 注意点: 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性
            obj.currentType = "新设置的值";
            console.log(obj.currentType); // 新设置的值
            console.log(obj.__proto__.currentType); // "人"
        </script>
    </head>
    <body>
    
    </body>
    </html>
    

    逻辑
    把上面代码 obj下面的注释解开,会发现打印的是人和人,这是从原型对象里面查找出来的,当对currentType重新进行赋值,然后再打印的话,currentType就会变成新赋的值了,而原型对象里面的值,还是原来的值。

    读读大牛的思路
    Javascript继承机制的设计思想

    相关文章

      网友评论

          本文标题:JavaScript-9面向对象

          本文链接:https://www.haomeiwen.com/subject/zxqtektx.html