JavaScript——原型、原型链

写在前面:

很多人分不清__proto__和 prototype ,下面先举个例子:

prototype 是你自己打工挣得的一笔钱,而__proto__是你爹打工挣的钱,当你被你爹 new 出来的时候,他的钱也就是你的钱,但是如果你有兄弟姐妹,你爹的钱他们也可以使用,但是prototype是属于你自己的钱,你的兄弟姐妹用不了。简单来说就是,你爹(构造函数) 每创造出一个 孩子(实例),你爹自己的钱 (prototype:你爹也是人,他的钱属于他自己的prototype)就等于你(实例)的__proto__

1.原型初步认识

      let arr = ["hello"];
      console.log(arr.concat("world"));

如下图,__proto__属性就是 Array 对象的原型,因为arr 是Array的实例化对象,所以arr也可以使用 Array原型上的方法
在这里插入图片描述

      let a = {};
      let b = {};

      console.log(Object.getPrototypeOf(a) === Object.getPrototypeOf(b));//true

2.没有原型的对象

      let hq = { name: "hq" };
      console.log(hq.hasOwnProperty("name"));//true

      //完全数据字典对象
      let obj = Object.create(null, {
        name: {
          value: "hello",
        },
      });
      console.log(obj);

在这里插入图片描述
3.原型方法与对象方法优先级

      let hd = {
        render() {
          console.log("hd render");
        },
      };

      hd.__proto__.render = function () {
        console.log("hq");
      };
      
      hd.render();//hd render

*自己有就用自己的,没有才会到原型上找

4.函数拥有多个长辈

      function User() {}
      console.dir(User)

在这里插入图片描述
*prototype:服务于实例化对象

      function User() {}

      User.prototype.show = function () {
        console.log("hello");
      };

      let hq = new User();
      console.log(User.prototype === hd.__proto__);//true

*proto:服务于函数对象

      function User() {}

      User.__proto__.view = function () {
        console.log("user view");
      };

      User.view();//user view

*函数可作为构造函数,也可作为函数对象

5.原型关系与属性继承实例

      function User() {}
      
      console.dir(User.__proto__=== Function.prototype);//true

如上代码,因为 User 其实是通过 new Function 创建的,所以User 的原型__proto__就=== Function 的 prototype

      User.prototype.__proto__ === User.__proto__.__proto__; //true

如上代码,我们先来分析 User.prototype 就是User这个构造函数自身的原型,然而这个原型prototype它本身也是一个对象,而这个prototype对象的其实是通过Object 构造出来的。我们再看User.proto,因为User 是通过new Function 来的,所以 它的__proto__就等于Function.prototype。而Function的prototype和User的prototype一样都是通过Object创造出来的对象,所以它们的原型__proto__就相等
在这里插入图片描述
6.系统构造函数的原型

      let arr = []; //new Array
      console.log(arr.__proto__ === Array.prototype);//true
      
      let str = ""; //new String
      console.log(str.__proto__ === String.prototype);//true

      let bool = true; //new String
      console.log(bool.__proto__ === Boolean.prototype);//true

      let reg = /a/i; //new RegExp
      console.log(reg.__proto__ === RegExp.prototype);//true

      let obj = {}; //new Object
      console.log(obj.__proto__ === Object.prototype);//true
      

多看一眼

        console.dir(Object.__proto__)

输出如下:
在这里插入图片描述
妥妥的一个函数
没错,Object也是通过Function构造出来的。

7.自定义对象的原型设置

*设置原型:setPrototypeOf

      let obj = {};
      let parent = {name: "parent"};

      Object.setPrototypeOf(obj, parent);

在这里插入图片描述
*获取原型:getPrototypeOf

      let obj = {};
      let parent = { name: "parent", age: 18 };
      Object.setPrototypeOf(obj, parent);
      console.log(Object.getPrototypeOf(obj));

在这里插入图片描述
8.原型中的constructor引用

