一、js函數
首先弄明白何為函數呢,按照犀牛書的說法,函數簡單的說就是重復執行的代碼塊。函數是這樣的一段JavaScript 代碼,它只定義一次,但可能被執行或調用任意次。
函數的定義方式:
1.聲明式函數定義: function 函數名 (){};這種定義方式,會將函數聲明提升到該函數所在作用域的最開頭,也是就無論你在這個函數的最小作用域的那兒使用這種方式聲明的函數,在這個作用域內,你都可以調用這個函數為你所用。
2.函數表達式:let fun = function(){}; 此方式定義的函數,只能在該作用域中,這段賦值代碼執行之后才能通過fun()調用函數,否則,由於變量聲明提升,fun === undefined。
3.new Function 形式: var fun1 = new Function (arg1 , arg2 ,arg3 ,…, argN , body );Function構造函數所有的參數都是字符串類型。除了最后一個參數, 其余的參數都作為生成函數的參數即形參。這里可以沒有參數。最后一個參數, 表示的是要創建函數的函數體。
總結:1 、第一種和第二種函數的定義的方式其實是第三種new Function 的語法糖,當我們定義函數時候都會通過 new Function 來創建一個函數,只是前兩種為我們進行了封裝,我們看不見了而已,js 中任意函數都是Function 的實例。2、ECMAScript 定義的 函數實際上是功能完整的對象。
二、構造函數
定義:通過 new 函數名 來實例化對象的函數叫構造函數。任何的函數都可以作為構造函數存在。之所以有構造函數與普通函數之分,主要從功能上進行區別的,構造函數的主要 功能為 初始化對象,特點是和new 一起使用。new就是在創建對象,從無到有,構造函數就是在為初始化的對象添加屬性和方法。構造函數定義時首字母大寫(規范)。
對new理解:new 申請內存, 創建對象,當調用new時,后台會隱式執行new Object()創建對象。所以,通過new創建的字符串、數字是引用類型,而是非值類型。
1、常用的構造函數:
1. var arr = []; 為 var arr = new Array(); 的語法糖。
2. var obj = {} 為 var obj = new Object(); 的語法糖
3. var date = new Date();
4. ...
2、執行構造函數時發生的事 : let f = new Foo();
function Foo(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Foo.prototype.belief = function(){
console.log('量變是質變的必要准備,質變是量變積累到一定程度的必然結果!');
}
let f = new Foo ('zh',18,'男');
a . let f = {}; //一個繼承自 Foo
.prototype
的新對象被創建。
b. f.__proto__ = Foo.prototype; // f 繼承 Foo的原型。
b Foo.call(f,'zh',18,'男'); //執行Foo函數,將name,age,sex 參數傳入Foo中執行,此時函數內部this 為 new 創建的 f對象,所以 f.name = 'zh';f.age = 18; f.sex = '男';
c. 實例化對象完成,此時 f = {
name:'zh',
age:18,
sex:'男'
}
d. f.belief(); 打印'量變是質變的必要准備,質變是量變積累到一定程度的必然結果!
手寫new函數
function newTest (constructFunction){
let obj = {};
obj.__proto__ = constructFunction.prototype;
return function(){
constructFunction.apply(obj,arguments);
return obj;
}
}
注意:當構造函數中有返回對象時候,最終new出來的對象會是構造函數的返回值,而不是new過程中生成的對象。僅當構造函數返回值是對象時有效,當不是對象時依舊返回new過程中形成的對象(無論如何new 構造函數之后都會返回一個對象值)。
三、ES6 中 class 與構造函數的關系
class 為 構造函數的語法糖,即 class 的本質是 構造函數。class的繼承 extends 本質 為構造函數的原型鏈的繼承。
例如:
類的寫法
class Person{ //定義一個名字為Person的類
constructor(name,age){ //constructor是一個構造方法,用來接收參數
this.name = name; //this代表實例對象
this.age = age;
}
say(){ //這是一個類的方法,注意千萬不要加上function
return this.name + this.age
}
}
var obj = new Person('老鐵',18);
console.log(obj.say());
構造函數的寫法
function Person(name,age){ //構造函數和實例化構造名相同且大寫(非強制,但這么寫有助於區分構造函數和普通函數)
if(!(this instanceof Person)){ //避免使用者不小心講Person當作普通函數執行
throw new Error(''請使用 new Person"); //仿ES6 class 中的寫法
}
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
return this.name + this.age
}
var obj = new Person('老鐵',18); //通過構造函數創建對象,必須使用new運算符
console.log(obj.say());
總結:通過class定義的類 和通過構造函數定義的類 二者本質相同。並且在js執行時,會將第一種轉會為第二種執行。所以 ES6 class的寫法實質就是構造函數。