(五)原型和原型链的基础题解析

418 阅读2分钟

js本身是一个基于原型的语言,最初我们的继承只能依靠原型做继承;后来引入了es5 es6 我们可以拿Class做继承;其实Class内部还是一个原型的继承;

讲解过程:

  1. 先拿出题目
  2. 再透过题目看知识点
  3. 最后解答

题目

  • 如何准确判断一个变量是不是数组?
  • 手写一个简易的jQuery,考虑插件和扩展性(为了更好的学习js学习内部思路)
  • class的原型本质,怎么理解?通过自己的语言把原型和本质表述出来

知识点

  • Class和继承
  • 类型判断 instanceof
  • 原型和原型链

class

Class是一个面向对象的语法实现,Class其实很像一个模板,我们可以通过模板去构建一些东西。

  • constructor
  • 属性
  • 方法

class的原型本质:

  • 原型和原型链的图示(自己画一遍)
  • 属性和方法的执行规则
class Student {
    constructor(name,number){
        this.name = name 
        this.number = number
        // 可以赋更多属性
    }
    siHi(){
        console.log(`妹子${this.name}想打酱油${this.number}`)
    }
    study(){...可以直接写多个方法..}
}

通过类class  创造实例
const xiaorongrong = new Student('小熔熔',100)
console.log(xiaorongrong)
xiaorongrong.siHi()

继承

  • extends
  • super
  • 扩展或重写的方法
直接打印一个未声明的变量会报错  xxx is not defined
但直接打印一个对象内不存在的值会是undefined
// 父类
class People {
    constructor(name){
        this.name = name
    }
    eat(){
        console.log(`${this.name}是一个漂亮妹子`)
    }
}
// 子类 继承的话要记得在constructor内super
class Student extends People {
    constructor(name,number){
        super(name)
        this.number = number
    }
    sayHi(){
        console.log(`姓名${this.name}漂亮妹子还对你招了手${this.number}`)
    }
}

// 再写一个继承People的子类
class Teacher extends People {
    constructor(name,major) {
        super(name)
        this.major = major
    }
    teacher(){
        console.log(`${this.name}教授${this.major}`)
    }
}

// 实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name) //夏洛
console.log(xialuo.Siholll)//undefined
xialuo.sayHi() 
xialuo.eat()
xialuo instanceof Student // true
xialuo instanceof People // true

// 了解this指向后补充一下
xialuo._proto_.sayHi()  // 姓名undfined漂亮妹子还对你招了手undfined
// 这里undefined其实是因为xialuo._proto_调用了sayHi()方法,this指向的是xialuo._proto_

// xialuo.sayHi() 
// 其实相当于xialuo._proto_.sayHi.call(xialuo) ,但内部不是这样执行的

原型

继续刚才继承的例子

typeof People // function
typeof Student // function
console.log(xialuo._proto_) // sayHi() 隐式原型
console.log(Student.prototype) // sayHi()  显示原型
console.log(xialuo._proto_ === Student.prototype) // true
画一下这部分的原型链

image.png

原型关系:
每个class都有显示原型prototype
每个实例都有隐式原型_proto_
实例的_prop_指向对应class构造函数的prototype

原型链

继续刚才的例子

console.log(Student.prototype._proto_)
console.log(People.prototype)
console.log(People.prototype === Student.prototype._proto_)

image.png

xialuo.hasOwnProperty('name')// true
xialuo.hasOwnProperty('sayHi')// false

image.png

类型判断-instanceof

[] instanceof Array  //  true
[] instanceof Object // true
{} instanceof Object // true

其实instanceof内部做了一个先从变量下查找有没有该元素,如果没有的话就顺着去该元素的_prop_上去寻找,一个原型链的顺序找到最顶端,如果都没找到才会返回false,如果能找到就返回true

提示
1.class是ES6语法规范,由ECMA委员会发布
2.ECMA 只规定语法规则,代码的书写规范,不规定如何实现
3.以上说的都是V8引擎的实现方式,也是主流的

手写简易jQuery考虑插件和扩展性代码演示

主要看看它的基本结构,了解原型和继承

js:   
// 一开始直接声明jQuery的类
class jQuery {
     // 构造器
    constructor(selector){
         const result = document.querySelectorAll(selector)  
         const length = result.length
         for (let i = 0;i<length;i++){
             this[i] = result[i]
         }
         this.length = length
         this.selector = selector
         // 类数组  对象
         
    }
    get(index) {
        return this[index]
    }
    each(fn) {
        for( let i = 0;i<this.length;i++){
            const elem = this[i]
            fn(elem)
        }
    }
    on(type,fn){
        return this.each(elem => {
            elem.addEventListener(type, fn, false)
        })
    }
    // 扩展很多 DOM API
}

我们可以在控制台打印一下

html:
<body>
        <p>一段文字 1</p>
        <p>一段文字 2</p>
        <p>一段文字 3</p>
        <script src="./promise-demo.js"></script>
</body>

const $p = new jQuery('p')
console.log($p)
// jQuery{0:p, 1:p, 2:p, length:3, selector:"p",_proto_:Object}
$p.get(1) // <p>一段文字 2</p>
$p.each((elem) => console.log(elem.nodeName)) // 3p (3个p)
$p.on('click', ()=>alert('clicked'))

考虑插件的扩展性:

// 插件
js=> 利用原型 把方法挂载在原型上
jQuery.prototype.dialog = function (info){
    alert(info)
}
console=>
const $p = new jQuery('p')
$p.dialog()

// 复写/“造轮子” 这种就类似于,让大家用自己的插件,自己的插件继承于原对象
class myJQuery extends jQuery {
    constructor(selector){
           super(selector) // 继承所有父类
           // 扩展自己的方法
           addClass(){
           
           }
           style(data){
           
           }
    }
}

小结

  • class和继承,结合手写JQuery的示例来调整
  • instanceof
  • 原型和原型链:图示&执行规则