*通过原型的constructor 可以找到构造函数

      function User() {}
      console.log(User.prototype.constructor === User);//true
      function User(name) {
        this.name = name;
      }

      User.prototype = {
        constructor: User,
        show() {console.log(this.name)},
      };

      let ls = new User("李四");

      ls.show();//李四

9.基于实例创造对象

先看看如下代码:

        function Admin() { }
        let obj = new Admin();
        console.log(obj.__proto__.constructor === Admin);//true

大白话:实例化对象的原型__proto__当中的 constructor 属性指向的是构造函数本身
再理解:

      function User(name) {
        this.name = name;
        this.show = function () {
          console.log(this.name);
        };
      }

      let ls = new User("李四");

      function createByObj(obj, ...args) {
        //找到obj原型的constructor
        const constructor = Object.getPrototypeOf(obj).constructor;
        return new constructor(...args);
      }

      let zs = createByObj(ls, "张三");
      zs.show();

10.原型检测之instanceof

  • a 对象的原型链上是否有 A 这个构造函数的 prototype
        function A() { }
        let a = new A();
        console.log(a instanceof A)//true
        function A() { }
        function B() { }

        let b = new B();
        A.prototype = b
        let a = new A();

        console.log(a instanceof B)//true

11.Object.isPrototypeOf原型检测

        let a = {}
        let b = {}
        // b 对象是否在 a 对象的原型链上
        console.log(b.isPrototypeOf(a))//false
        console.log(Object.prototype.isPrototypeOf(a))//true
        //把b对象设置为a对象的原型
        Object.setPrototypeOf(a, b)
        console.log(b.isPrototypeOf(a))//true

12.in 与 hasOwnProperty的属性检测
in:检测一个属性是否存在于一个对象或者该对象的原型链上

        let a = { url: 'baidu.com' }
        let b = { name: 'baidu' }
        console.log('url' in a)//true
        Object.prototype.c = 'hello'
        console.log('c' in a)//true
        Object.setPrototypeOf(a, b)
        console.log('name' in a)

hasOwnProperty:检测当前对象,不检查其原型链上是否存在某一属性

        let a = { url: 'baidu.com' }
        let b = { name: 'baidu' }
        Object.setPrototypeOf(a, b)
        console.log(a.hasOwnProperty('name'))//false
        let a = { url: 'baidu.com' }
        let b = { name: 'baidu' }
        Object.setPrototypeOf(a, b)
        for (const key in a) {// 会遍历到原型链上的属性
            console.log(key)
        }

在这里插入图片描述
利用 hasOwnProperty,只遍历自身属性

        for (const key in a) {
            if(a.hasOwnProperty(key))
            console.log(key)
        }

原型检测:
instanceof: 一个对象 的原型链上是否有 某个构造函数 的 prototype
isPrototypeOf:一个对象 是否在 另一个对象 的原型链上

属性检测:
hasOwnProperty:检测 当前对象,不检查其原型链上是否存在 某一属性
in:检测 一个属性 是否存在于 一个对象 或者 该对象的原型链

13.使用call或apply借用原型链

        let obj = { data: [1, 3, 2, 6, 5] }
        Object.setPrototypeOf(obj, {
            max() {
                return this.data.sort((a, b) => b - a)[0]
            }
        })

        let zs = {
            lessons: { js: 34, php: 53, node: 66 },
            get data() {
                return Object.values(this.lessons)
            }
        }
        console.log(obj.max.apply(zs))//66
        let obj = { data: [1, 3, 2, 6, 5] }
        Object.setPrototypeOf(obj, {
            max(data) {
                return data.sort((a, b) => b - a)[0]
            }
        })

        let zs = {
            lessons: { js: 34, php: 53, node: 66 },
        }

        console.log(obj.max.call(null, Object.values(zs.lessons)))//66

14.DOM节点借用Array原型方法

<body>
    <button message='1' class="one">1</button>
    <button message='2'>1</button>

    <script>
        let btns = document.querySelectorAll('button')

        btn = Array.prototype.filter.call(btns, item => {
            return item.hasAttribute('class')
        })
        console.log(btn[0].innerHTML);//1
    </script>
</body>

