前端开发核心知识进阶 2.7 面向对象和原型——永不过时的话题

本节引言


“对象”这个概念在编程中非常重要,任何语言和领域的开发者都应该具有面向对象思维,有效运用对象。良好的面向对象系统设计将是应用具有健壮性、可维护性和可扩展性的关键;反之,
如果面向对象环节有失误,那么项目将会面临灾难性的后果。
JavaScript面向对象的实质是基于原型的对象系统,而不是基于类。这是由最初的设计所决定的,
是基因层面的特点。随着ES Next标准的进化和新特性的添加,JavaScript 面向对象更加贴近其他传统面向对象型语言。有幸目睹语言的发展和变迁,伴随着某种语言成长,我认为是开发者之幸。
本篇就让我们深人对象和原型,了 解JavaScript 在这个方向上的能力。请注意,下面不会过多
赘述基础内容,读者需要具有一定的知识准备。
 

一、实现new没有那么容易

new关键字都做了什么

1.首先创建一个空对象a,这个对象会作为执行函数之后返回的对象实例

2.使对象a的原型(__proto__)指向构造函数的prototype属性

3.将对象a赋值给构造函数内部的this,并执行构造函数逻辑

4.根据构造函数执行逻辑,返回对象a或者构造函数的显示返回值

下面进行new实现

function newFn(...args){
  const constructor = args.shift()
  const obj = Object.create(constructor.prototype)
  const result = constructor.apply(obj,args)
  return (typeof result === 'object' && result != null) ? result : obj
}

 解析:Object.creat()的作用是什么呢,就是把返回一个空对象a,对象a的__proto__指向第一个参数。使用apply把函数里的this指向空对象a,并执行函数体,返回值如果是个对象则返回,否则返回对象a

例子试验一下

function Dog(a){
  this.a = a
}


Dog.prototype.add = function(){
  this.a++
}


function Cat(a){
  this.a = a
  return {b: 10}
}

let d = newFn(Dog,5)
let c = newFn(Cat,5)
console.log(d); //{ a : 5 }
console.log(c); //{ b : 10 }


//Object.create() 例
const o = Object.create(Dog.prototype)
console.log(o.__proto__); //{ add: [Function (anonymous)] }

二、对象的继承

function Dog(a){
  this.a = a
}
Dog.d = 'd'
Dog.prototype.add = function(){
  this.a++
}

以上的对象有原型对象,有私有属性,还有实例属性,怎么都继承呢

原型链继承

function Cow(){

}
Cow.prototype = new Dog(5)

构造函数继承

function Cow(args){
  //...
  Dog.call(this, args)
}
let cow = new Cow(5)

组合继承

//XXX 组合继承
function Cow(a,b){
  this.b = b
  Dog.call(this, a)
}

Cow.prototype = Object.create(Dog.prototype)
Object.setPrototypeOf(Cow,Dog)
let cow = new Cow(10,15)

call方法使Cow实例继承Dog实例的属性和方法

Cow.prototype = Object.create(Dog.prototype) 使Cow的原型对象赋值为Dog的原型对象

Object.setPrototypeOf(Cow,Dog) 使Cow的__proto__指向Dog,这意味着Cow可以拿到Dog的静态属性和方法,例如变量d

封装成方法

function inherit(Child,Parent){

  //继承原型
  Child.prototype = Object.create(Parent.prototype)

  //修复constructor
  Child.prototype.constructor = Child

  //存储超类
  Child.super = Parent

  //静态属性继承
  if(Object.setPrototypeOf){
    // setPrototypeOf es6
    Object.setPrototypeOf(Child,Parent)
  }else if(Child.__proto__){
    // ES6引入__proto__
    Child.__proto__ = Parent
  }else{
    // 兼容IE10,拷贝Child没有,Parent有的属性
    for(var k in Parent){
      if(Parent.hasOwnProperty(k) && !(k in Child)){
        Child[k] = Parent[k]
      }
    }
  }
}

三、jQuery中的对象思想

JQery的核心思想就是靠选择器获取node节点,声明一个空数组a,储存起来,数组a的__porto__赋值为JQery的函数对象$.fn,返回数组,所以数组可以使用JQery封装的方法,代码如下

var jQuery = (function(){

  var $
  $ = function(selector, context){
      var dom = []
      var nodeList
      dom.__proto__ = $.fn
      if(context !== undefined){
        nodeList = context.querySelectorAll(selector)
      }else{
        nodeList = document.querySelectorAll(selector)
      }
      for(var i=0; i<nodeList.length; i++){
        dom[i]=nodeList[i]
      }
      return dom
  
  }
  $.fn = {
    css: function(...args){
        let attr
        if(args.length===1){
          attr = args[0]
          for(var i=0;i<this.length;i++)
          {
           for(var j in attr){
             this[i].style[j]=attr[j];
            }
          }
        }else if(args.length === 2){
          let key = args[0]
          let value = args[1]
          for(var i=0;i<this.length;i++)
          {
           this[i].style[key]=value;
          }
        }
         return this;
    },
    //...
  }
  
  $.ajax = function(){
    //...
  }
  
  return $
  
  })()
window.jQuery = jQuery
window.$ === undefined && (window.$ = jQuery)


总结:
面向对象是一个永远说不完的话题,更是一个永远不会过时的话题,具备良好的面向对象架构能力,对于开发者来说至关重要。同时,由于JavaScript面向对象的特殊性,使它区别于其他语言面向对象的特殊性,使它区别于其他语言而“与众不同”,所以我们在了解了JavaScript 原型、原型链知识的前提下,对比其他语言的思想来学习JavaScript 就变得非常重要和有意义了。
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值