JavaScript忍者秘籍 -面向对象与原型

什么是原型?
javascript通过原型实现继承。每个对象都可以有一个原型,每个对象的原型也可以拥有一个原型,形成了一个原型链。查找特定属性会被委托在原型链上,按照当前对象 > 当前对象的原型 > 当前对象的原型的原型顺序查询。

· 每一个函数都有一个原型对象
· 每一个函数的原型对象都具有一个constructor属性,该属性指向函数本身
· constructor对象的原型设置为新创建的对象的原型

通过object1.prototype.xxx=function(){}设置的方法是object1的原型属性而非实例属性。

实例属性与原型属性有什么区别?
把函数作为构造函数,通过new调用,此时上下文被定义为新的对象实例,通过原型暴露属性,通过构造函数的参数进行初始化。

             function Ninja(){
              this.swung = false;
              this.swingSword = function(){ //实例方法
                return !this.swung;
              };
             }
             
             Ninja.prototype.swingSword = function(){ //原型方法
               return this.swung;
             };
             
             const ninja = new Ninja();
             assert(ninja.swingSword(),
                   "Called the instance method, not the prototype method.");

若实例属性与原型属性同名,则创建新的实例对象时,实例方法会重写原型方法,在实例中可以查找到,就不会再查找原型。
7-1

原型如何实现继承?
SubClass.prototype = new SuperClass();
SubClass的实例的原型是SuperClass的实例,SuperClass实例具有SuperClass的全部属性,SuperClass实例也同时具有一个指向超类的原型。

如何解决继承后,原constructor属性被覆盖问题?

            "use strict";
            
            function Person(){}
            Person.prototype.dance = function(){};

            function Ninja(){}
            Ninja.prototype = new Person();

            Object.defineProperty(Ninja.prototype, "constructor", {
              enumerable: false,
              value: Ninja,
              writable: true //定义一个新的不可枚举的constructor属性,属性值为Ninja
            });

            const ninja = new Ninja();

            assert(ninja.constructor === Ninja,
                  "Connection from ninja instances to Ninja constructor reestablished!");

            for(let prop in Ninja.prototype){
              assert(prop === "dance", "The only enumerable property is dance!");
            }

使用Object.defineProperty()对原constructor设置不可枚举的constructor属性

instanceof
用于检测左边类与右边类是否是同一个子类,注意原型是否发生改变。

class -ES6 
class提供了一种更为优雅的创建对象和实现继承的方式,但是其底层实现仍然是基于原型。

            class Ninja{
              constructor(name, level){
                this.name = name;
                this.level = level;
              }

              swingSword() {
                return true;
              }

              static compare(ninja1, ninja2){//静态方法
                return ninja1.level - ninja2.level; 
              }
            }

class 如何实现继承?

            class Person {
              constructor(name){
                this.name = name;
              }

              dance(){
                return true;
              }
            }

            class Ninja extends Person { 
              construct(name, weapon){
                  //super(name); //Uncomment this line of code when super gets supported.
                this.weapon = weapon;
              }

              wieldWeapon(){
                return true;
              }
            }


原型方法与实例方法区别

        //one
        function Person(firstName, secondName) {
            this.firstName = firstName;
            this.secondName = secondName;
            this.getFullName = function () {
                return this.firstName + "" + this.secondName;
            }
        }
        //two
        function Person(firstName, secondName) {
            this.firstName = firstName;
            this.secondName = secondName;
        }
        Person.prototype.getFullName = function () {
            return this.firstName + "" + this.secondName;
        }

第一种getFullName方法是在Person构造函数内创建的实例方法,凡是使用Person构造函数创建的对象都具有各自的getFullName方法;
第二种,定义在Person原型上,范式用Person构造函数创建的对象可以访问;
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值