JSLearning
標(biāo)簽(空格分隔): 前端學(xué)習(xí)
基礎(chǔ)
值類型
- Undefine
- Null
- Boolean
- Number
- String
引用類型
- Object
Object支持動態(tài)創(chuàng)建屬性
var person = new Object();
person.name = "Hello JavaScript";
alert(person .name);
檢測類型
var s = "Nicholas" ;
alert(typeof s); //string
person = new Object ();
alert(person instanceof Object );//true
RegExp
var expression1 = /[bc]at/i
var expression2 = new ReqExp("[bc]at","i");
正則表達(dá)式字符串匹配元字符以及已經(jīng)轉(zhuǎn)義過的字符需要雙重轉(zhuǎn)義
元字符:( [ { \ ^ $ | ) ? * + . ] }需要轉(zhuǎn)義成
"\\["
等
已轉(zhuǎn)義的字符:\n \ 需要轉(zhuǎn)義成"\\n" "\\\\"
Function
函數(shù)本質(zhì)上一個對象,是Function類型的實例。
//函數(shù)聲明
function sum (num1,num2) {
return num1 + num2;
}
//函數(shù)表達(dá)式
var sum = function(num1, num2) {
return num1 + num2;
}
var sum = new Function("num1","num2","return num1 + num2");//不推薦
//這三種都是定義一個函數(shù)削彬,但是sum可以改變的啼县,僅僅是一個指針
沒有重載的概念
函數(shù)聲明和函數(shù)表達(dá)式的區(qū)別
解析器在加載數(shù)據(jù)的時候囊卜,會率先讀取函數(shù)聲明端仰,并使其在執(zhí)行任何代碼之前可用沛鸵;治愈函數(shù)表達(dá)式噪矛,則必須等解析器執(zhí)行到它所在的代碼行医清,才會被真正正確的解釋執(zhí)行起暮。
alert(sum(10,10));
function sum (num1,num2) {
return num1 + num2;
}
//以上代碼ok
alert(sum(10,10));
var sum = function(num1, num2) {
return num1 + num2;
}
//以上代碼error
函數(shù)可以當(dāng)參數(shù),也可以當(dāng)返回值
函數(shù)的內(nèi)部屬性
*arguments(傳入函數(shù)的所有參數(shù))
*arguments.callee(正在被執(zhí)行的函數(shù)對象)
*arguments.callee.caller(當(dāng)前函數(shù)的調(diào)用方)
*this(執(zhí)行的環(huán)境對象会烙,網(wǎng)頁的全局域中調(diào)用的時候,this就是window,如果作為一個對象的屬性調(diào)用负懦,比如o.sum(10,10),this就是o這個對象)
函數(shù)屬性和方法
*length 參數(shù)的數(shù)量
*prototype
*call,apply 設(shè)定函數(shù)的作用域,即this的值
*bind 綁定函數(shù)的作用域柏腻,即this的值
基本的包裝類型
特殊的引用類型
*Boolean
*Number
*String
面向?qū)ο蠡A(chǔ)
對象是無序?qū)傩缘募现嚼鳎鋵傩钥梢园局怠ο蠡蛘吆瘮?shù)五嫂。
//對象定義
var person = {
name:"Nicholas",
age:29,
job:"Software Engineer",
sayName:function(){
alert(this.name);
}
}
數(shù)據(jù)屬性
- Configurable:是否可以通過delete刪除屬性
- Enumerable:是否可以通過for-in循環(huán)返回屬性
- Writable:是否可寫
- Value:屬性的數(shù)據(jù)值
對象直接定義和通過
defineProperty
定義屬性的時候以上的各個值默認(rèn)值不一樣颗品,前者都是true,后者都是false,但value都是undefine。
訪問器屬性
- Configurable
- Enumerable
- Get 讀取屬性時調(diào)用的函數(shù)
- Set 寫入時調(diào)用的函數(shù)
對象直接定義和通過
defineProperty
定義屬性的時候以上的各個值默認(rèn)值不一樣沃缘,前者都是true,后者都是false,但get & set 都是undefine躯枢。
var book = {
_year:2004,
edition:1
}
Object.defineProperty(book,"year",{
get:function(){
return this._year
}
set:function(newValue) {
if (newValue > 2004) {
this.year = newValue;
this.edition = newValue - 2004;
}
}
});
book.year = 2005;
alert(bool.edition)
讀取屬性的特性
Object.getOwnPropertyDescriptor
創(chuàng)建對象
工廠模式
function createPerson(name,age,job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
}
return o;
}
構(gòu)造函數(shù)模式
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
}
}
var person1 = new Person("Greg",27,"Doctor");
//person1會有一個construtor(構(gòu)造函數(shù))屬性 指向Person
使用new加構(gòu)造函數(shù)創(chuàng)建實例會經(jīng)歷以下4個步驟
- 創(chuàng)建一個新的對象
- 將構(gòu)造函數(shù)的作用域賦給對象(因此this指向了這個新對象)
- 執(zhí)行構(gòu)造函數(shù)中的代碼(為這個對象添加屬性)
- 返回新的對象
對象類型檢測
alert(person1 instanceof Person);//true;
alert(person1 instanceof Object);//true
構(gòu)造函數(shù)的問題
屬性時函數(shù)對象的對象,會重復(fù)創(chuàng)建槐臀。
原型模式
每個函數(shù)都有一個prototype屬性锄蹂,是一個指針,指向一個對象水慨,作用是讓實例共享屬性和方法得糜。
原型對象的理解
function Person() {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person();
person1.sayName();//訪問原型對象的
- Person(函數(shù)對象)
- Peron.prototype(原型對象)
- person1(實例)
函數(shù)對象通過prototype屬性訪問原型對象,原型對象可以通過constructor對象訪問函數(shù)對象晰洒,實例對象可以通過[[Prototype]]訪問原型對象朝抖。
每當(dāng)讀取實例的某個屬性的時候,都會執(zhí)行一個搜索谍珊,首先搜索實例本身治宣,然后沿著原型鏈搜索。
原型鏈:通過[Prototype]]屬性連接起來砌滞,末端是Object.prototype
調(diào)用實例函數(shù)的時候炼七,即使這個函數(shù)是原型對象定義,函數(shù)中的this依然指向當(dāng)前實例
對象中新增一個和原型對象重名屬性時,不會重寫原型的值布持,而是新增一個屬性豌拙,并屏蔽原型對象的屬性
hasOwnProperty()
判斷某個屬性是否是實例屬性。
!object.hasOwnProperty(name) && (name in object)
判斷name是object原型對象的方法
原型的動態(tài)性
實例創(chuàng)建后修改原型题暖,也能從實例中反映出來按傅。
組合使用構(gòu)造函數(shù)模式和原型模式
最常用的創(chuàng)建對象的方式
function Person(name,age,job) {
this.name = name;
this.age = age;
this.jog = job;
this.friends = ["shelby","court"];
}
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person("Nicholas",29,"Doctor");
//實例屬性在構(gòu)造函數(shù)中定義捉超,所有實例共享原型對象的屬性,這個是默認(rèn)模式
動態(tài)原型模式
function Person(name,age,job) {
this.name = name;
this.age = age;
this.jog = job;
if (typeof this.sayName != "function") {
Person.prototype.sayName = function() {
alert(this.name);
}
}
}
繼承
原型鏈繼承
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType() {
this.subProperty = false;
}
//繼承了SuperType
SubType.prototype = new SuperType();
//修復(fù)constructor
SubType.prototype.constructor = SubType;
SubType.prototype.getSubVale = function() {
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());//true
以上代碼最終形成這樣的關(guān)系
SubType實例 -> SuperType實例(SubType.prototype) -> SuperType.prototype(Object實例) -> Object.prototype
SubType繼承SuperType,SuperTyper繼承Object
所有類型默認(rèn)都繼承Object類型唯绍,原因是默認(rèn)原型都是Object的實例拼岳,指向了Object.prototype。
確定原型和實例的關(guān)系
alert(instance instanceof Object);//true
alert(instance instanceof SuperType);//true
alert(instance instanceof SubType);//true
給原型添加新方法况芒,一定要放在替換原型語句之后
單純的原型鏈問題:父類如果定義屬性惜纸,被子類繼承的時候,會被各個子類的實例共享绝骚,創(chuàng)建子類類型的時候耐版,不能像父類傳遞屬性。
構(gòu)造函數(shù)繼承
function SupetType(name) {
this.name = name;
}
function SubType() {
//繼承了SuperType,同時還傳遞了參數(shù)
SuperType.call(this,"Nicholas");
//實例屬性
this.age = 29;
}
var instance = new SubType();
alert(instance.name);//Nicholas;
alert(instance.age);//29
借用構(gòu)造函數(shù)的問題:函數(shù)屬性在構(gòu)造函數(shù)內(nèi)部定義压汪,無復(fù)用粪牲,超類型原型中定義的方法,對子類不可見止剖。
組合模式
最常用的繼承方式
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function() {
alert(this.name);
};
function SubType(name,age) {
//繼承屬性
SuperType.call(this,name);
//子類屬性
this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();
//修正constructor
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
alert(this.age);
};
var instance1 = new SubType("Nicholas",29);
instance1.colors.push("black");
alert(instance1.colors);//"red,blue,green,black"
instance1.sayName();///Nicholas
instance1.sayAge();//29
var instance2 = new SubType("Greg",27);
alert(instance2.colors);//"red,bule,green"
instance2.sayName();//Greg
instance2.sayAge();//27
淺復(fù)制
var person = {
name:"Nicholas",
friends:["Shelby","Court","Van"]
}
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends);//"Shelby,Court,Van,Rob,Barbie"
//覆蓋同名屬性
var haAnotherPerson = Object.create(person,{
name:{
value:"Greg"
}});
alert(anotherPerson.name);//Greg
//這個函數(shù)的作用和Object.create傳入一個參數(shù)時行為相同
function object(o) {
function F(){}
F.prototype = o;
return new F();
}
寄生組合式繼承
最理想的繼承范式
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function() {
alert(this.name);
};
function SubType(name,age) {
//繼承屬性
SuperType.call(this,name);
//子類屬性
this.age = age;
}
function object(o) {
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType,superType) {
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function() {
alert(this.age);
};
var instance1 = new SubType("Nicholas",29);
instance1.colors.push("black");
alert(instance1.colors);//"red,blue,green,black"
instance1.sayName();///Nicholas
instance1.sayAge();//29
var instance2 = new SubType("Greg",27);
alert(instance2.colors);//"red,bule,green"
instance2.sayName();//Greg
instance2.sayAge();//27
函數(shù)表達(dá)式
//函數(shù)聲明提升腺阳,調(diào)用可以放在聲明前
sayHi();
function sayHi() {
alert("Hi!");
}
//函數(shù)表達(dá)式,錯誤穿香,函數(shù)還不存在
sayHi();
var sayHi = function() {
alert("Hi!");
}
遞歸
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num-1);
}
}
//命名函數(shù)表達(dá)式
var factorial = (function f(num) {
if (num <= 1) {
return 1;
} else {
return num * f(num-1);
}
})
閉包
類似于block,定義的時候可以引用外部變量亭引,并持有。
function crateComparisonFunction(propertyName) {
return function(object1,object2) {
//引用了propertyName
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {u
retrn 0;
}
};
}
閉包和變量
function createFunctions() {
var result = new Array();
for (var i = 0;i < 10; i++) {
result[i] = function() {
return i;
}
}
//result數(shù)組中 每個函數(shù)變量i都是10 不是copy 只是引用
return result;
}
function createFunctions() {
var result = new Array();
for (var i = 0;i < 10;i++) {
result[i] = function(num){
return function() {
return num;
}
}(i);
}
//result數(shù)組中 每個函數(shù)的變量num就是從0到9
return result;
}
關(guān)于this
var name = "The Window";
var object = {
name:"My Object".
getNameFunc:function() {
return function() {
return this.name;
}
}
}
alert(object.getNameFunc()());//"The Window";
//這個調(diào)用和以上相同 所以this=window.
var f = object.getNameFunc();
alert(f();)
var name = "The Window";
var object = {
name:"My Object".
getNameFunc:function() {
var that = this;
return function() {
return that.name;
}
}
}
alert(object.getNameFunc()());//"My Object";
內(nèi)存泄露
function assignHandler() {
var element = document.getElementById("someElement");
//循環(huán)引用
element.onclick = function() {
alert(element.id);
}
}
//破除循環(huán)引用
function assignHandler() {
var element = document.getElementById("someElement");
var id = element.id;
//循環(huán)引用
element.onclick = function() {
alert(id);
}
//局部變量設(shè)置為null,閉包也不會引用element皮获,就不會循環(huán)引用了焙蚓。
element = null;
}
閉包會引用包含函數(shù)的局部變量,即使沒有直接引用局部變量魔市,進(jìn)而閉包會持有局部變量指向的對象,要破除這種持有赵哲,可以將局部變量設(shè)置為null在包含函數(shù)結(jié)束前待德。
模仿塊級作用域
(function() {
//這里是塊級作用域
})();
私有變量
funciton MyOject() {
//私有變量和私有函數(shù)
var privateVariable = 10;
function privateFunction() {
return false;
}
//特權(quán)方法
this.publicMethod = function() {
privateVariable++;
return privateFunction();
}
}
var object = new MyObject();
alert(object.publicMethod);
靜態(tài)私有變量
(function() {
//私有變量和私有函數(shù)
var privateVariable = 10;
function privateFunction() {
return false;
}
//構(gòu)造函數(shù) 未經(jīng)聲明的變量,會創(chuàng)建一個全局變量枫夺。
MyObject = function() {
};
//公有/特權(quán)方法
MyOject.prototype.publicMethod = function() {
privateVariable++;
return privateFunction();
};
})
模塊模式
var singleton = function() {
//私有變量和函數(shù)
var privateVariable = 10;
function privateFunction() {
return false;
}
//公有方法和屬性
return {
publicProperty:true,
publicMethod:function() {
privateVariable++;
return privateFunction();
}
}
}();
增強的模塊模式
var singleton = function() {
//私有變量和函數(shù)
var privateVariable = 10;
function privateFunction() {
return false;
}
//創(chuàng)建對象
var object = new CustomType();
//添加公有方法和屬性
object.publicProperty = true;
object.publicMethod = function() {
privateVariable++;
return privateFunction();
};
return object;
}();