欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js静态属性,实例属性,封装性,prototype,__proto__综合解析

程序员文章站 2024-03-13 10:48:09
...

原创作品,转载请注明来源,我的博客园sogeisetsu里也有这篇文章

js静态属性,实例属性,封装性,prototype,__proto__综合解析

下面是我在写博客的源代码,您可以先不要看他,先看下面的文字部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>js属性</title>
    <script>
        //先构造一个函数
        //先搞清楚原型链
        function qust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }
        //先创建一个实例对象
        let shili=new qust();
        //构造函数的原型对象通过prototype来调用
        console.log(qust.prototype);//打印原型对象,打印结果是object
        //注意,这个时候还没有改变原型对象
        console.log(qust.prototype.constructor);//打印原型对象的constructor
        /*打印结果是如下
        ƒ qust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
         …
        * */
        console.log(qust);//打印构造函数
        /*结果如下
        * ƒ qust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
         …*/
        console.log(qust === qust.prototype.constructor);//true,原型对象的constructor指向构造函数
        //但是,如果我们修改了qust.prototype(原型对象),qust.prototype.constructor还指向构造函数吗?
        qust.prototype={//prototype保存一些构造函数共有的属性,来节省内存
            type:"人类",
            typerun:function () {
                console.log('人类');
            }
        };
        console.log(qust === qust.prototype.constructor);//false,不相等了。
        // 注意点: 为了不破坏原有的关系, 在给prototype赋值的时候, 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁
        qust.prototype={//prototype保存一些构造函数共有的属性,来节省内存
            constructor:qust,//不带括号
            setype:"人类",
            typerun:function () {
                console.log('人类');
            }
        };
        console.log(qust === qust.prototype.constructor);//true
        /*
        1.对象中__proto__组成的链条我们称之为原型链
        2.对象在查找属性和方法的时候, 会先在当前对象查找
          如果当前对象中找不到想要的, 会依次去上一级原型对象中查找
          如果找到Object原型对象都没有找到, 就会报错
         */
        // 放个图就明白了
        let shi=new qust();//由于修改了一些东西,所以新创建一个对象
        console.log(shi.setype);//打印在原型对象中定义的值,结果是人类
        shi.setype="新人类";
        console.log(shi.setype);//新人类
        console.log(shi.__proto__);/*{setype: "人类", constructor: ƒ, typerun: ƒ}*/
        console.log(shi.__proto__.setype);//人类
        console.log(qust.prototype.setype);//人类
        console.log(shi.__proto__===qust.prototype);//true
        // 注意点: 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性
        /*
                1.在JavaScript中属性和方法分类两类
                1.1实例属性/实例方法
                在企业开发中通过实例对象访问的属性, 我们就称之为实例属性
                在企业开发中通过实例对象调用的方法, 我们就称之为实例方法
                1.2静态属性/静态方法
                在企业开发中通过构造函数访问的属性, 我们就称之为静态属性
                在企业开发中通过构造函数调用的方法, 我们就称之为静态方法
                */
        //先看一下原先设置的qust
        /*function qust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }
        * */
        //上面的属性或方法都是通过创建实例对象才能访问或调用,所以我们叫他实例属性或实例方法
        qust.school="qust";//这是一个静态属性,通过构造函数来访问
        console.log(qust.school);//qust
        //定义一个方法
        qust.getschool=function () {
            console.log("qust is my school");
        }//这是通过构造函数访问的方法,我们称其为静态方法
        qust.getschool()//调用静态方法
        //qust is my school
        //封装性
        //防止混乱构造一个新函数newqust
        function newqust() {
            this.name="university";//这是公有属性
            this.age=12;
            //以下是修改内容
            let myage=19;//设置一个私有年龄,这是在函数外面无法修改的
            this.setnewage=function (newage) {
              if(newage>=0){
                  myage=newage;
              }
            };
            //我们还需要一个来调用年龄
            this.getage=function () {
              return myage;
            };
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性,只能在该函数里访问,在外无法访问,这就为我们的封装性提供了可能
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }
        //试一下调用私有属性
        console.log(newqust.age);//undefined
        /*
        * 假设一个场景,让用户设置自己的年龄,年龄吗肯定大于零的,但是通过公有属性却而已随意设置*/
        let newshili=new newqust();
        newshili.age=-2;
        console.log(newshili.age);//-2,这是荒诞的
        //所以需要修改
        newshili.setnewage(15);
        console.log(newshili.getage());//15

    </script>
</head>
<body>

</body>
</html>

先搞清楚原型链,prototype

先构造一个函数

function qust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }

先创建一个实例对象来调用构造函数中的属性

 let shili=new qust();

