JavaScript中的原型详解

·  阅读 43

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

原型 prototype

        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.sayHi = function() {
                console.log('hi, 我是' + this.name + ', 我' + this.age + '了');
            }
        }

        Person.prototype.sayHello = function() {
            console.log('hello, 我是' + this.name + ', 我' + this.age + '了');
        }

        console.log(Person.prototype);

        let p1 = new Person('shaosiming', 18);
        let p2 = new Person('dasiming', 19);

        console.log(p1.sayHi == p2.sayHi); // false
        console.log(p1.sayHello == p2.sayHello); // true
复制代码

可以看到, 如果不使用原型那么每个对象都有自己的方法, 这样会很大的浪费内存资源 像sayHi这样的方法, 是属性每个对象的

而有了原型之后, 我们可以在原型上添加一个公用的方法, 这样就节省了内存资源

原型链的使用流程

  1. 当一个对象调用方法和访问属性时, 首先会在自己本身查找, 如果找到则调用或访问
  2. 如果在自身找不到属性和方法时, 会去自身的原型上查找, 如果找到则调用或访问
  3. 如果在自身的原型上找不到属性和方法时, 则去原型的原型上查找, 如果找到则调用或访问
  4. 按照这个规则, 在原型链上一路向上
  5. 直到Object这个根原型, 如果还没有找到, 则返回undefin

作用

  • 使用原型后, 我们可以把公有的属性和方法放到原型对象上去, 这样节省内存资源
  • 在使用原型后, 在给原型添加一个新方法或属性时, 拥有该原型的所有对象也自动获得了该属性和方法, 哪怕这些对象的创建是在添加这个方法和属性之前

this

在方法中this指向调用这个方法的对象.

而在如果在对象中没有找到要调用的方法, 而在原型中找到了要调用的方法, this还是指向调用方法的对象.

        Person.prototype.isSleeping = false;

        Person.prototype.sleep = function() {
            this.isSleeping = true;
        }

        console.log(p1.isSleeping); // false
        console.log(p2.isSleeping); // false
        console.log(p1.hasOwnProperty('isSleeping')); // false
        console.log(p2.hasOwnProperty('isSleeping')); // false

        p1.sleep();

        console.log(p1.isSleeping); // true
        console.log(p2.isSleeping); // false
        console.log(p1.hasOwnProperty('isSleeping')); // true
        console.log(p2.hasOwnProperty('isSleeping')); // false
复制代码

hasOwnProperty方法: 查看对象自身有没有某个属性

注意: 这里一开始的时候p1和p2都没有isSleeping属性, isSleeping属性都是在它们的原型上

而当p1调用了sleep方法之后, 在该方法中this指向调用者, 也就是p1, 因此向p1添加了属性isSleeping并设置为true

而p2没有调用sleep方法, 因此也就没有向p2对象中添加isSleeping属性, 这个属性在原型上

原型链

在js中可以通过原型这种方式来实现常见面向对象中的继承这个特性

比如我们要让Student继承自Person, 在js中想要实现这种效果, 要按照如下步骤进行

  1. 有一个Peron构造函数, 有一个Student构造函数
  2. 设置Student的prototype为new Person()的空对象
  3. 如果想要实现的完全一点还要设置Student的prototype的constructor为Student构造函数

注意: 在Student的构造函数中, 我们可以请求Person构造函数来帮我们初始化实例, 这里要使用Person.call()这种调用方式

原型链的终点永远都是Object这个对象

uml图

代码

        function Person(name, age) {
            this.name = name;
            this.age = age;
        }

        Person.prototype.sayHi = function() {
            console.log('Person sayHi');
        }

        function Student(name, age, classNo) {
            // 要使用这种调用方式, 原指定Person构造函数中的this
            Person.call(this, name, age);
            this.classNo = classNo;
        }

        // 在在这里设置Student的原型为通过Person构造的空对象
        Student.prototype = new Person();

        // 这里要设置Student的原型的构造函数为Student, 否则它是指向的Person这个构造函数
        Student.prototype.constructor = Student;

        Student.prototype.study = function() {
            console.log(`${this.name}正在${this.classNo}班学习`);
        }

        let stu = new Student('shaosiming', 18, 100);
        console.log(stu);
        console.log('stu constructor: ', stu.constructor);
        stu.sayHi();
        stu.study();
复制代码

给内置对象添加属性或者方法

有了原型, 我们可以给内置的对象添加属性或者方法, 简直不要太方便

        // 给内置对象添加方法
        let arr = ['wow', 'haha', 'xixi', 'abcdcba']
        String.prototype.palindrome = function() {
            let lastIdx = this.length - 1;
            for (let i = 0; i <= lastIdx; i++) {
                if (this[i] !== this[lastIdx - i]) {
                    return false;
                }
                return true;
            }
        }

        String.prototype.palindrome2 = function() {
            let reverseStr = this.split('').reverse().join('');
            return reverseStr === this.valueOf()
        }

        for (let i = 0; i < arr.length; i++) {
            const element = arr[i];
            if (element.palindrome2()) {
                console.log(`${arr[i]} is a palidrome`);
            } else {
                console.log(`${arr[i]} is not a palidrome`);
            }
        }
复制代码
分类:
前端
收藏成功!
已添加到「」, 点击更改