15.合理的构造函数方法声明

        function User(name) {
            this.name = name;
            this.show = function () {
                console.log(this.name)
            }
        }
        let ls = new User('李四')
        let zs = new User('张三')

        console.log(ls);
        console.log(zs);

面向对象中,只保存对象属性, 对于show方法没必要开辟独立内存造成浪费
在这里插入图片描述
如下,将show方法放到原型中

        function User(name) {
            this.name = name;
        }
        User.prototype.show = function () {
            console.log(this.name);
        }
        let ls = new User('李四')
        let zs = new User('张三')

在这里插入图片描述
16.this和原型没有关系

        let obj = {
            name: '张三',
            show() {
                console.log(this.name)
            }
        }
        Object.setPrototypeOf(obj, {})
        obj.show()//张三

无论原型怎么改,我们的this永远指向调用它的对象

        let obj = {
            name: '张三',
        }
        let User = {
            name: '李四',
            show() {
                console.log(this.name)
            }
        }
        Object.setPrototypeOf(obj, User)
        obj.show()//'张三'

17.__proto__是属性访问器

*严格意义来讲__proto__它不是一个属性,它是getter setter

      let obj = { name: "张三" };

      obj.__proto__ = {
        show() {
          console.log(this.name);
        },
      };
      console.log(obj.__proto__);

在这里插入图片描述
如上,我们将obj的__proto__设置为别的对象,ok,没问题,但是请看下面

      let obj = { name: "张三" };

      obj.__proto__ = {
        show() {
          console.log(this.name);
        },
      };
      obj.__proto__ = 99//重点
      console.log(obj.__proto__);

(不是和上面同一张截图!)(不是和上面同一张截图!)
没错,它输出的结果和上面一样,这是因为它是一个getter 和 setter ,对它的赋值操作进行了判断。

大概意思如下:

      let obj = {
        action: {},

        get proto() {
          return this.action;
        },
        set proto(value) {
          if (value instanceof Object) {
            this.actioin = value;
          }
        },
      };
      obj.proto = "abc";
      console.log(obj.proto);//{}

如上,并没有将"abc"设置成功,但是如下设置为一个对象,那就能设置成功

      obj.proto = {
        show: function () {},
      };
      console.log(obj.proto);

在这里插入图片描述
霸王硬上弓

      let obj = Object.create(null);
      obj.__proto__ = 99;
      console.dir(obj.__proto__);//99

通过Object.create让其不继承Object 的原型,使其成为孤儿,这样就可以随意设置它的__proto__属性(此时就是属性了)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript中,每个对象都有一个隐藏的 `__proto__` 属性,它指向该对象的原型原型是一个普通的对象,它包含了共享属性和方法。当我们访问一个对象的属性或方法时,JavaScript引擎会首先在该对象本身查找,如果找不到,则会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(Object.prototype)。这个原型链的过程就是通过 `__proto__` 属性来实现的。 例如,当我们创建一个实例对象 `teacher` 时,如果 `teacher` 对象本身没有 `teach()` 方法,JavaScript引擎会通过对象的 `__proto__` 属性查找到 `Teacher.prototype` 的显式原型上,如果 `Teacher.prototype` 仍然没有该方法,它会继续沿着 `Teacher.prototype.__proto__` 找到 `Person.prototype`,直到找到 `teach()` 方法并执行。这样就形成了一个原型链。 同时,可以注意到 `Object.prototype.__proto__` 的值为 `null`,即 `Object.prototype` 没有原型。所以在原型链中,当找到顶层原型还没有属性时,就会返回 `undefined`。 需要注意的是, `__proto__` 是一个非标准的属性,实际开发中不应该直接使用它。它只是内部指向原型对象 `prototype` 的一个指示器,我们应该使用 `Object.getPrototypeOf()` 或 `Object.setPrototypeOf()` 来访问和设置对象的原型。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [JS原型原型链](https://blog.csdn.net/elevenhope/article/details/122882582)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [JavaScript原型链(重要)](https://blog.csdn.net/liyuchenii/article/details/125957625)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值