面向?qū)ο蠡仡櫍?/h4>
- 通過new構(gòu)造函數(shù)的方式(class的constructor (es6))
class Person{
constructor(name){ //構(gòu)造器
this.name = name
}
}
var person = new Person('tom')
- function的方式 (es3)
function Person(name){
this.name = name
}
var person = new Person('jack')
class Person{
constructor(name){ //構(gòu)造器
this.name = name
}
}
var person = new Person('tom')
function Person(name){
this.name = name
}
var person = new Person('jack')
步驟:
1、自動構(gòu)建對象
2、手動設(shè)置屬性
3、自動返回對象
- 通過工廠模式
function factory(name){
var obj = new Object()
obj.name = name
return obj
}
步驟:
1、手動構(gòu)建對象
2、手動設(shè)置屬性
3、手動返回對象
構(gòu)造函數(shù)的缺陷:
構(gòu)造函數(shù)的缺陷:就是里面聲明的函數(shù),會在每次new的時候重新在對應(yīng)的堆上開辟一個內(nèi)存,這樣占用的內(nèi)存就很大,效率就低了。
解決方式 :找一個共享的空間(對象),只聲明一次),將這個函數(shù)放進(jìn)去
- 那么現(xiàn)在這個共享空間應(yīng)該屬于構(gòu)造函數(shù)
- 這個屬于構(gòu)造函數(shù)的空間就被稱為原型
function Person(name){
this.name = name
this.age = 18
this.sayHello = ()=>{
console.log('hello');
}
}
var person = new Person('jack')
var person1 = new Person('tom')
console.log(person == person1);//false 對應(yīng)的存儲地址不一樣
console.log(person.age == person1.age);//true
console.log(person.sayHello == person1.sayHello);//false 函數(shù)也是引用數(shù)據(jù)比較的是地址、
原型:
prototype
概述:prototype是屬于函數(shù)的一個空間,它是一個對象。因為構(gòu)造函數(shù)也是函數(shù)所以它也具備。而這個prototype屬性我們稱為顯式原型。
函數(shù)的prototype
對應(yīng)的這個prototype顯示是一個對象,里面具備對應(yīng)的屬性及方法。主要為方法,那么也就是說這個prototype屬性上一般存放對應(yīng)的方法。
function fn(){
}
console.log(fn.prototype);

構(gòu)造函數(shù)的prototype
function Person(){
}
console.log(Person.prototype);
//獲取當(dāng)前的構(gòu)造函數(shù)
console.log(Person.prototype.constructor);
//將函數(shù)存儲在原型上
Person.prototype.sayHello = ()=>{
console.log(this);
}
//新建對象
var person = new Person()
var person1 = new Person()
console.log(person == person1);//false
//person.sayHello ===> Person.prototype.sayHello
//對于prototype上存儲的內(nèi)容 通過實例對象.屬性名訪問
console.log(person.sayHello == person1.sayHello);//true
///對于prototype上存儲的內(nèi)容 通過實例對象.屬性名訪問
console.log(person.constructor);
- 從上可得構(gòu)造函數(shù)的prototype是一個對象,第二個里面有個屬性 constructor指向當(dāng)前的構(gòu)造函數(shù)。
- 實例對象訪問對于的prototype上的內(nèi)容可以通過實例對象.屬性名訪問
- 一般將對應(yīng)的函數(shù)存儲在對應(yīng)prototype上(這個函數(shù)只會聲明一次)。將函數(shù)存儲在原型,將屬性放在構(gòu)造函數(shù)里面。
- 在prototype里面聲明的函數(shù)的this指向當(dāng)前的調(diào)用的實例對象
__proto__
概述:__proto__稱為隱式原型,它是屬于對象的一個空間,每個對象都存在這個空間,那么對應(yīng)的實例對象也是一個對象,所以它也有這個空間。這個空間指向?qū)?yīng)的構(gòu)造函數(shù)的prototype。
var obj = new Object()
//每個對象都存在的一個空間 它指向?qū)?yīng)的構(gòu)造函數(shù)的prototype
console.log(obj.__proto__);
//對象的__proto__指向?qū)?yīng)的構(gòu)造函數(shù)的prototype
console.log(obj.__proto__ == Object.prototype);
function Person(){
}
var person = new Person()
console.log(person.__proto__ == Person.prototype);
// Person.prototype.sayHello = ()=>{
// }
person.__proto__.sayHello = ()=>{
console.log('hello');
}
person.sayHello()
__proto__的指向:
-
__proto__指向?qū)?yīng)的構(gòu)造函數(shù)的prototype - 構(gòu)造函數(shù)也是一個對象,它的
__proto__指向?qū)?yīng)的父類的構(gòu)造函數(shù)的prototype - Object的
__proto__指向null
//指向Person.prototype
console.log(person.__proto__);
//指向構(gòu)造函數(shù)的原型的原型 構(gòu)造函數(shù)的原型是啥 是一個對象 Object.prototype
console.log(person.__proto__.__proto__);
//指向構(gòu)造函數(shù)的原型的原型 構(gòu)造函數(shù)的原型是啥 是一個對象 Object.prototype 的__proto__是null
console.log(person.__proto__.__proto__.__proto__);
原型鏈:
概述:對象在__proto__上找屬性的鏈?zhǔn)浇Y(jié)構(gòu)被稱為原型鏈。
從__proto__的指向來看,對象在原型上找屬性的過程為:
- 先找自己的
__proto__(對應(yīng)的構(gòu)造函數(shù)的prototype) - 再找對應(yīng)的自身構(gòu)造函數(shù)的原型的
__proto__找到父類構(gòu)造函數(shù)的原型 ,再找對應(yīng)的父類的原型的__proto__,直到找到object為止 - 在Object的原型的
__proto__(null)上還找不到就返回undefinedObject.prototype.hello = '你好' class Person{ constructor(){ this.name = '張三' } } Person.prototype.sex = '女' Person.prototype.username = 'rose' //對象賦值 有就重新賦值 沒有就添加屬性賦值 Person.hi = '你好嗎' var person = new Person() person.age = '109' class Son extends Person{ constructor(){ super() this.age = '李四' } } Son.prototype.sex = '男' //實例化對象 var son = new Son() console.log(son.age);//李四 console.log(son.name);//張三 console.log(son.username);//rose console.log(son.sex);//男 console.log(son.hello);//你好 console.log(son.hi);//undefined

