JS高級必須知道的幾個點!

1.1 函數聲明


//ES5

function getSum(){}

function (){}//匿名函數

//ES6()=>{}

//如果{}內容只有一行{}和return關鍵字可省,

1.2 函數表達式(函數字面量)


//ES5

var sum=function(){}

//ES6

let sum=()=>{}//如果{}內容只有一行{}和return關鍵字可省,

1.3 構造函數


var sum=new GetSum(num1,num2)

1.4 三種方法的對比


1.函數聲明有預解析,而且函數聲明的優先級高于變量;

2.使用Function構造函數定義函數的方式是一個函數表達式,這種方式會導致解析兩次代碼,影響性能。第一次解析常規的JavaScript代碼,第二次解析傳入構造函數的字符串


2.ES5中函數的4種調用


在ES5中函數內容的this指向和調用方法有關


2.1 函數調用模式


包括函數名()和匿名函數調用,this指向window


function getSum() {

? ? console.log(this) //window

}

getSum()

(function() {

? ? ? console.log(this) //window

})()

? ? ? var getSum=function() {

? ? console.log(this) //window

}

getSum()

2.2 方法調用


對象.方法名(),this指向對象


var objList = {

? name: 'methods',?

? getSum: function() {?

? ? console.log(this) //objList對象

? }

}

objList.getSum()

2.3 構造器調用


new 構造函數名(),this指向構造函數


function Person() {

? console.log(this); //指向構造函數Person

}

var personOne = new Person();

2.4 間接調用


利用call和apply來實現,this就是call和apply對應的第一個參數,如果不傳值或者第一個值為null,undefined時this指向window


function foo() {

? console.log(this);

}

foo.apply('我是apply改變的this值');//我是apply改變的this值

foo.call('我是call改變的this值');//我是call改變的this值



3.ES6中函數的調用


箭頭函數不可以當作構造函數使用,也就是不能用new命令實例化一個對象,否則會拋出一個錯誤。

箭頭函數的this是和定義時有關和調用無關。

調用就是函數調用模式。


(() => {

? console.log(this)//window

})()

?