构造函数的原型对象通过prototype来调用

console.log(qust.prototype);//打印原型对象,打印结果是object

注意,这个时候还没有改变原型对象

console.log(qust.prototype.constructor);//打印原型对象的constructor

qust.prototype.constructor是指向构造函数qust的。

所以????

console.log(qust === qust.prototype.constructor);//true

但是,如果我们修改了qust.prototype(原型对象),qust.prototype.constructor还指向构造函数吗?

修改qust.prototype

 qust.prototype={
            type:"人类",
            typerun:function () {
                console.log('人类');
            }
        };
console.log(qust === qust.prototype.constructor);//false,不相等了。

那怎么办呢?

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

就像这样????

        qust.prototype={//prototype保存一些构造函数共有的属性,来节省内存
            constructor:qust,//????不带括号,注意修改的就是这里
            setype:"人类",
            typerun:function () {
                console.log('人类');
            }
        };
 console.log(qust === qust.prototype.constructor);//true

我们之前设置了一个对象shili,还记得吗?

我们是这样设置的,????

 let shili=new qust();

shili是一个实例对象
实例对象的__proto__指向构造函数的原型对象qust.prototype

console.log(shili.__proto__===qust.prototype);//true
1.对象中__proto__组成的链条我们称之为原型链
2.对象在查找属性和方法的时候, 会先在当前对象查找
如果当前对象中找不到想要的, 会依次去上一级原型对象中查找
如果找到Object原型对象都没有找到, 就会报错
放个图就明白了

js静态属性,实例属性,封装性,prototype,__proto__综合解析

 let shi=new qust();//由于修改了一些东西,所以新创建一个对象
        console.log(shi.setype);//打印在原型对象中定义的值,结果是人类
        shi.setype="新人类";
        console.log(shi.setype);//新人类
        console.log(shi.__proto__);/*{setype: "人类", constructor: ƒ, typerun: ƒ}*/
        console.log(shi.__proto__.setype);//人类
        console.log(qust.prototype.setype);//人类
        console.log(shi.__proto__===qust.prototype);//true

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

实例属性和静态属性

1.在JavaScript中属性和方法分类两类
1.1实例属性/实例方法
在企业开发中通过实例对象访问的属性, 我们就称之为实例属性
在企业开发中通过实例对象调用的方法, 我们就称之为实例方法
1.2静态属性/静态方法
在企业开发中通过构造函数访问的属性, 我们就称之为静态属性
在企业开发中通过构造函数调用的方法, 我们就称之为静态方法

先看一下原先设置的qust

function qust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }

????上面的属性或方法都是通过创建实例对象才能访问或调用,所以我们叫他实例属性或实例方法

就像这样

 let shi=new qust();//由于修改了一些东西,所以新创建一个对象
        console.log(shi.setype);//打印在原型对象中定义的值,结果是人类

先设置一个静态属性
qust.school="qust";//这是一个静态属性,通过构造函数来访问

来调用它
console.log(qust.school);//qust

//定义一个方法
qust.getschool=function () {
   console.log("qust is my school");
}//这是通过构造函数访问的方法,我们称其为静态方法


qust.getschool()//调用静态方法返回qust is my school

封装性

防止混乱构造一个新函数newqust

function newqust() {
            this.name="university";//这是公有属性
            this.age=12;
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性,只能在该函数里访问,在外无法访问,这就为我们的封装性提供了可能
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }

试一下调用私有属性

  console.log(newqust.age);//undefined,无法调用

这是私有属性,只能在该函数里访问,在外无法访问,这就为我们的封装性提供了可能

假设一个场景,让用户设置自己的年龄,年龄吗肯定大于零的,但是通过公有属性却而已随意设置

let newshili=new newqust();
        newshili.age=-2;
        console.log(newshili.age);//-2,这是荒诞的

所以需要修改,newqust修改如下

 function newqust() {
            this.name="university";//这是公有属性
            this.age=12;
            //以下是修改内容
            let myage=19;//设置一个私有年龄,这是在函数外面无法修改的
            this.setnewage=function (newage) {
              if(newage>=0){
                  myage=newage;
              }
            };
            //我们还需要一个来调用年龄
            this.getage=function () {
              return myage;
            };
            //这是共有方法
            this.run=function () {
                console.log("have ran");
            };
            let age="12";//这是私有属性,只能在该函数里访问,在外无法访问,这就为我们的封装性提供了可能
            //这是私有方法
            function go() {
                console.log("have gone");
            }
        }

可以修改年龄

newshili.setnewage(15);
        console.log(newshili.getage());//15

如果将年龄设置成负值呢?

 newshili.setnewage(-5);
        console.log(newshili.getage());//返回19