注意事項:
- 原型鏈不包含對象賦值
- 對象賦值的操作是找到這個屬性了重新設(shè)置值
- 沒有找到這個屬性進(jìn)行,添加這個屬性進(jìn)行賦值操作
總結(jié):
- 構(gòu)造函數(shù)的原型prototype
- 實例對象的原型
__proto__ - 實例對象的
__proto__指向構(gòu)造函數(shù)的prototype - 原型鏈通過對應(yīng)的對象的
__proto__去找對應(yīng)的屬性 直到找到Object為止 - 原型一般上面寫函數(shù),可以保證函數(shù)只聲明一次。對應(yīng)的屬性寫在構(gòu)造函數(shù)內(nèi)。
- 原型上的方法/屬性。通過實例對象.屬性名直接訪問(平常通過對象去點的方法都稱為原型方法)
- 在對應(yīng)的原型上的函數(shù)里面的this指向當(dāng)前調(diào)用的實例對象
通過原型來實現(xiàn)數(shù)組的高階函數(shù)
forEach實現(xiàn)和map實現(xiàn)
//數(shù)組的原型
//在數(shù)組的原型上添加一個myForEach的方法
//在對應(yīng)的原型上的函數(shù)里面的this指向當(dāng)前調(diào)用的實例對象
Array.prototype.myForEach = function(fn){
//遍歷
for(let i=0;i<this.length;i++){
fn(this[i],i,this)
}
}
Array.prototype.myMap = function(fn){
let returnArr = []
//遍歷
for(let i=0;i<this.length;i++){
returnArr.push(fn(this[i],i,this))
}
return returnArr
}
reduce實現(xiàn)
//回調(diào)函數(shù) defaultValue初始值
Array.prototype.myReduce = function(fn,defaultValue){
//默認(rèn)請求 前面的值為第一個開始下標(biāo)為第二個
let previousValue = this[0]
let index = 1
//如果傳了初始值 那么對應(yīng)的初始值為傳入的值 開始的下標(biāo)從0開始
if(typeof defaultValue != 'undefined'){
previousValue = defaultValue
index = 0
}
//遍歷
for(let i=index;i<this.length;i++){
previousValue = fn(previousValue,this[i],i,this)
}
return previousValue
}
面向?qū)ο蟮娜筇匦裕?/h4>
- 封裝 (函數(shù)的抽取,屬性的抽?。?/li>
- 繼承 (子類繼承父類)
- 多態(tài) (重寫,子類重寫父類方法)
繼承
概述:子類繼承父類的屬性和方法(非私有的屬性和方法,非靜態(tài)的方法)
繼承的實現(xiàn):
- 使用extends關(guān)鍵詞實現(xiàn)繼承(類的繼承、es6新增)
// es6新增類的繼承 extends關(guān)鍵詞實現(xiàn)
class Person{
constructor(){
this.name = 'jack'
}
}
class Son extends Person{
constructor(age){
super()
this.age = age
}
}
var son = new Son(18)
console.log(`son`, son);
- 原型鏈繼承 (覆蓋之前原型上的所有方法 顯示的時候不會顯示繼承來的屬性 (在原型上重復(fù)出現(xiàn)一樣的屬性))
核心:在子類的原型上創(chuàng)建父類的對象
function Person(){
this.name = 'jack'
}
function Son(age){
this.age = age
}
Son.prototype.say = ()=>{
console.log(`你好`);
}
//原型繼承
// 將要繼承的類放在繼承的子類的原型上
//原型鏈會覆蓋原本原型上的私有的方法及屬性
Son.prototype = new Person()
var son = new Son(18)
console.log(`son`, son);
console.log(son.name);
// son.say()
- 對象冒充 (會顯示繼承的屬性,不能繼承原型上的方法)
核心:更改this指向,在子類中調(diào)用父類的構(gòu)造函數(shù)
function Person(){
this.name = 'jack'
}
function Son(age){
//改this指向 執(zhí)行父類的構(gòu)造函數(shù)
Person.call(this)
this.age = age
}
var son = new Son(18)
console.log(`son`, son);
- 組合繼承 (使用原型鏈繼承和對象冒充結(jié)合)
// 組合繼承 原型鏈繼承加對象冒充
function Person(){
this.name = 'jack'
}
Person.prototype.say = ()=>{
console.log(`hello`);
}
function Son(age){
//改this指向 執(zhí)行父類的構(gòu)造函數(shù)
Person.call(this)
this.age = age
}
//原型鏈繼承
Son.prototype = new Person()
var son = new Son(18)
console.log(`son`, son);
son.say()
- 組合寄生繼承 (對象冒充 + 原型鏈繼承(創(chuàng)建一個原型對象放在原型鏈上))
- 對象冒充
- 在子類的原型上創(chuàng)建父類的原型對象
//組合寄生繼承
function Person(){
this.name = 'jack'
}
Person.prototype.say = ()=>{
console.log(`hello`);
}
function Son(age){
//改this指向 執(zhí)行父類的構(gòu)造函數(shù)
Person.call(this)
this.age = age
}
//寄生
Son.prototype = Object.create(Person.prototype)
var son = new Son(18)
console.log(`son`, son);
ES6的模塊化
概述:模塊的思想,將對應(yīng)的功能代碼封裝為一個模塊(包含js代碼、css代碼、 html代碼)。
注意:
- 想要使用別人就導(dǎo)入,想要給別人用就導(dǎo)出。復(fù)用性強(qiáng)。
模塊化的常用的模式:
- amd (在對應(yīng)的加載之前導(dǎo)入)
- cmd (在用的時候?qū)耄?/li>
- comment.js (基于amd和cmd之上)
es6的模塊化的關(guān)鍵詞(要想導(dǎo)入,必須先導(dǎo)出)
- import 導(dǎo)入
- export 導(dǎo)出
export的使用(三種方式):
- 導(dǎo)出:export default (只能聲明一次)
//默認(rèn)導(dǎo)出只有一個 如果使用export default 導(dǎo)出的可以使用對應(yīng)的一個名字來接
export default {
obj,
str,
say
}
接收:import 名字 from './test.js'
import obj from './test.js'
console.log(obj) //{obj,str,say}
- 導(dǎo)出:export
//如果直接使用的對應(yīng)的export 導(dǎo)出那么必須通過{鍵}來接
export const obj = {
name:'jack',
age:18
}
//如果導(dǎo)出的是值類型 一定要寫變量名
export const str = "你好世界"
export const say = ()=>{
console.log('hello world');
}
接收:import {方法名} from './test.js'
import {obj,str,say} from './test.js'
- 導(dǎo)出:export {只能寫變量}
const name = 'tom'
//第三種導(dǎo)出
export {
//只能寫變量
name
}
接收:import {變量名} from './test.js'
import {name} from './test.js'
import使用:
import 名字 from '地址'