let arrowFun = () => {

? console.log(this)//window}

arrowFun()

?

let arrowObj = {

? arrFun: function() {

? (() => {?

? ? console.log(this)//arrowObj

? })()

? }

}

arrowObj.arrFun();



4.call,apply和bind


1.IE5之前不支持call和apply,bind是ES5出來的;

2.call和apply可以調用函數,改變this,實現繼承和借用別的對象的方法;


4.1 call和apply定義


調用方法,用一個對象替換掉另一個對象(this)

對象.call(新this對象,實參1,實參2,實參3.....)

對象.apply(新this對象,[實參1,實參2,實參3.....])


4.2 call和apply用法


1.間接調用函數,改變作用域的this值

2.劫持其他對象的方法


var foo = {

? name:"張三",?

? logName:function(){

? ? console.log(this.name);

? }

}

var bar={

? name:"李四"

};

foo.logName.call(bar);//李四

實質是call改變了foo的this指向為bar,并調用該函數

3.兩個函數實現繼承


function Animal(name){?

? this.name = name;?

? this.showName = function(){?

? ? console.log(this.name);

? }?

}?

function Cat(name){?

? Animal.call(this, name);?

}? ?

var cat = new Cat("Black Cat");?

cat.showName(); //Black Cat

4.為類數組(arguments和nodeList)添加數組方法push,pop


(function(){

? Array.prototype.push.call(arguments,'王五');

? console.log(arguments);//['張三','李四','王五']

})('張三','李四')

5.合并數組


let arr1=[1,2,3];

let arr2=[4,5,6];

Array.prototype.push.apply(arr1,arr2); //將arr2合并到了arr1中

6.求數組最大值


Math.max.apply(null,arr)

7.判斷字符類型


Object.prototype.toString.call({})

4.3 bind


bind是function的一個函數擴展方法,bind以后代碼重新綁定了func內部的this指向,不會調用方法,不兼容IE8。


var name = '李四'

var foo = {

? name: "張三",? ?

? logName: function(age) {?

? console.log(this.name, age);

? }

}

var fooNew = foo.logName;

var fooNewBind = foo.logName.bind(foo);

fooNew(10)//李四,10

fooNewBind(11)//張三,11? 因為bind改變了fooNewBind里面的this指向



5.JS常見的四種設計模式

5.1 工廠模式


簡單的工廠模式可以理解為解決多個相似的問題。


function CreatePerson(name,age,sex) {

? ? var obj = new Object();

? ? obj.name = name;

? ? obj.age = age;

? ? obj.sex = sex;

? ? obj.sayName = function(){? ?

? ? ? ? return this.name;

? ? }? ?

? ? return obj;

}

var p1 = new CreatePerson("longen",'28','男');

var p2 = new CreatePerson("tugenhua",'27','女');

console.log(p1.name); // longen

console.log(p1.age);? // 28

console.log(p1.sex);? // 男

console.log(p1.sayName()); // longen


console.log(p2.name);? // tugenhua

console.log(p2.age);? // 27

console.log(p2.sex);? // 女

console.log(p2.sayName()); // tugenhua?

5.2單例模式


只能被實例化(構造函數給實例添加屬性與方法)一次


// 單體模式

var Singleton = function(name){

? ? this.name = name;

};

Singleton.prototype.getName = function(){

? ? return this.name;

}

// 獲取實例對象

var getInstance = (function() {

? ? var instance = null;? ?

? ? return function(name) {? ?

? ? ? ? if(!instance) {//相當于一個一次性閥門,只能實例化一次

? ? ? ? ? ? instance = new Singleton(name);

? ? ? ? }? ? ? ?

? ? ? ? return instance;

? ? }

})();

// 測試單體模式的實例,所以a===b

var a = getInstance("aa");

var b = getInstance("bb");

5.3 沙箱模式


將一些函數放到自執行函數里面,但要用閉包暴露接口,用變量接收暴露的接口,再調用里面的值,否則無法使用里面的值。


let sandboxModel=(function(){? ?

? ? function sayName(){};? ?

? ? function sayAge(){};? ?

? ? return{? ?

? ? ? ? sayName:sayName,

? ? ? ? sayAge:sayAge

? ? }

})()

5.4 發布者訂閱模式


就例如如我們關注了某一個公眾號,然后他對應的有新的消息就會給你推送


//發布者與訂閱模式

? ? var shoeObj = {}; // 定義發布者

? ? shoeObj.list = []; // 緩存列表 存放訂閱者回調函數


? ? // 增加訂閱者

? ? shoeObj.listen = function(fn) {

? ? ? ? shoeObj.list.push(fn); // 訂閱消息添加到緩存列表

? ? }


? ? // 發布消息

? ? shoeObj.trigger = function() {

? ? ? ? ? for (var i = 0, fn; fn = this.list[i++];) {

? ? ? ? ? ? ? fn.apply(this, arguments);//第一個參數只是改變fn的this,

? ? ? ? ? ? }

? ? ? ? }

? ? // 小紅訂閱如下消息

? ? shoeObj.listen(function(color, size) {? ?

? ? ? ? console.log("顏色是:" + color);? ? ? ?

? ? ? ? console.log("尺碼是:" + size);

? ? });

? ? ? ?

? ? // 小花訂閱如下消息

? ? shoeObj.listen(function(color, size) {? ?

? ? ? ? console.log("再次打印顏色是:" + color);? ? ? ?

? ? ? ? console.log("再次打印尺碼是:" + size);

? ? });

? ? shoeObj.trigger("紅色", 40);

? ? shoeObj.trigger("黑色", 42);?

代碼實現邏輯是用數組存貯訂閱者, 發布者回調函數里面通知的方式是遍歷訂閱者數組,并將發布者內容傳入訂閱者數組。




6.原型鏈


6.1 定義


對象繼承屬性的一個鏈條


6.2構造函數,實例與原型對象的關系


var Person = function (name) { this.name = name; }//person是構造函數

var o3personTwo = new Person('personTwo')//personTwo是實例



原型對象都有一個默認的constructor屬性指向構造函數

6.3 創建實例的方法


1.字面量


let obj={'name':'張三'}

2.Object構造函數創建


let Obj=new Object()

Obj.name='張三'

3.使用工廠模式創建對象


function createPerson(name){

var o = new Object();

o.name = name;

};

return o;

}

var person1 = createPerson('張三');

4.使用構造函數創建對象


function Person(name){

this.name = name;

}

