一伍绳、面向?qū)ο缶幊?/h3>
-
對象:包括字符串 數(shù)組 自定義對象等,萬物皆對象
對象是單個(gè)事物的抽象乍桂,包含屬性和行為(方法冲杀,功能)
一個(gè)容器,封裝了屬性和方法睹酌,面向?qū)ο笕ㄋ褪菍傩院头椒ǚ庋b到幾個(gè)對象中;
要用的話憋沿,直接調(diào)用就可以
面向?qū)ο蟮奶匦裕悍庋b性 繼承性 【多態(tài)性】抽象
對象:包括字符串 數(shù)組 自定義對象等,萬物皆對象
對象是單個(gè)事物的抽象乍桂,包含屬性和行為(方法冲杀,功能)
一個(gè)容器,封裝了屬性和方法睹酌,面向?qū)ο笕ㄋ褪菍傩院头椒ǚ庋b到幾個(gè)對象中;
要用的話憋沿,直接調(diào)用就可以
面向?qū)ο蟮奶匦裕悍庋b性 繼承性 【多態(tài)性】抽象
2.打印學(xué)生的成績旺芽,使用對象的方法
3.面向?qū)ο蟮脑O(shè)計(jì)思想
抽象除Class(構(gòu)造函數(shù)) 根據(jù)Class(構(gòu)造函數(shù))創(chuàng)建Instance(實(shí)例) 指揮Instance得結(jié)果
4.創(chuàng)建對象的幾種方式
方法1.
var a=new Object(); 這樣有一點(diǎn)麻煩
a.name="Bob";
a.age=18辐啄;
a.sayName=function(){
}
方法2.
var a={name:"Bob";age:18采章;sayName:function(){ } }
? 字面量方法容易重復(fù)
方法3.封裝一個(gè)工廠函數(shù)
方法4.自定義構(gòu)造函數(shù)
5.實(shí)例成員:在構(gòu)造函數(shù)內(nèi)部添加給this的成員,在創(chuàng)建實(shí)例是必須由對象調(diào)用
靜態(tài)成員:添加構(gòu)造函數(shù)自身的成員壶辜,只能由構(gòu)造函數(shù)調(diào)用 如: Math.PI 調(diào)用圓周率
6.多個(gè)對象中有公共的屬性悯舟,每次調(diào)用會浪費(fèi)內(nèi)存,解決方法一:
將公共的函數(shù)提前到構(gòu)造函數(shù)之外:
function sayName(){`
`console.log(this.name);`
`}`
`function Person(name,age,sex) {`
this.name=name; --用this替代新對象person砸民,不需要創(chuàng)建一個(gè)空對象Object`
this.age=age;
this.type=human;
this.sayName=sayName;}
`var p1= new Person(“zs”抵怎,18,true);`
`p1.sayName ();`
解決方法二:將公共的函數(shù)封裝到一個(gè)對象中;然后在后面繼續(xù)寫構(gòu)造函數(shù)
var fns={sayName:function() {
console.log(this.name)};
sayAge:function() {
console.log(this.age)};
}
7.解決方法三:使用原型對象:prototype對象阱洪,可以解決內(nèi)存浪費(fèi)問題
1.任何函數(shù)都有prototype屬性:構(gòu)造函數(shù)也不例外便贵,屬性值是一個(gè)對象,通常叫做
原型對象冗荸,這個(gè)對象內(nèi)部可以添加一些屬性和方法:比如上面構(gòu)造函數(shù)Person進(jìn)行操作
添加屬性和方法:
Person.prototype.type="human" ;Person.prototype.sayHi=function(){ 函數(shù)內(nèi)容};
構(gòu)造函數(shù)的原型對象的constructor屬性(對象都有這個(gè)屬性):指向自己Person這個(gè)構(gòu)造函數(shù):
console.log(**Person.prototype.constructor** )
輸出為Person這個(gè)函數(shù)
8.所有的對象都有——proto——_的屬性:是一個(gè)指針承璃,指向的就是生成實(shí)例對象的構(gòu)造函數(shù)的原型對象,即 實(shí)例對象的——proto——屬性指向的是這個(gè)實(shí)例對象的原構(gòu)造函數(shù)的prototype屬性
——proto——屬性不是一個(gè)標(biāo)準(zhǔn)的屬性蚌本,是瀏覽器自己根據(jù)語法自動生成的
p1.——proto——.saiHi()=Person.prototype.saiHi() ,不過一般簡寫成p1.sayHi() 即可
同樣p1.——proto——.constructor=p1.constructor ,輸出是構(gòu)造函數(shù)Person
9.每個(gè)構(gòu)造函數(shù)的prototype屬性指向他的原型對象盔粹,而這個(gè)原型對象的所有屬性和方法,都會被構(gòu)造函數(shù)的實(shí)例對象所擁有程癌,因此:
我們可以把實(shí)例對象需要共享的屬性和方法直接定義在prototype對象上舷嗡,優(yōu)化解決方法二:將所有實(shí)例共享的屬性和方法,如之前構(gòu)造函數(shù)中的type=human屬性 以及sayName 方法嵌莉,都添加給原型對象:
Person.prototype.type=human;
Person.prototype.sayName=function(){console.log(this.name)};
p1.sayName();
//調(diào)用即可
Person構(gòu)造函數(shù)的原型對象也是對象进萄,是對象就有原型對象,所以生成的實(shí)例對象的原型對象的原型對象是一個(gè)叫做Object函數(shù)的原型對象,而這個(gè)Object的原型對象指向的是一個(gè)空指針null中鼠;關(guān)系圖可婶,也就是原型鏈:10.原型鏈:
12.實(shí)例對象讀寫原型對象成員
先在自己身上找,找不到的話會沿著原型鏈向上查找援雇,如果一直到原型鏈的末端都沒有找到矛渴,則返回undefined;
通過實(shí)例對象更改或添加原型對象的屬性和方法惫搏,會直接添加給自己具温,會屏蔽對原型對象的訪問
通過實(shí)例對象更改或添加原型對象中復(fù)雜類型的數(shù)據(jù),如果自己沒有找到筐赔,會沿著原型鏈繼續(xù)查找:
如添加一個(gè)性別屬性 p1.sex="male"
铣猩,然后console.dir(p1)
會在自己身上找到,但是在自己的原型對象之上沒有這個(gè)新加的屬性 川陆;
如添加一個(gè)方法: p1.sayAge=function(){} 同樣輸出console.dir(p1)
剂习,這個(gè)方法只添加在自己身上
如果通過實(shí)例對象更改原型對象的屬性和方法:
p1.type="person"
(原來是 human),同樣輸出console.dir(p1)
较沪, 發(fā)現(xiàn)這個(gè)實(shí)例對象增加了一個(gè)type="person"的屬性,而他的原型對象p1.--ptoto--
上的type="human"還是沒有變化失仁,添加方法也一樣的
如果添加一個(gè)新的屬性給原型對象尸曼,是一個(gè)對象類型,city:beijng,
如:``
Person.prototype.address={city:"beijing"}
通過實(shí)例對象更改:
p1.address.city="shanghai "
會在原型鏈中進(jìn)行查找萄焦,
輸出p1這個(gè)實(shí)例對象控轿,會發(fā)現(xiàn)在自己身上沒有修改,而是修改到p1的實(shí)例對象p1.--proto--
上了
13.更簡單的原型語法
每添加一個(gè)屬性和方法都要寫一Person.prototype
拂封,比較麻煩茬射,因此使用一個(gè)對象字面量 對
對象原型進(jìn)行賦值 ,如:
Person.prototype={
type:"human";
sayName:function(){console.log(this.name)}
}
這樣會丟失constractor
成員冒签,因此要手動添加contractor屬性指向正確的構(gòu)造函數(shù)
Person.prototype`={
type:"human"在抛,
constractor:Person, 手動添加contractor屬性指向正確的構(gòu)造函數(shù)
sayName:function(){console.log(this.name)}萧恕;}
一般將私有成員(非函數(shù))放到構(gòu)造函數(shù)中刚梭,將公共成員(一般是函數(shù))放到原型對象中,充
重置了Person.prototype
記得手動添加contractor屬性指向正確的構(gòu)造函數(shù)
14.內(nèi)置構(gòu)造函數(shù)的原型對象
Object.prototype Function.prototype String.prototype Array.prototype
一般不允許更改內(nèi)置而構(gòu)造函數(shù)的原型對象
15.自調(diào)用函數(shù)IIFE:表示函數(shù)在定義時(shí)就立即調(diào)用票唆,如果將一個(gè)函數(shù)矮化成一個(gè)表達(dá)式朴读,就可以在后面添加()進(jìn)行調(diào)用
通過在函數(shù)前面添加操作符,可以讓函數(shù)矮化成表達(dá)式 如+ - ()走趋! 四種方式衅金、
最常用的是(),將函數(shù)用()包裹起來,可以關(guān)住函數(shù)的作用域氮唯,在外部是不能進(jìn)行
調(diào)用的
(function(a) {
console.log(a)} (1); 用完之后后面就用不了了鉴吹,類似于一次性函數(shù),后面括號里
是實(shí)參您觉,輸出為 1
補(bǔ)充:函數(shù)調(diào)用的方式拙寡,函數(shù)名或函數(shù)表達(dá)式后加(),自調(diào)用函數(shù)就是一個(gè)函數(shù)表達(dá)式加了
()琳水,這個(gè)函數(shù)表達(dá)式用()把原函數(shù)矮化成立表達(dá)式
自調(diào)用函數(shù)可以封閉作用域
二肆糕、隨機(jī)方塊
1.以對象字面量的方式,封裝一個(gè)tools對象在孝,里面添加獲取隨機(jī)整數(shù)的方法getRandom,
诚啃,MDN上有,直接用
在添加一個(gè)獲取隨機(jī)顏色的方法:給rgb(r,g,b)
中的r g b獲取0-255的隨機(jī)值私沮,調(diào)用getRandom
方法始赎,用this調(diào)用,最后返回一個(gè)顏色值: return "rgb("+r+""+g+""+b+")"
2.自定義一個(gè) 隨機(jī)方塊 的構(gòu)造函數(shù)仔燕,設(shè)置方塊的寬高 背景顏色 定位位置
function Block( option){ 參數(shù)option是一個(gè)對象造垛,里面包含寬高 顏色 定位等方塊的屬性
option=option||{ };
this.width=option.width||20;
this.height=option.height||20;
this.backgroundColor=option.backgroundColor||"red";
this.x=option.x||0;
this.y=option.y||0;
}
三、貪吃蛇
1.創(chuàng)造Food的構(gòu)造函數(shù)晰搀,設(shè)置寬高 位置 顏色 的屬性
通過原型設(shè)置方法五辽,將事物渲染到大的盒子map上
onkeydown
按鍵按下事件 鍵盤編碼 37:左鍵
38:上鍵 39:右鍵 40:下鍵
window.Food=Food
利用window對象增加一個(gè)food屬性,屬性值就是food的構(gòu)造函數(shù)外恕,可以把food 的構(gòu)造函數(shù)在外部進(jìn)行調(diào)用杆逗,在外部生成對象實(shí)例
2.思路:根據(jù)游戲抽象出幾個(gè)必要的對象,F(xiàn)ood Snake Game對象鳞疲,其中Game對象并不是游戲中的必備元素罪郊,而是游戲的邏輯,都可以抽象出對象尚洽。
3.Food 對象:構(gòu)造函數(shù)生成對象悔橄,設(shè)置寬高、left翎朱、top的基本屬性橄维;在其原型對象上添加渲染render方法,使其能夠隨機(jī)出現(xiàn)在地圖中拴曲,需要使用空數(shù)組存儲所有會出現(xiàn)的Food争舞,保障后期隨時(shí)生成和刪除;
同樣在其原型對象上添加刪除remove方法澈灼。
function Food(){
// 自身高度竞川,寬度店溢,默認(rèn)的位置,顏色
this.width=20;
this.height=20;
this.x=0;
this.y=0;
this.color="green";
// 創(chuàng)建一個(gè)空數(shù)組容納隨機(jī)生成的食物塊
this.elements=[];
}
4.Snake 對象:構(gòu)造函數(shù)生成對象委乌,注意設(shè)置的每一個(gè)蛇節(jié)的css屬性床牧,在其原型對象上添加渲染方法,注意是一節(jié)一節(jié)渲染遭贸,初始3節(jié)戈咳,循環(huán)渲染,渲染后需要刪除重新渲染壕吹;
Snake.prototype.render=function(map){
// 循環(huán)的方法進(jìn)行渲染
for (var i = 0,len = this.body.length ; i < len ; i++){
var ele=document.createElement("div");
// 給生成的每一個(gè)ele添加樣式;
ele.style.width = this.width+"px";
ele.style.height=this.height+"px";
ele.style.left=this.body[i].x*this.width+"px";
ele.style.top=this.body[i].y*this.height+"px";
ele.style.backgroundColor=this.body[i].color;
ele.style.position= "absolute";
map.appendChild(ele);
this.elements.push(ele);
}
};
在原型對象上添加位置食物方法 move著蛙,及初始方向向右移動,當(dāng)前一節(jié)的位置left top等于前一節(jié)的位置
for(var i=this.body.length-1;i>0;i--){
this.body[i].x=this.body[i-1].x;
this.body[i].y=this.body[i-1].y;
}
5.Game對象耳贬,最重要的一步踏堡,決定游戲是否成功運(yùn)行的關(guān)鍵,需要首先在其構(gòu)造函數(shù)中設(shè)置Food 和Snake屬性咒劲,生成相應(yīng)的對象實(shí)例顷蟆,后續(xù)直接調(diào)用。
var that;
function Game(map){
// 生成實(shí)例對象作為屬性
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
}
需要用到的方法:綁定按鍵的bindKey:給整個(gè)文檔doucument設(shè)置 onkeydown事件腐魂,利用事件委托函數(shù)控制蛇的移動方向
讓蛇運(yùn)動的方法:設(shè)置定時(shí)器帐偎,定時(shí)器函數(shù)參數(shù)包含 Food實(shí)例和Snake直接調(diào)用的render 和remove函數(shù),另外需要判斷蛇吃到食物的條件蛔屹,以及吃到食物后肮街,將蛇節(jié)最后一一項(xiàng)添加給蛇身自己。
// 吃掉食物增加一個(gè)蛇節(jié)
// 吃掉食物的條件:蛇頭的位置和食物的位置重合
for(var i=0;i<that.food.elements.length;i++){
if(hX===that.food.elements[i].offsetLeft&&hY===that.food.elements[i].offsetTop){
that.food.remove(that.map,i);
that.food.render(that.map);
var last=that.snake.body[that.snake.body.length-1];
that.snake.body.push({
x:last.x,
y:last.y,
color:last.color
});
}
}
四判导、繼承
1.對象之間的繼承,父級對象繼承到子級的對象沛硅,如 老李和小李兩個(gè)對象
var laoli = {
name: "laoli",
money: 1000000,
house: ["商鋪", "住宅"],
tech: function () {
console.log("廚藝")
}};
var xiaoli={
name: "xiaoli"
對象之間進(jìn)行繼承眼刃,使用 for……in
for (var k in laoli) {
子級有的屬性不需要繼承
if (xiaoli[k]) {
continue;
}
xiaoli[k] = laoli[k];
}}
封裝一個(gè)對象之間繼承的函數(shù)
function extend(parent, child) {
for (var k in parent) {
// 子級有的屬性不需要繼承
if (child[k]) {
continue;
}
child[k] = parent[k];
}
}
// 調(diào)用函數(shù)實(shí)現(xiàn)繼承
extend(laoli,xiaoli);
console.log(xiaoli);
2.原型繼承
提取兩個(gè)對象所有公共的屬性,然后放到一個(gè)父類型中
比如學(xué)生 和老師摇肌,公共的屬性有 name age sex 擂红,用構(gòu)造函數(shù)創(chuàng)建一個(gè)人類
Person對象,書寫兩者公共的3條屬性围小。
// 人類類型
function Person(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 學(xué)生類型
function Student(score) {
this.score = score;
}
// 老師類型
function Teacher(salary) {
this.salary = salary;
}
// 原型對象昵骤,可以將自己的屬性和方法繼承給將來的實(shí)例對象使用
Student.prototype = new Person("zs",18,"男");
Student.prototype.constructor = Student;
// 生成一個(gè)實(shí)例
var s1 = new Student(89);
var s2 = new Student(100);
console.dir(s1);
console.dir(s2);
console.log(s1.name);
console.log(s1.constructor);
- call方法
// call
// 函數(shù)本身就是一種對象,就能夠有自己的屬性和方法
// call 方法本身是一種執(zhí)行函數(shù)的方法
function fn(a,b) {
console.log(this);
console.log(a + b);
}
// 自定義一個(gè)簡單對象 o
var o = {
name: "zs"
}
// 普通函數(shù)調(diào)用
// fn(2,3);
// call 方法在調(diào)用函數(shù)的時(shí)候肯适,有兩個(gè)功能
// 1.更改函數(shù)內(nèi)部的 this 指向变秦,原先默認(rèn)是 window
// 2.調(diào)用函數(shù)執(zhí)行內(nèi)部代碼
// 參數(shù): 第一個(gè)參數(shù)用來指定 this,第二個(gè)及以后框舔,就是傳的實(shí)參
fn.call(o,3,4);
4.屬性的繼承
// 構(gòu)造函數(shù)的屬性的繼承
// 人類類型
function Person(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 學(xué)生類型
function Student(name,age,sex,score) {
// 直接對父類型的構(gòu)造函數(shù)進(jìn)行一個(gè)普通調(diào)用
// Person 普通調(diào)用過程中蹦玫,內(nèi)部的 this 指向的是 window
// 可以通過 call 方法更改Person 內(nèi)部的 this赎婚,現(xiàn)在的this就指向了Student
Person.call(this,name,age,sex);
this.score = score;
}
// 老師類型
function Teacher(name,age,sex,salary) {
Person.call(this,name,age,sex);
this.salary = salary;
}
// 創(chuàng)建學(xué)生的實(shí)例對象
var s1 = new Student("zs",18,"男",89);
var s2 = new Student("ls",19,"男",92);
console.dir(s1);
console.dir(s2);
-
方法 的繼承
// 父類型的原型對象中有方法也需要繼承 Person.prototype.sayHi = function () { console.log("你好"); }; // 學(xué)生類型 function Student(name,age,sex,score) { Person.call(this,name,age,sex); this.score = score; } // 子類型的原型對象上,需要繼承父類型原型對象的方法 // 方法1:對象拷貝繼承 // for (var k in Person.prototype) { // // 保留自己的 constructor 不要進(jìn)行繼承 // if (k === "constructor") { // continue; // } // Student.prototype[k] = Person.prototype[k]; // } // 方法2:原型繼承 Student.prototype = new Person(); Student.prototype.constructor = Student; // 老師類型 function Teacher(name,age,sex,salary) { Person.call(this,name,age,sex); this.salary = salary; } // 創(chuàng)建學(xué)生的實(shí)例對象 var s1 = new Student("zs",18,"男",89); var s2 = new Student("ls",19,"男",92); console.dir(s1); console.dir(s2); s1.sayHi();
6.組合繼承樱溉,屬性在構(gòu)造函數(shù)中繼承挣输,方法通過原型繼承,參照4 5的結(jié)合
// 組合繼承:屬性在構(gòu)造函數(shù)內(nèi)部繼承福贞,方法通過原型繼承
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("你好");
}
// 生成一個(gè)子類型
function Teacher(name,age,salary) {
// 繼承父類的屬性
Person.call(this,name,age);
this.salary = salary;
}
// 方法繼承撩嚼,通過原型對象繼承
Teacher.prototype = new Person();
Teacher.prototype.constructor = Teacher;
// 生成老師的一個(gè)實(shí)例
var t1 = new Teacher("wang",45,10000);
console.dir(t1);
console.log(t1.name);
t1.sayHi();
繼承的原理,方法為什么可以被繼承:
7.函數(shù)定義的方式
函數(shù)表達(dá)式可以沒有名字完丽,如匿名函數(shù),函數(shù)定義和聲明的區(qū)別:
fun(); 函數(shù)調(diào)用
// 函數(shù)聲明
// 必須定義函數(shù)名
function fun() {
/ console.log(1);
}
// 函數(shù)表達(dá)式
// 是將函數(shù)賦值給一個(gè)變量肠套,可以是一個(gè)匿名函數(shù)
var fn = function () {
console.log(2);
};
fn();
8.函數(shù)定義的new方式
函數(shù)本身也是一種對象舰涌,通過new Function 的方式來定義的,如:
var fun = new Function('a','b','var a = "1";console.log(a+b)');
fun(2,3);
console.dir(fun);
傳的參數(shù)都 是字符串 你稚,要用單引號或者雙引號瓷耙,一般不推薦,還是用傳統(tǒng)的函數(shù)聲明調(diào)用方式
函數(shù)本身也是一種對象刁赖,因此可以調(diào)用屬性和方法
9.函數(shù)的調(diào)用和this
普通函數(shù)內(nèi)的this默認(rèn)指向window搁痛;構(gòu)造函數(shù)中this指向的是將來創(chuàng)建的實(shí)例對象;
對象中的方法宇弛,里面的對象指的是調(diào)用的對象自己鸡典;事件函數(shù)的內(nèi)部 this 指向的是事件源,
如 btn 枪芒,document彻况;定時(shí)器和延時(shí)器中的函數(shù),默認(rèn)內(nèi)部的 this 指向的是 windowthis真正指向的是誰舅踪,要看其調(diào)用形式和執(zhí)行環(huán)境
10.函數(shù)的 call apply bind 方法纽甘,都可以打點(diǎn)調(diào)用,如 fun.call( 參數(shù)) fun是函數(shù)名抽碌,括號
function fun(a,b,c,d) {
console.log(this);
console.log(a + b + c + d);
}
// call方法:1.功能:第一個(gè)可以指定函數(shù)的 this悍赢,第二個(gè)可以執(zhí)行函數(shù)并傳參
// 2.參數(shù):第一個(gè)參數(shù),傳入一個(gè)指定讓 this 指向的對象货徙,第二個(gè)參數(shù)及以后左权,是函數(shù)參數(shù)的列表
// 3.返回值:就是函數(shù)自己的返回值
// 4.測試
var o = {
name: "zs"
}
// fun.call(o,1,2);
// apply 方法
// 1.功能:第一個(gè)可以指定函數(shù)的 this,第二個(gè)可以執(zhí)行函數(shù)并傳參
// 2.參數(shù):第一個(gè)參數(shù)痴颊,傳入一個(gè)指定讓 this 指向的對象赏迟,第二個(gè)參數(shù)是函數(shù)的參數(shù)組成的數(shù)組
// 3.返回值:就是函數(shù)自己的返回值
// 4.測試
// fun.apply(o,[4,5]);
// bind 方法
// 1.功能:第一個(gè)可以指定函數(shù)的 this,bind 方法不能執(zhí)行函數(shù)祷舀,但是可以傳參
// 2.參數(shù):第一個(gè)參數(shù)瀑梗,傳入一個(gè)指定讓 this 指向的對象烹笔,第二個(gè)參數(shù)及以后,是函數(shù)參數(shù)的列表
// 3.返回值:返回一個(gè)新的指定了 this 的函數(shù)抛丽,也可以叫綁定函數(shù)
// 4.測試
var fn = fun.bind(o,2,3);
console.log(fn);
fn(6,7); 輸出為2+3+6+7=18谤职,前提是原函數(shù)fun傳入4個(gè)參數(shù)才可以
- call方法的運(yùn)用
如何讓一個(gè)字面量書寫的對象,像數(shù)組一樣亿鲜,直接調(diào)用 arr.push() 方法添加新的元素呢允蜈?
// {} 的對象自己是沒有 push 方法的
// 類數(shù)組對象 getElementsByTagName
var o = {
0: 10,
1: 20,
2: 30,
length: 3
};
// console.log(o[0])
// 增加一項(xiàng)新的數(shù)據(jù),原先老實(shí)方法
// o["3"] = 40;
// o.length = 4;
// 利用數(shù)組中的 push 方法蒿柳,指定內(nèi)部的this 為對象 o饶套,就可以處理類數(shù)組對象的數(shù)據(jù)
Array.prototype.push.call(o,50);
console.log(o);
// 輸出為:50添加到了o 對象的第四項(xiàng)上了
- apply方法的運(yùn)用
內(nèi)置在js中的方法比如Math的一些方法,如何將數(shù)組作為參數(shù)呢垒探?
// 定義一個(gè)數(shù)組妓蛮,利用 apply 方法,可以將它拆開進(jìn)行操作
var arr = [1,3,4,6,8];
// 想借用一些現(xiàn)在內(nèi)置在js 中的方法
// console.log(Math.max(1,3,5,7,9));
// 利用 apply 方法圾叼,將數(shù)組傳給 max 的第二個(gè)參數(shù)
// console.log(Math.max.apply(Math,arr));
console.log(1,2,3);
console.log.apply(console,arr); ---輸出為 1 3 4 6 8分開的數(shù)字而非數(shù)組
- bind方法的運(yùn)用
// 想修改的是定時(shí)器的函數(shù)內(nèi)部的 this
var o = {
name: "zs",
age: 18,
s: function () {
setInterval(function () {
console.log(this.age);
}.bind(this),1000);
}
}
// o.s();
// 更改 事件函數(shù)中的 this
document.onclick = function () {
console.log(this);
}.bind(o); 輸出的是o這個(gè)對象蛤克,不執(zhí)行定時(shí)器這個(gè)函數(shù)
-
函數(shù)的其他成員
console.dir一個(gè)函數(shù),可以得到函數(shù)內(nèi)部的成員
arguments:傳入的是函數(shù)在調(diào)用 時(shí)夷蚊,傳入的所有實(shí)參組成的類數(shù)組對象构挤,有一個(gè)callee屬性,類似constructor惕鼓,
caller 函數(shù)的調(diào)用者筋现,函數(shù)在哪個(gè)作用域調(diào)用,caller就是誰箱歧,如果是在全局調(diào)用矾飞,caller就是null
如果是在內(nèi)部執(zhí)行的話,如:
function test() { fn(1,2,3,4); } test();
此時(shí)caller就是調(diào)用的函數(shù)名稱 test
length:形參的個(gè)數(shù)
name:函數(shù)的名字
使用arguments對象呀邢,找到最大的一個(gè)實(shí)參凰慈,如:
function max() { // 判斷實(shí)參中最大的數(shù) var nowMax = arguments[0]; for (var i = 1 ; i < arguments.length;i++) { if (arguments[i] > nowMax) { nowMax = arguments[i]; } } return nowMax; } console.log(max(1,4,7,9));
-
高階函數(shù):函數(shù)可以做參數(shù)的函數(shù);函數(shù)可以作為返回值的函數(shù)
1.函數(shù)作為另一個(gè)函數(shù)的參數(shù)時(shí):
// 定義一個(gè)函數(shù)驼鹅,吃飯的函數(shù),吃完飯之后森篷,可以做其他的事情输钩,看電影、聊天仲智、看書 function eat(fn) { console.log("吃晚飯"); // // 接下來的要做的事情是不固定的 fn(); } eat(function () { console.log("看電影"); }); 輸出結(jié)果是 吃晚飯 看電影
2.函數(shù)作為另一個(gè)函數(shù)的返回值
需求:通過同一段代碼實(shí)現(xiàn)以下效果 // 輸出 100 + m // 輸出 1000 + m // 輸出 10000 + m function outer(n) { return function inner(m) { console.log(m + n); } } // 在外部執(zhí)行 inner 函數(shù) // 100 + m var fun = outer(100); fun(3); 輸出為103. fun(13); 輸出為113 fun(23); 輸出為123 var fun1 = outer(1000); fun1(3); 輸出為1000+3=1003
-
函數(shù)閉包:天生存在的买乃,函數(shù)記住自己的作用域和函數(shù)自己,函數(shù)自己也
就是一個(gè)閉包钓辆,不論函數(shù)以何種方式進(jìn)行調(diào)用剪验,都會回到自己定義時(shí)的密閉
環(huán)境進(jìn)行執(zhí)行:即如果函數(shù)調(diào)用時(shí)跑到外部進(jìn)行調(diào)用肴焊,也會執(zhí)行原先在內(nèi)部生
成的語句
體會一下閉包,把內(nèi)部函數(shù)拿到外部父函數(shù)外面功戚,看能不能調(diào)用父函數(shù)內(nèi)部的變量:
```
// 將一個(gè)內(nèi)部函數(shù)拿到父函數(shù)的外面娶眷,觀察是否還能調(diào)用父函數(shù)內(nèi)部的變量
function outer() {
var a = 10;
function inner() {
console.log(a);
}
// 將inner 函數(shù)作為返回值
return inner;
}
outer()
// 在outer函數(shù)的外面,是不能直接訪問 a 變量啸臀,如下面兩條語句就無法執(zhí)行
// outer();
// console.log(a);
// 將 outer 執(zhí)行的結(jié)果届宠,賦值給一個(gè)變量
var inn = outer();
console.log(inn);
// 在全局調(diào)用 inn,按道理應(yīng)該查找全局的 a變量
inn();
// 輸出的真正結(jié)果是 10乘粒,來自于 outer 函數(shù)內(nèi)部的變量
```
-
閉包功能:1.可以在函數(shù)外部讀取函數(shù)內(nèi)部成員
? 2.讓函數(shù)在外部延長函數(shù)內(nèi)部變量的存活時(shí)間豌注,不會被馬上消除,如:
// 將一個(gè)內(nèi)部函數(shù)拿到父函數(shù)的外面灯萍,觀察是否還能調(diào)用父函數(shù)內(nèi)部的變量 function outer() { // 形成閉包環(huán)境中的變量不是一成不變的轧铁,可以被更改 var a = 10; function inner() { console.log(a++); } // 將inner 函數(shù)作為返回值 return inner; } var inn = outer(); inn(); 輸出結(jié)果為10 inn(); 變量a未消失,且可以被改變旦棉,此時(shí)的a變成了11齿风,所以輸出為11
本身變量a在執(zhí)行一次就在內(nèi)存中被銷毀了,因?yàn)殚]包他爸,所有這個(gè)變量可以被調(diào)用兩次
閉包帶來的問題:使用自調(diào)用函數(shù)解決
五聂宾、正則表達(dá)式
1.在線正則表達(dá)式訓(xùn)練網(wǎng)站
c.runoob.com/front-end/845
2.創(chuàng)建正則的方法
正則表達(dá)式也是對象,是一種索引類型 诊笤,創(chuàng)建方法2種:推薦使用字面量方式
// 創(chuàng)建正則的第一種方法系谐,正則的字面量 /
var reg = /abc/;
// 第二種,通過 構(gòu)造函數(shù) 創(chuàng)建
var reg1 = new RegExp("cde");
3.相關(guān)正則方法
字符串方法與其對應(yīng)的正則表達(dá)式:
4.正則表達(dá)式的組成
六讨跟、 ES6 新特性 習(xí)慣將ES2015稱為ES6
1.解決了原有語法的一些問題或者缺陷纪他;對原有語法進(jìn)行增強(qiáng);
全新的對象晾匠,全新的方法茶袒,全新的功能;全新的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)
2.最新版本的瀏覽器凉馆,谷歌最新版薪寓,可以直接在瀏覽器中執(zhí)行;可以在VS中安裝相關(guān)插件
3.let和塊級作用域
通過現(xiàn)代關(guān)鍵字let定義塊內(nèi)部的變量 其定義的變量在塊級作用域內(nèi)部可以被訪問
非常適合設(shè)置 在for 循環(huán)中的循環(huán)變量:如:
// 非常適合設(shè)置 在 for 循環(huán)中的循環(huán)變量
for (var i = 0 ; i < 3 ; i++) {
for (var i = 0; i < 3;i++) {
console.log(i);
}
} 輸出一次 0 1 2
因?yàn)閒or 里面的變量都是全局變量澜共,變量間會發(fā)生覆蓋向叉,最終值執(zhí)行了一次外層循環(huán),三次內(nèi)層循環(huán)
沒有輸出9個(gè)嗦董,輸出 0 1 2
let設(shè)置:
// 通過 let 定義變量母谎,只在自己的循環(huán)中生效
for (let i = 0 ; i < 3 ; i++) {
for (let i = 0; i < 3;i++) {
console.log(i);
}
}
此時(shí)就會輸出3次 0 1 2
通過循環(huán)批量添加事件,之前的用法:
// 通過 let 定義變量京革,只能在塊級內(nèi)部被調(diào)用
var eles = [{}, {}, {}];
for (var i = 0 ; i < eles.length ; i++) {
eles[i].onclick = function () {
console.log(i);
}
}
eles[0].onclick();
最終結(jié)果奇唤,不管傳入的實(shí)參是0 還是 1 2幸斥,結(jié)果都是3 ,因?yàn)閒or循環(huán)內(nèi)部var 定義的是全局變量咬扇,循環(huán)開始后 全局變量 i先后為 0 1 2甲葬,最終 i的值會由最新的 2替換,再i++為3冗栗,最終輸出一個(gè) 3
解決方法:將var 替換成let, 或者用一個(gè)自調(diào)用函數(shù)封閉i的作用域
循環(huán):實(shí)際有兩層作用域
for (var i = 0 ; i < 10 ; i++) {
var i = "foo";
console.log(i); 只輸出了一次foo
for (var i = 0 ; i < 10 ; i++) {
let i = "foo";
console.log(i); 輸出了10次foo 演顾,for循環(huán)括號里的var也可以換成let
?
4.const
const name=“zs”;
name=“l(fā)s”隅居;
? 此時(shí)name不會被更改為ls钠至。const聲明的時(shí)候必須同時(shí)賦予一個(gè)初始值
const obj={};
obj.name="zs";
給這個(gè)空對象添加屬性和屬性值是可以的,這個(gè)obj指向的對象是沒有改變的
補(bǔ)充:主要用const胎源,配合let棉钧,不用var
5.數(shù)組的解構(gòu)
// 數(shù)組解構(gòu)
const arr = [100, 200, 300]
const foo = arr[0]
const bar = arr[1]
const baz = arr[2]
console.log(foo, bar, baz)
新的方法:`
const arr = [100, 200, 300]`
const [foo, bar, baz] = arr`
console.log(foo, bar, baz)` 輸出為100 200 300,對應(yīng)賦值
如果只想要獲取第三個(gè)成員涕蚤,可以寫成 const [, , baz] = arr
宪卿;
獲取成員后的剩余成員:
const arr = [100, 200, 300]
const [foo, ...rest] = arr
console.log(rest)
數(shù)組的靈活運(yùn)用:
const arr = [100, 200, 300]
const [foo, bar, baz = 400, more = 123] = arr
console.log(more) 輸出為123
console.log(baz) 輸出為400而不是300
將字符串分割為數(shù)組,用數(shù)組的解構(gòu)万栅,如:
const path = "foo/bar/baz"
// const temp = path.split("/") 之前的方法佑钾,獲取下標(biāo)為1的項(xiàng) bar
// const a = temp[1]
const [,a,] = path.split("/")
console.log(a)
6.對象的解構(gòu),同數(shù)組的解構(gòu)很像:
// 對象解構(gòu)
const obj = { name: 'zs', age: 18 }
const { name } = obj
console.log(name) 獲取name 的屬性和值
const obj = { name: 'zs', age: 18 }
const name = "tom"
const { name: newName } = obj
console.log(name) 輸出tom
console.log(newName) 輸出為zs
7.模板字符串,加反引號`
添加反引號可以給字符串換行烦粒,
${ }插值表達(dá)式 可以將里面的內(nèi)容插入到字符串中休溶,如:
const name = "tom"
const str = `hey, ${name},${1 + 1},${Math.random()}`
console.log(str) 輸出為hey,tom扰她,2兽掰,一個(gè)隨機(jī)數(shù)
8.模板字符串標(biāo)簽函數(shù)
const name = "zs"
const gender = true
function myTagFunc(strings, name, gender) {
// console.log(strings,name,gender)
// 處理一下 性別
const sex = gender ? "man" : "woman"
return strings[0] + name + strings[1] + sex + strings[2]
}
const str = myTagFunc`hi, ${name} is a ${gender}`
console.log(str)
9.字符串?dāng)U展方法
const msg = 'Error: foo is not defined.'
console.log(msg.startsWith('Error')) 判斷是否以xx開頭
console.log(msg.endsWith('.')) 判斷是否以xx結(jié)尾
console.log(msg.includes('foo')) 判斷是否包含xx
10.參數(shù)默認(rèn)值
形參設(shè)置默認(rèn)值,實(shí)參沒有設(shè)置徒役,傳入的就是默認(rèn)值
function foo(enable = true孽尽,bar) { 參數(shù)默認(rèn)值在前
// enable = enable || true
// enable = enable === undefined ? true : enable
console.log('foo invoked enable:')
console.log(enable)
}
foo('bar') 輸出為foo invoked enable: bar,因?yàn)榇藭r(shí)默認(rèn)值被實(shí)參‘bar’替代了
function foo(bar,enable = true) { 一般都是參數(shù)默認(rèn)值在后
// enable = enable || true
// enable = enable === undefined ? true : enable
console.log('foo invoked enable:')
console.log(enable)
}
foo('bar') 輸出為 foo invoked enable: true
9.剩余操作符
function fun(...args) {
console.log(args)
}
fun(1,2,3,4) 輸出為所有實(shí)參的數(shù)組 [1,2,3,4]
function fun(n忧勿,...args) {
console.log(args)
}
fun(1,2,3,4) 輸出為除第一個(gè)實(shí)參1的剩下實(shí)參的數(shù)組 [2,3,4]
11.展開操作符
// 展開數(shù)組操作
const arr = ['foo', 'bar', 'baz']
// console.log(arr[0],arr[1],arr[2]) 傳統(tǒng)的死辦法
// console.log.apply(console,arr) 利用apply 的方法杉女,console對象的this指向的就是console自己
console.log(...arr) es2015的方法,輸出為[foo鸳吸,bar宠纯,baz]
12.箭頭函數(shù) =>
將下面這個(gè)函數(shù)用箭頭函數(shù)改寫:
function plus(a) {
return a + 1
}
console.log(plus(10))
改寫為:
const plus = (a, b) => { 只要一個(gè)參數(shù)可以不用加(),如果箭頭后只有
console.log('plus invoked') 一條語句层释,那這條語句就是返回值
return a + b
}
console.log(plus(1,2)) 輸出為3
const arr = [1,2,3,4,5,6,7]
// const arr1 = arr.filter(function (item) { 篩選數(shù)組中的奇數(shù),filter篩選函數(shù)
// return item % 2 只有奇數(shù)才會返回1快集,也就是true
// })
const arr1 = arr.filter(i => i % 2) 用箭頭函數(shù)簡化上面的篩選函數(shù)
console.log(arr1)
12.箭頭函數(shù)的this 內(nèi)部沒有this 的機(jī)制贡羔,從外部進(jìn)行查找
// 箭頭函數(shù)與 this
const person = {
name: "tom",
// sayHi: function () {
// console.log(`hi,my name is ${this.name}`) 這里的this指向的是person對象自己
// }
// sayHi: () => {
// console.log(`hi,my name is ${this.name}`) 箭頭函數(shù)這里的this找不到指向的內(nèi)容
// }
sayHi: function () {
? setTimeout(() => { 箭頭函數(shù)省去了函數(shù)名
? console.log(`hi,my name is ${this.name}`) 箭頭函數(shù)本身沒有this廉白,從外部找到了this,指向的是person乖寒,如果沒有用箭頭函數(shù)猴蹂,則無法正確執(zhí)行
? },1000);
}
}
person.sayHi() 可以正確執(zhí)行
13.對象字面量的增強(qiáng)
// 對象字面量增強(qiáng)
const bar = "bar"
const age = "age"
const obj = {
name: "tom",
// bar: bar
bar, 屬性名和屬性值一樣可以省去屬性值
sayHi () { 方法可以不用寫函數(shù)名
? console.log('hi')
? console.log(this) this指向的是對象obj
},
// 計(jì)算屬性名
[1+2]: 18 添加表達(dá)式作為屬性名,[]里面可以是表達(dá)式也可以是變量
}
// obj[age] = 18 以前的方法楣嘁。obj添加[]進(jìn)行更改磅轻。[]內(nèi)部是動態(tài)的屬性名,樂意是表達(dá)式
console.log(obj)
// obj.sayHi()
14.對象擴(kuò)展的方法 Object.assign方法
const source1 = {
a: 123,
b: 123
}
const source2 = {
b: 678,
d: 789
}
const target = {
a:456,
c:789
}
const result = Object.assign(target,source1,source2) 將后面兩個(gè)對象的屬性合并到target中去逐虚,同樣的屬性會采用后面對象的屬性值進(jìn)行覆蓋
console.log(target)
console.log(target === result) 最終的新對象還是target對象
// 應(yīng)用聋溜,在 options 對象參數(shù)接收時(shí),簡化
function Block(options) {
// this.width = options.width; 以前的方法叭爱,通過傳入的實(shí)參添加Blcck的屬性
Object.assign(this,options)
}
const block1 = new Block({width: 100, height: 100, x: 50, y: 50})
console.log(block1)
15.Object.is方法 :判斷兩個(gè)是否是同一類型的數(shù)據(jù)
Object.is(NaN,NaN)
值為false
16.class
function Person(name, age) { 之前構(gòu)造函數(shù)的方法
// this.name = name;
// this.age = age;
// }
// Person.prototype.sayHi = function () {
// console.log(`hi,my name is ${this.name}`)
// }
class Person { class的方法撮躁,也更加整潔
constructor (name, age) { 參數(shù)在constractor后書寫
this.name = name;
this.age = age;
}
sayHi () {
console.log(`hi,my name is ${this.name}`)
}
}
const p1 = new Person("tom",18) 同樣的生成p
console.log(p1)
p1.sayHi() 實(shí)例對象調(diào)用方法
17.靜態(tài)方法 static
使用static修飾的屬性和方法,可以直接由對象進(jìn)行調(diào)用买雾,生成的對象實(shí)例反而不能調(diào)用成功
class Person {
constructor (name, age) {
? this.name = name;
? this.age = age;
}
sayHi () {
? console.log(`hi,my name is ${this.name}`)
}
static create (name,age) {
? console.log(this) this指向的是不是實(shí)例對象把曼,而是Person
? return new Person(name,age)
}
}
const p1 = Person.create("zs",19) 調(diào)用時(shí)打點(diǎn)是crrate 不是static
console.log(p1)
- 類的繼承 使用extends
// 靜態(tài)方法
class Person {
constructor (name, age) {
? this.name = name;
? this.age = age;
}
sayHi () {
? console.log(`hi,my name is ${this.name}`)
}
}
class Student extends Person {
constructor (name,age,number) {
? super(name,age) super對象指向的是父類
? this.number = number;
}
hello () { 給Student添加自己的一個(gè)方法
super.sayHi() 使用的是父類的方法,用super打點(diǎn)調(diào)用父類的方法
console.log(`學(xué)號是 ${this.number}`) 自己的方法的表達(dá)式
}
}
const s1 = new Student("tom",18,102)
s1.hello();
-
set 的全新結(jié)構(gòu)漓穿,Set是一個(gè)對象
const s = new Set() 生成 s 這一個(gè)實(shí)例對象 s.add(1).add(2).add(3).add(4).add(2) 重復(fù)的內(nèi)容會被忽略 console.log(s)
s.forEach(i => console.log(i))
ES5中的遍歷方法 for each`for (let i of s) {` ES2015的遍歷方法 for of `console.log(i)` `}`
console.log(s.size)
可以得到集合的長度判斷集合中是否存在某個(gè)值
console.log(s.has(4))
console.log(s.delete(100)) 判斷是否刪除成功 console.log(s) 輸出為true或者flase
s.clear()
刪除集合中所有數(shù)據(jù)set一般用作數(shù)組去重:
// 數(shù)組去重 const arr = [1.3,4,6,2,4,7,5,8] // const b = Array.from(new Set(arr)) 方法一:把集合轉(zhuǎn)換為數(shù)組 Array.from方法 const b = [...new Set(arr)] 方法2: ...rest方法 console.log(b)21
-
Map數(shù)據(jù)結(jié)構(gòu) const obj = {} obj[true] = "boolean" obj[123] = "number" obj[{a: 1}] = "object" 對象型的數(shù)據(jù)嗤军,此時(shí)無法轉(zhuǎn)換成字符串的鍵值對集合 console.log(Object.keys(obj)) key可以讓對象中的屬性和屬性值轉(zhuǎn)換字符串的鍵值對集合 console.log(obj[{}]) console.log(obj['[object Object]'])
使用Map讓對象類型也可以轉(zhuǎn)換為字符串的鍵值對集合:
const map = new Map() const a = { a: 1} map.set(a,100) map 的set方法,a參數(shù)指代對象類型的屬性晃危,100是對象類型的屬性的屬性值 console.log(map) console.log(map.get(a))
map 也有 has delete clear方法
-
symbol 本身表示獨(dú)一無二的值叙赚,直接以函數(shù)方式執(zhí)行 Symbol()
`const s = Symbol()` `console.log(s)` `console.log(typeof s)` 輸出為symbol
Symbol() 函數(shù)內(nèi)部可以傳入?yún)?shù),參數(shù)就是對這個(gè)數(shù)據(jù)的描述山害,用作區(qū)分
如:Symbol(” ddd“ )
Symbol()`可以作為對象的屬性纠俭,
const obj = { [Symbol()] : 789, name: "zs" } obj[Symbol()] = 123 obj[Symbol()] = 456 console.log(obj[Symbol()])無法在外部進(jìn)行訪問
symbol最主要的作用就是為對象添加獨(dú)一無二的屬性
-
for of遍歷
之前的變量 for each for in
const arr = [100, 200, 300, 400] for (const item of arr) { console.log(item) } arr.forEach(item => { 沒有辦法打斷遍歷 console.log(item) }) for (const item of arr) { console.log(item) if (item >= 200) { break; } }輸出為100 200 const s = new Set(["foo", "bar", "baz"]) for (const item of s) { console.log(item) } const m = new Map() m.set("foo",1) m.set("bar",2) for (const [key,value] of m) { console.log(key,value) 輸出為foo和1;bar和2的兩個(gè)鍵值對 } const obj = { name: "zs", age: 18 } for (const item of obj) { 不用于對象的遍歷 console.log(item) }
-
ES 2016新增內(nèi)容
```
// ES2016 新增內(nèi)容
const arr = [1,true,NaN,23,'hello']
// console.log(arr.indexOf(true))存在會返回1
// console.log(arr.indexOf(null))不存在會返回-1
// console.log(arr.indexOf(NaN))無法查找NaN是否存在
// includes 包含
// console.log(arr.includes(NaN))包含返回true
// 指數(shù)運(yùn)算符 **
// console.log(Math.pow(2,3))自帶的方法浪慌,下面ES2016的方法更便捷
console.log(2 ** 10)
```