十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
一、代碼模塊
成都創(chuàng)新互聯(lián)專注于曲沃企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站開發(fā),購物商城網(wǎng)站建設(shè)。曲沃網(wǎng)站建設(shè)公司,為曲沃等地區(qū)提供建站服務(wù)。全流程專業(yè)公司,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)1.js里面代碼可以放在不同的文件里, 稱為模塊
2.一個(gè)模塊需要引用其他模塊代碼的時(shí)候,使用require()
3.require:
(1)如果是第一次調(diào)用,那么就加載,執(zhí)行腳本
(2)每個(gè)代碼模塊由module.exports導(dǎo)出的對象
(3)每次require的時(shí)候,都返回module.exports(模塊出口)
他可以指向任何類型, 函數(shù),對象, 值.....
4.requirefunction Person(name,height){
this.name=name;
this.height=height;
this.hobby=function(){
return 'watching movies';
}
}
var boy=new Person('keith',180);
var girl=new Person('rascal',153);
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby);//false
, 如果是第一次執(zhí)行,他就把
js里所有代碼加載進(jìn)來, 在執(zhí)行這整個(gè)js文件, 然后返回module.exports.
require得到的就是module.exports指向的對象.
5.如果不是第一次require,他就直接返回module.exports.
二、this
顯示傳遞this call
1.每個(gè)函數(shù)都包含兩個(gè)非繼承而來的方法:call()方法和apply()方法。
(1)相同點(diǎn): 兩個(gè)方法的作用是一樣的
(2)不同點(diǎn): 接收參數(shù)的方式不同.
2.作用:
.在特定的作用于中調(diào)用函數(shù),等于設(shè)置函數(shù)體內(nèi)this對象的值,
擴(kuò)充函數(shù)賴以運(yùn)行的作用域
(1)call方法使用
function test_func(name,sex){ this.name = name; this.sex = sex; } var xiaoming = {}; test_func.call(xiaoming func,"xiaoming",10); console.log(xiaoming);
(2)apply使用 兩個(gè)參數(shù) 一個(gè)是函數(shù)的作用域(this),另一個(gè)是參數(shù)數(shù)組.
function test_func(name,sex){ this.name = name; this.sex = sex; } var xiaoming = {}; test_func.apply(xiaoming,["xiaoming",10]); console.log(xiaoming);
3.隱式傳遞this
這個(gè)this就是對象, 也就是對象直接調(diào)用,this被隱式傳到函數(shù)里,
var xiaohong = { name: "xiaohong", test_func: function(){ console.log(this); }, } xiaohong.test_func();
4.強(qiáng)制傳遞綁定this
強(qiáng)制設(shè)置函數(shù)體this的值, 參數(shù)是一個(gè)表.
但是對象卻不會(huì)引用這個(gè)函數(shù)>
var func = function(){ console.log(this); }.bind(xiaohong); func();
5.定義完函數(shù)體,在綁定對象。
在定義完函數(shù)體后, 這個(gè)函數(shù)對象的this一定不是綁定的;
因?yàn)?函數(shù)對象來綁定對象的時(shí)候,不是把對象綁定到func函數(shù)對象里,
而是產(chǎn)生了一個(gè)新的函數(shù)對象,然后返回這個(gè)函數(shù)對象.
(1)錯(cuò)誤,沒有獲得綁定好的函數(shù)對象
func = function(){ console.log(this); } func.bind(xiaohong);
(2)正確,先獲得綁定好的函數(shù)對象,再調(diào)用
func = function(){ console.log(this); } func = func.bind(xiaohong); func();
7.優(yōu)先級(jí)
(1)綁定的優(yōu)先級(jí) 大于 隱式傳遞
綁定一般用在回調(diào)函數(shù)。
var xiaohong = { name: "xiaohong", test_func: function(){ console.log(this); }.bind(5), } xiaohong.test_func(); //輸出的是5
(2)顯示傳遞 大于 隱式傳遞
強(qiáng)制 > 顯示 > 隱式
三、實(shí)現(xiàn)面向?qū)ο?/p>
.在javascript中不存在類的概念, 而是通過 構(gòu)造函數(shù)
和原型鏈(prototype chains)實(shí)現(xiàn)的
function person(name, sex){ this.name = name; this.sex = sex; } person.prototype.test_func = function(){ console.log("person test_func"); console.log(this); } var p = new person("xiaohong",10); console.log(p); var p2 = new person("xiaotian",12); console.log(p2); p.test_func(); p2.test_func();
構(gòu)造函數(shù)
(1)構(gòu)造函數(shù)提供一個(gè)生成對象的模板并描述對象的基本結(jié)構(gòu),
一個(gè)構(gòu)造函數(shù)可以生成多個(gè)對象,每個(gè)對象都有相同的結(jié)構(gòu),
構(gòu)造函數(shù)就是對象的模板, 對象就是構(gòu)造函數(shù)的實(shí)例,
構(gòu)造函數(shù)特點(diǎn):
a:內(nèi)部使用的this對象,指向要生成的對象實(shí)例,
b:使用new操作符來調(diào)用構(gòu)造函數(shù),并返回對象實(shí)例,
(2)構(gòu)造函數(shù)的缺點(diǎn): 同一個(gè)對象實(shí)例之間, 當(dāng)你new調(diào)用構(gòu)造函數(shù)
返回一個(gè)實(shí)例的時(shí)候,里面的所有函數(shù)都會(huì)新創(chuàng)建出來, 這個(gè)函數(shù)
都是一個(gè)新創(chuàng)建的函數(shù), 是不被實(shí)例共享的, 這樣很浪費(fèi)資源.
function Person(name,height){ this.name=name; this.height=height; this.hobby=function(){ return 'watching movies'; } } var boy=new Person('keith',180); var girl=new Person('rascal',153); console.log(boy.name); //'keith' console.log(girl.name); //'rascal' console.log(boy.hobby===girl.hobby);//false
prototype屬性
(1) 為了解決構(gòu)造函數(shù)的對象之間無法共享屬性的缺點(diǎn),js提供了prototype屬性.
(2)js中所有類型都是對象,(除了null和undefined),而每個(gè)對象都繼承自另一個(gè)
對象, 稱為"原型"對象 (prototype object) , null沒有原型對象,
(3)原型對象上的所有屬性和方法,都會(huì)被對象實(shí)例所享.
(4)通過構(gòu)造函數(shù)生成對象實(shí)例時(shí), 會(huì)將對象實(shí)例的原型指向構(gòu)造函數(shù)
的prototype屬性, 每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,
這個(gè)屬性就是對象實(shí)例的原型對象,
(5)對于構(gòu)造函數(shù)prototype是作為構(gòu)造函數(shù)的屬性,對于對象實(shí)例來說
prototype是對象實(shí)例的原型對象, 所以prorotype即是屬性,又是對象.
function Person(name,height){ this.name=name; this.height=height; } Person.prototype.hobby = function(){ return 'watching movies'; } var boy = new Person('keith',180); var girl = new Person('rascal',153); console.log(boy.name); //'keith' console.log(girl.name); //'rascal' console.log(boy.hobby===girl.hobby);//true
(6)原型對象的屬性不是對象實(shí)例的屬性,對象實(shí)例的屬性是繼承自
構(gòu)造函數(shù)定義的屬性,因?yàn)闃?gòu)造函數(shù)內(nèi)部有一個(gè)this關(guān)鍵字,來指向
要生成的對象實(shí)例,對象實(shí)例屬性, 其實(shí)就是構(gòu)造函數(shù)內(nèi)部定義的屬性.
所以只要你修改原型對象上的屬性和方法, 變動(dòng)會(huì)離開體現(xiàn)在所有對象實(shí)例上.
(7)當(dāng)某個(gè)對象實(shí)例沒有該屬性或方法時(shí), 就會(huì)到原型對象上去查找
如果實(shí)例對象自身有某個(gè)對象或方法, 就不會(huì)去原型對象上查找,
如下,當(dāng)boy對象實(shí)例hobby方法修改時(shí), 就不會(huì)在繼承原型對象
上的hobby方法了, 不會(huì)girl沒有修改, 所以它依舊繼承原型對象的方法.
function Person(name,height){ this.name=name; this.height=height; } Person.prototype.hobby = function(){ console.log("aaa"); } var boy = new Person('keith',180); var girl = new Person('rascal',153); boy.hobby = function(){ console.log("bbb"); } boy.hobby(); //bbb girl.hobby(); //aaa
(8).原型鏈
對象的屬性和方法,可能是定義在自身,也可能是原型對象,由于
原型對象本身對于對象實(shí)例來說也是對象,它也有自己的原型, 所以形成了
一條原型鏈(prototype chain),比如a對象是b對象的原型,b對象是c對象的原型
以此類推, 所有對象的原型頂端, 都是object.prototype,即object構(gòu)造
函數(shù)的prototype指向的哪個(gè)對象, 而object.prototype也有自己的原型對象,
這個(gè)對象就是 "null" 沒有任何屬性和方法, 而null對象則沒有原型.
特點(diǎn):
a.讀取對象某個(gè)屬性時(shí),javaScript先找對象本身的屬性,如果找不到,就去他的原型找,
如果還是找不到,則去原型的原型找,直到object.portotype找不到則返回 undefined.
b.如果對象自身和它的原型定義了同名屬性,優(yōu)先讀取對象自身屬性,稱為 "覆蓋"
c.一級(jí)級(jí)向上找屬性, 對性能有影響, 越上層,影響越大,
new 操作符
1.javascript也有new關(guān)鍵字, js中萬物皆對象, 為何還要new關(guān)鍵字.
其實(shí)js中new關(guān)鍵字不是用來創(chuàng)建一個(gè)類的實(shí)例對象,而是用于繼承,
function Animal(name){ this.name = name; } Animal.color = "black"; Animal.prototype.say = function(){ console.log("I'm " + this.name); }; var cat = new Animal("cat"); console.log( cat.name, //cat cat.height //undefined ); cat.say(); //I'm cat console.log( Animal.name, //Animal Animal.color //back ); Animal.say(); //not function
2.代碼解讀
1-3 行創(chuàng)建一個(gè)函數(shù)Animal,并在其this上定義了屬性:name,
4 行在Animal對象(Animal本身是函數(shù)對象)上定義了一個(gè)靜態(tài)屬性:color,并復(fù)制"black"
5-7行在Animal函數(shù)的屬性prototype上定義一個(gè)say方法,say輸出了this的name值
8行使用new關(guān)鍵字創(chuàng)建了一個(gè)新對象cat,
10-14行cat對象常識(shí)方位name和color屬性,并調(diào)用say方法
16-20行Animal對象訪問name和color屬性,并調(diào)用say方法
3.重點(diǎn)解析 new方法做了什么?
js引擎在執(zhí)行new 這行代碼的時(shí)候,做了很懂工作,偽代碼如下
var obj = {}; obj.__proto__ = Animal.prototype; var result = Animal.call(obj,"cat"); //顯示傳遞this,和參數(shù)到構(gòu)造函數(shù) return typeof result === 'obj'? result : obj ; //
a)__proto__(隱式原型)與prototype(顯式原型)
每個(gè)對象都有__proto__屬性, 但只有函數(shù)對象才有prototype屬性.
b ) 首先會(huì)創(chuàng)建一個(gè)空對象obj, 把obj的__proto__指向Animal的原型對象
prototype, 此時(shí)便簡歷了obj對象的原型鏈:
obj -> Animal.prototype -> object.prototype -> null
c)在obj對象執(zhí)行空間調(diào)用構(gòu)造函數(shù)并傳遞參數(shù)"cat"
這里這個(gè)obj就是構(gòu)造函數(shù)里的this對象,this指向的就是obj;
d ) 判斷返回值 如果無返回值或者返回非對象值, 則將obj作為新對象, 否則返回值
坐位新對象,
4.了解new運(yùn)行機(jī)制后,cat就是d過程的返回值 表, 他有一個(gè)原型鏈,
cat上新增了一個(gè)新的屬性: name
5.再次參照上面的代碼分析
(1)cat.naem 在過程c 中obj作為this,傳遞到構(gòu)造函數(shù),構(gòu)造產(chǎn)生name屬性,
因此cat.name就是obj.name
(2)cat.color cat首先在自身找color,沒有則言責(zé)原型鏈查找,我們僅在Animal
對象是哪個(gè)定義color,沒有再其原型鏈上定義, 因此找不到
(3)cat.say() 首先找自身,沒有,找原型鏈Animal的prototype屬性定義了say
因此可以再原型鏈?zhǔn)巧险业絪ay方法
(4)Animal.color 對于Animal來說它本身是一個(gè)對象,因此他在訪問屬性也遵守
上述查找規(guī)則, 所以他能找到
(5)Animal.name 先查找自身naem 但這個(gè)name不是我們定義的name,
而是這個(gè)函數(shù)對象內(nèi)部本身就存在這個(gè)屬性,一般情況下,函數(shù)對象在產(chǎn)生內(nèi)置name
屬性會(huì)將函數(shù)名作為賦值(僅函數(shù)對象).
(6)Animal.say() Animal在自身查找, 沒有,沿著原型鏈查找,
這是Animal函數(shù)對象的原型鏈
Animal的原型對象是Function.prototype
原型鏈: Animal -> Function.prototype -> Objecct.prototype -> null
在Animal原型鏈上并沒有找到,say方法, 因?yàn)锳nimal的prototype
只是Animal的一個(gè)屬性, 并不是它的原型對象,
Animal的原型對象是Function.prototype
(7)所有實(shí)例化的對象,他們的__protp__都指向構(gòu)造函數(shù)的prototype屬性
只要有一個(gè)實(shí)例對象修改其中的內(nèi)容, 其他的實(shí)例對象也會(huì)跟這改變.
(8)根據(jù)上面的知識(shí)實(shí)現(xiàn)面向?qū)ο?/p>
function Point(){ this.xpos = 0; this.ypos = 0; } Point.prototype.set_pos = function(x,y){ this.xpos = x; this.ypos = y; } Point.prototype.get_posy = function(){ return this.ypos; } var p1 = new Point(); var p2 = new Point(); p1.set_pos(10,20); p2.set_pos(100,200); console.log(p1.get_posy()); console.log(p2.get_posy());
類的繼承(原型實(shí)現(xiàn))
1.繼承就是父類有的方法或?qū)傩? 子類繼承后其方法和屬性子類也可以使用的.
2.繼承實(shí)現(xiàn)方法: A類有個(gè)prototype, 類B也有個(gè)prototype
把類A的prototype的內(nèi)容 復(fù)制(淺復(fù)制) 給類B的prototype,
這樣的話,類A和類B公用了這個(gè)prototype
3.首先定義一個(gè)人類
var Person = function(){}; Person.prototype.set_name = function(name){ this.naem = name; //設(shè)置姓名 }; Person.prototype.set_age = function(age){ this.age = age; //設(shè)置年齡 };
4.定義一個(gè)男人類, 繼承自人類, 有兩種做法
(1)男人類.prototype = Person.prototype;
但是這樣會(huì)造成一個(gè)問題:這樣賦值就是引用賦值 (淺賦值),
導(dǎo)致這兩個(gè)prototype指向的是同一個(gè)對象, 如果子類修改一個(gè)
方法屬性, 父類的也會(huì)跟著改變, 顯然是不行的.
(2)new出來的是新的實(shí)例,會(huì)把原來的prototype拷貝過來
這樣就可以擴(kuò)展自己的方法了, 實(shí)際上這個(gè)prototype的__ptoto還是
指向父類的prototype, 而prototype則共享__ptoto__里的屬性方法,
擴(kuò)展子類prototype的時(shí)候,不影響父類ptototype, 應(yīng)為是new出來的, 他的
__proto__才指向父類prototype, ptototype只是共享這個(gè)方法屬性.
//定義一男人類 var Man = function(){}; //做法(1) //做法(2) var Super = function(){}; Super.prototype = Person.prototype; Man.prototype = new Super(); //這里就是繼承 Man.prototype.set_sex = function(sex){ this.sex = sex; } console.log(Super.prototype); console.log(Man.prototype); console.log(Man.prototype.__proto__); var m = new Man(); //使用父類方法 m.set_name("小王"); m.set_age(10); //使用子類方法 m.set_sex(0); console.log(m);
(3) 只要你擴(kuò)展自己方法,和父類同名,就會(huì)隱藏父類方法,
因給根據(jù)原型鏈原則, 查找方法屬性 先到實(shí)例本身進(jìn)行查找 然后原型對象
這個(gè)原型其實(shí)就是他的父類.
Man.prototype.set_name = function(name){ console.log("子類重寫該方法"); }
(4) 如果要調(diào)用父類的函數(shù), 使用父類的ptototype 把子類實(shí)例傳給父類方法
Man.prototype.set_name = function(name){ person.prototype.set_name.call(name); console.log("子類重寫該方法"); }
(5)Class實(shí)現(xiàn) 可以繼承 也可以繼承
function Class(param){ var new_class = function(){}; //如果有要繼承的父類 if(param.extend != null){ var Super = function(){}; Super.prototype = param.extend.prototype; new_class.prototype = new Super(); } //遍歷參數(shù) 把內(nèi)容添加到新對象里 for(var key in param){ if(key == "extend"){ continue; } new_class.prototype[key] = param[key]; } return new_class; }
(6)使用Class函數(shù) 實(shí)現(xiàn)繼承和 擴(kuò)展方法屬性
//Student學(xué)生類 傳入?yún)?shù)表 var Student = Class({ //繼承自 Person extend: Person, //定義方法 set_class: function(classa){ console.log("set_class",classa); }, //定義屬性 name: "學(xué)生類", }); //實(shí)例化對象 var s = new Student(); s.set_class(12312); console.log(s.name);
閉包
1. 看一段閉包代碼
function a(){ var n = 0; function inc(){ n++; console.log(n); } inc(n); inc(n); } a(); //輸出1 輸出2
2.再 看一段閉包代碼
function a(){ var n = 0; this.inc = function(){ n++; console.log(n); }; } var c = new a(); c.inc(); //1 c.inc(); //2
3.閉包 有權(quán)訪問另一個(gè)函數(shù)作用域內(nèi)的遍歷都是閉包, Inc函數(shù)訪問
構(gòu)造函數(shù)a里面的遍歷n,所以形成一個(gè)閉包
4.匿名函數(shù),lambda表達(dá)式,閉包區(qū)別:
從功能行上說他們是一個(gè)東西, 只是不同語言的不同稱呼罷了,
它們都是匿名函數(shù), 若匿名函數(shù)捕獲了一個(gè)外部變量,它就是閉包.
qq交流群:140066160
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。