var person1 = new Person('張三');

6.4 new運算符


1.創了一個新對象;

2.this指向構造函數;

3.構造函數有返回,會替換new出來的對象,如果沒有就是new出來的對象

4.手動封裝一個new運算符


var new2 = function (func) {

? ? var o = Object.create(func.prototype); //創建對象

? ? var k = func.call(o);          //改變this指向,把結果付給k

? ? if (typeof k === 'object') {      //判斷k的類型是不是對象

? ? ? ? return k;              //是,返回k

? ? } else {? ?

? ? ? ? return o;               //不是返回返回構造函數的執行結果

? ? }

}?

6.5 對象的原型鏈





7.繼承的方式


JS是一門弱類型動態語言,封裝和繼承是他的兩大特性


7.1原型鏈繼承

將父類的實例作為子類的原型

1.代碼實現

定義父類:


// 定義一個動物類

function Animal (name) {

? // 屬性

? this.name = name || 'Animal';

? // 實例方法

? this.sleep = function(){?

? ? console.log(this.name + '正在睡覺!');

? }

}

// 原型方法

Animal.prototype.eat = function(food) {

? console.log(this.name + '正在吃:' + food);

};

子類:


function Cat(){

}

Cat.prototype = new Animal();

Cat.prototype.name = 'cat';


// Test Code

var cat = new Cat();

console.log(cat.name);//cat

console.log(cat.eat('fish'));//cat正在吃:fish? undefined

console.log(cat.sleep());//cat正在睡覺! undefined

console.log(cat instanceof Animal); //true

console.log(cat instanceof Cat); //true

2.優缺點

簡單易于實現,但是要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之后執行,無法實現多繼承


7.2 構造繼承


實質是利用call來改變Cat中的this指向

1.代碼實現

子類:


function Cat(name){

? Animal.call(this);

? this.name = name || 'Tom';

}

2.優缺點

可以實現多繼承,不能繼承原型屬性/方法


7.3 實例繼承


為父類實例添加新特性,作為子類實例返回

1.代碼實現

子類


function Cat(name){

? var instance = new Animal();

? instance.name = name || 'Tom';

? return instance;

}

2.優缺點

不限制調用方式,但不能實現多繼承


7.4 拷貝繼承


將父類的屬性和方法拷貝一份到子類中

1.子類:


function Cat(name){

? var animal = new Animal();

? for(var p in animal){

? ? Cat.prototype[p] = animal[p];

? }

? Cat.prototype.name = name || 'Tom';

}

2.優缺點

支持多繼承,但是效率低占用內存


7.5 組合繼承


通過調用父類構造,繼承父類的屬性并保留傳參的優點,然后通過將父類實例作為子類原型,實現函數復用

1.子類:


function Cat(name){

? Animal.call(this);

? this.name = name || 'Tom';

}

Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

7.6 寄生組合繼承


function Cat(name){

? Animal.call(this);

? this.name = name || 'Tom';

}

(function(){

? // 創建一個沒有實例方法的類

? var Super = function(){};

? Super.prototype = Animal.prototype;

? //將實例作為子類的原型

? Cat.prototype = new Super();

})();

7.7 ES6的extends繼承


ES6 的繼承機制是先創造父類的實例對象this(所以必須先調用super方法),然后再用子類的構造函數修改this,


class ColorPoint extends Point {

? constructor(x, y, color) {

? ? super(x, y); // 調用父類的constructor(x, y)

? ? this.color = color;

? }


? toString() {? ? return this.color + ' ' + super.toString(); // 調用父類的toString()

? }

}?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 工廠模式類似于現實生活中的工廠可以產生大量相似的商品,去做同樣的事情,實現同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,827評論 2 17
  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創建,需要時才創建 最常見的單例模式,...
    Obeing閱讀 2,093評論 1 10
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,046評論 0 2
  • 魯家廟的廟早就不存在了,只剩下人們對它的回憶,以及那處名叫“廟道口”的地名。 據老人們講述,那所廟里原來是有和尚的...
    草石閱讀 821評論 0 1
  • 哈哈!今天又是忙碌的一天,答應給兒子包多彩的餃子,我今天的兌現,不然0當媽的說話不算數,以后怎么教育...
    愛你的貝貝閱讀 206評論 0 4