JavaScript學習記錄十七
apply和call方法的使用
//apply和call的使用 //作用:可以改變this的指向
//apply和call方法中如果沒有傳入引數,或者是傳入的是null,那麼呼叫該方法的函式物件中的this就是預設的window
*JavaScript中存在繼承,通過呼叫apply或call傳過去的第一個引數來動態指定方法中的 this .
function f1(x,y) { console.log("結果是:"+(x+y)+this); return "10000"; } f1.apply(); f1.call(); f1.apply(null); f1.call(null); apply和call都可以讓函式或者方法來呼叫,傳入引數和函式自己呼叫的寫法不一樣,但是效果是一樣的 f1.apply(null,[100,200]); f1.call(null,100,200);
apply和call的使用方法 /* * apply的使用語法 * 函式名字.apply(物件,[引數1,引數2,...]); * 方法名字.apply(物件,[引數1,引數2,...]); * call的使用語法 * 函式名字.call(物件,引數1,引數2,...); * 方法名字.call(物件,引數1,引數2,...); * * 作用:改變this的指向 * 不同的地方:引數傳遞的方式是不一樣的
* 只要是想使用別的物件的方法,並且希望這個方法是當前物件的,那麼就可以使用apply或者是call的方法改變this的指向
function f1() { console.log(this+":====>呼叫了"); } f1是函式,f1也是物件,因為f1中有 __proto__和prototype console.dir(f1); 物件呼叫方法,說明,該物件中有這個方法 f1.apply(); f1.call(); console.log(f1.__proto__==Function.prototype); 所有的函式都是Function的例項物件 console.log(Function.prototype);//ƒ () { [native code] } console.dir(Function); apply和call方法實際上並不在函式這個例項物件中,而是在Function的prototype中
bind是用來複制一份 //使用的語法: /*理解:將改變this後的函式狀態複製了一份。函式呼叫之後內部this使用的是指定後的 * 函式名字.bind(物件,引數1,引數2,...);---->返回值是複製之後的這個函式 * 方法名字.bind(物件,引數1,引數2,...);---->返回值是複製之後的這個方法
function Person(age) {
this.age=age;
}
Person.prototype.play=function () {
console.log(this+"====>"+this.age);
};
function Student(age) {
this.age=age;
}
var per=new Person(10);
var stu=new Student(20);
//複製了一份
var ff=per.play.bind(stu);
ff(); [object Object]====>20
bind方法的使用
<script>
通過物件,呼叫方法,產生隨機數
function ShowRandom() {
1-10的隨機數
this.number=parseInt(Math.random()*10+1);
}
新增原型方法
ShowRandom.prototype.show1=function () {
改變了定時器中的this的指向了,本來應該是window,現在是例項物件了
window.setInterval(this.show2.bind(this),1000);
};
新增原型方法
ShowRandom.prototype.show2=function () {
顯示隨機數--
console.log(this.number);
};
例項物件
var sr=new ShowRandom();
呼叫方法,輸出隨機數字
呼叫這個方法一次,可以不停的產生隨機數字
sr.show1();
</script>
函式中的幾個成員
//函式中有一個name屬性----->函式的名字,name屬性是隻讀的,不能修改 //函式中有一個arguments屬性--->實參的個數 //函式中有一個length屬性---->函式定義的時候形參的個數 //函式中有一個caller屬性---->呼叫(f1函式在f2函式中呼叫的,所以,此時呼叫者就是f2)
function f1(x,y) {
console.log(f1.name);
console.log(f1.arguments.length);
console.log(f1.length);
console.log(f1.caller);//呼叫者
}
函式還可以通過引數傳遞來實現呼叫,在函式體中執行函式
function f1(fn) {
setInterval(function () {
console.log("定時器開始");
fn();
console.log("定時器結束");
},1000);
}
f1(function () {
console.log("好睏啊,好累啊,就是想睡覺");
});
函式作為返回值
可以參考java中設定toString方法進行理解
var num=10;
console.log(typeof num); number
var obj={};
console.log(obj instanceof Object); true
更改this為obj,直接列印obj的使用會顯示其資料型別
Object.prototype.toString.call(obj);
console.log(obj) {}
獲取資料型別,修改this指向具體型別資料,通過toString方法進行列印
console.log(Object.prototype.toString.call([])); [object Array]
console.log(Object.prototype.toString.call(new Date())); [object Date]
函式作為返回值的使用
function getFunc(type) {
return function (obj) {
return Object.prototype.toString.call(obj) === type;
}
}
var ff = getFunc("[object Array]");
var result = ff([10, 20, 30]);
console.log(result); true
函式作為引數練習,有點像java中的重寫equals方法
*sort方法會從零號位置進行遍歷和比較,如果返回值大於零,則進行交換。
var arr = [1, 100, 20, 200, 40, 50, 120, 10];
//排序---函式作為引數使用,匿名函式作為sort方法的引數使用,那麼此時的匿名函式中有兩個引數,
arr.sort(function (obj1,obj2) {
if(obj1>obj2){
return -1;
}else if(obj1==obj2){
return 0;
}else{
return 1;
}
});
console.log(arr);
var arr1=["acdef","abcd","bcedf","bced"];
arr1.sort(function (a,b) {
if(a>b){
return 1;
}else if(a==b){
return 0;
}else{
return -1;
}
});
console.log(arr1);
案例:函式作為引數
function File(name, size, time) {
this.name = name;//電影名字
this.size = size;//電影大小
this.time = time;//電影的上映時間
}
var f1 = new File("jack.avi", "400M", "1997-12-12");
var f2 = new File("tom.avi", "200M", "2017-12-12");
var f3 = new File("xiaosu.avi", "800M", "2010-12-12");
var arr = [f1, f2, f3];
function fn(attr) {
//函式作為返回值
return function getSort(obj1, obj2) {
if (obj1[attr] > obj2[attr]) {
return 1;
} else if (obj1[attr] == obj2[attr]) {
return 0;
} else {
return -1;
}
}
}
var ff = fn("name");
//函式作為引數
arr.sort(ff);
for (var i = 0; i < arr.length; i++) {
console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);
}
作用域和作用域鏈和預解析
//變數---->區域性變數和全域性變數, //作用域:就是變數的使用範圍 //區域性作用域和全域性作用域 //js中沒有塊級作用域---一對括號中定義的變數,這個變數可以在大括號外面使用 //函式中定義的變數是區域性變數
if(true){
var num=10;
}
console.log(num) 10
function fn() {
var num2=20;
}
console.log(num2); 報異常 num2 is not defined
作用域鏈:變數的使用,從裡向外,層層的搜尋,搜尋到了就可以直接使用了層層搜尋,搜尋到0級作用域的時候,如果還是沒有找到這個變數,結果就是報錯
*如果裡層沒有對應的變數,它會一層一層想外查詢
var num=10;
function f() {
var num=20;
function f1() {
var num=30;
console.log(num);
}
f1();
}
f();
//預解析:就是在瀏覽器解析程式碼之前,把變數的 宣告 和 函式的宣告 提前(提升)到該作用域的最上面
console.log(num);
var num=10; undefined 宣告提前了,但是沒有初始化
f(); 函式執行了,預解析函式提前了
function f() {
console.log('函式執行了')
}
console.log(f1); undefined 函式的宣告提前了
var f1=function() {
console.log('宣告提前了')
}
閉包 * 閉包的概念:函式A中,有一個函式B,函式B中可以訪問函式A中定義的變數或者是資料,此時形成了閉包(這句話暫時不嚴謹) * 閉包的模式:函式模式的閉包,物件模式的閉包 * 閉包的作用:快取資料,延長作用域鏈 * 閉包的優點和缺點:快取資料
函式模式的閉包:在一個函式中有一個函式
function f1() {
var num=10;
//函式的宣告
function f2() {
console.log(num); 10
}
//函式呼叫
f2();
}
f1();
物件模式的閉包:函式中有一個物件
function f3() {
var num=10;
var obj={
age:num
};
console.log(obj.age);//10
}
f3();
閉包小練習
function f() {
var num=10;
return function(){
num++;
return num;
}
}
var fn=f();
console.log(fn()); 11
console.log(fn()); 12
console.log(fn()); 13
總結:如果想要快取資料,就把這個資料放在外層的函式和裡層的函式的中間位置
//閉包的作用:快取資料.優點也是缺陷,沒有及時的釋放
//區域性變數是在函式中,函式使用結束後,區域性變數就會被自動的釋放 //閉包後,裡面的區域性變數的使用作用域鏈就會被延長
function showRandom() {
var num=parseInt(Math.random()*10+1);
console.log(num);
}
showRandom();
showRandom();
showRandom();
實現了快取功能的閉包,多次呼叫列印的數字都一樣
function f1() {
var num=parseInt(Math.random()*10+1);
return function () {
console.log(num);
}
}
var ff=f1();
ff();
ff();
ff();
案例:點贊小案例
<style>
ul {
list-style-type: none;
}
li {
float: left;
margin-left: 10px;
}
img {
width: 200px;
height: 180px;
}
input {
margin-left: 30%;
}
</style>
<script>
//$永遠都是24k純帥的十八歲的楊哥$
</script>
</head>
<body>
<ul>
<li><img src="images/ly.jpg" alt=""><br/><input type="button" value="贊(1)"></li>
...若干個...
</ul>
<script>
//獲取所有的按鈕
//根據標籤名字獲取元素
function my$(tagName) {
return document.getElementsByTagName(tagName);
}
//閉包快取資料
function getValue() {
var value=2;
return function () {
//每一次點選的時候,都應該改變當前點選按鈕的value值
this.value="贊("+(value++)+")";
}
}
//獲取所有的按鈕
var btnObjs=my$("input");
//迴圈遍歷每個按鈕,註冊點選事件
for(var i=0;i<btnObjs.length;i++){
//註冊事件
btnObjs[i].onclick=getValue();
}
沙箱:環境,黑盒,在一個虛擬的環境中模擬真實世界,做實驗,實驗結果和真實世界的結果是一樣,但是不會影響真實世界
var num=10;
(function () {
var num=20;
console.log(num+10); 30
})();
沙箱小案例
(function () {
document.getElementById('btn').onclick=function () {
console.log('按鈕被點選了')
}
})();
(function () {
var str='我是中國人';
console.log(str.substr(2)) 中國人
})();
沙箱小案例
<div>這是div</div>
<div>這是div</div>
<p>這是p</p>
<p>這是p</p>
<script>
var getTag = 10;
var dvObjs = 20;
var pObjs = 30;
(function () {
//根據標籤名字獲取元素
function getTag(tagName) {
return document.getElementsByTagName(tagName)
}
//獲取所有的div
var dvObjs = getTag("div");
for (var i = 0; i < dvObjs.length; i++) {
dvObjs[i].style.border = "2px solid pink";
}
//獲取所有的p
var pObjs = getTag("p");
for (var i = 0; i < pObjs.length; i++) {
pObjs[i].style.border = "2px solid pink";
}
}());
console.log(getTag); 10
console.log(dvObjs); 20
console.log(pObjs); 20
遞迴:函式中呼叫函式自己,此時就是遞迴,遞迴一定要有結束的條件
function f(n) {
if(n==1){
return 1;
}
return n+f(n-1);
}
console.log(f(10));