Js 面向對象小結

面向對象有三個特性,一個個來講:

封裝

私有變量

應用閉包完成對象的私有變量。


function Animal (age) {
  this.getAge = function () {
    return age
  }
}
var dog = new Animal(3)
console.log(dog.age) // undefined
console.log(dog.getAge()) // 3

碰過的一個風趣的題目:
完成一個book組織函數,有一個屬性id,每次挪用該值加1。
應用閉包和馬上實行函數。

let Book = (function () {
  let id = 1
  return function () {
    this.id = id++
  }
})()
let bok1 = new Book() 
let bok2 = new Book() 
let bok3 = new Book() 
console.log(bok3.id) // 3

共有要領

看下面的代碼能夠發明,getAge被反覆建立了

var dog = new Animal(3)
var cat = new Animal(5)
console.log(dog.getAge === dog.getAge) // false

假如不想要領或許屬性在每次new時新建立一份,能夠將其設置在組織函數的原型prototype上。

Animal.prototype.feed = function () {
  console.log('feed')
}
console.log(dog.feed === cat.feed) // true

繼續

據說繼續有六種要領,假定讓Dog繼續Animal,不過就是for in 複製屬性,修正原型鏈如dog.prototype = new Animal,直接Object.create,在Dog中運用Animal.call
但是我們記着最好的一種就夠了,就是組合繼續。

先試下如許寫,應用call的繼續:

function Animal (name) {
  this.name = name;
  this.say = function() {
    console.log(this.name)
  }
}
// *1
function Dog (color, name) {
  Animal.call(this, name)
  this.color = color
}


// *2
let wangcai = new Dog('blue', 'wangcai')
console.log(wangcai) // {color: 'blue', name: 'wangcai')
wangcai.say() // 'wangcal'

但是假如在*1處加上如許的代碼

Animal.prototype.say2 = function() {
    console.log(this.name)
}

在*3處輸入

wangcai.say2(),會報錯提醒不存在該要領,申明我們的繼續是不完全的。dog沒有繼續原型鏈上的要領

我們須要在*2補上:

Dog.prototype = Object.create(Animal.prototype)

這時候不會報錯了,補上Object.create的polyfill

function objectCreate (proto) {
  function F() {}
  F.prototype = proto;
  return new F();
}

但是另有一點小破綻,當我們檢察wangcai.constructor時,會發明指向的是Animal。因而我們須要修復一下:

Dog.prototype.constructor = Dog

補充一下new的模仿

function fNew (base) {
var o = {}
o.__proto__ = base.prototype
base.call(o)
return o
}

完全代碼

function Animal (name) {
  this.name = name;
  this.say = function() {
    console.log(this.name)
  }
}
Animal.prototype.say2 = function () {
  console.log(this.name)
}
function Dog (color, name) {
  Animal.call(this, name)
  this.color = color
}
Dog.prototype = Object.create(Animal.prototype)
Dog.prototype.constructor = Dog
let wangcai = new Dog('blue', 'wangcai')

檢測繼續是不是勝利的代碼:

console.log(wangcai instanceof Animal)
console.log(wangcai instanceof Dog)
console.log(wangcai.constructor === Dog)
console.log(wangcai.say2 === Animal.prototype.say2)
console.log(wangcai.__proto__ === Dog.prototype)
console.log(wangcai.__proto__.__proto__ === Animal.prototype)
console.log(wangcai.__proto__.__proto__.__proto__ === Object.prototype)
console.log(wangcai.constructor === Dog)

運用Object.create()和修復Dog.prototype.constructor = Dog是不是是挺過剩的?es6供應了這麼一個函數Object.setPrototypeOf.

因而我們能夠運用

Object.setPrototypeOf(Dog.prototype, Animal.prototype)

替代方才提到的兩行代碼

能夠相識到Object.setPrototypeOf(A,B)相當於令A.__proto__ = B。

多態

一個函數能夠應用於差別的對象。而且依據this的差別,函數挪用的效果也差別

function test() {
  alert([this.a, this.b]);
}
 
test.call({a: 10, b: 20}); // 10, 20
test.call({a: 100, b: 200}); // 100, 200
 
var a = 1;
var b = 2;
 
test(); // 1, 2

或是在函數中檢測arguments的數目和範例來完成多態

function add (a, b) {
  if (arguments.length  === 2) {
    return a + b
  } else {
    return a + 1
  }
}
console.log(add(1,4))
console.log(add(1))

END

    原文作者:皮小蛋
    原文地址: https://segmentfault.com/a/1190000015453578
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