主頁 > 前端設計 > 世界上最流行的腳本-JavaScript,看過不會來找我

世界上最流行的腳本-JavaScript,看過不會來找我

2021-11-06 08:53:55 前端設計

文章目錄

  • 摘要
  • 1 引言
  • 2 基礎
    • 2.1 嵌入網頁
    • 2.2 基本語法
    • 2.3 資料型別
      • 2.3.1 基本資料型別
      • 2.3.2 高級資料型別
    • 2.4 程式結構
      • 2.4.1 順序結構
      • 2.4.2 選擇結構
      • 2.4.3 回圈結構
  • 3 函式
    • 3.1 函式定義
      • 3.1.1 定義函式的兩種方式
      • 3.1.2 函式引數
    • 3.2 變數作用域
    • 3.3 變數提升
    • 3.4 全域作用域
    • 3.5 命名空間
    • 3.6 解構賦值
    • 3.7 方法
    • 3.8 高階函式
      • 3.8.1 map/reduce
      • 3.8.2 filter
      • 3.8.3 sort
  • 4 面向物件
    • 4.1 JS創建物件的方式
    • 4.2 原型物件(prototype)和物件原型(_ _ proto _ _)
    • 4.3 原型物件(prototype)中的constructor屬性
    • 4.4 原型鏈實作繼承
      • 4.4.1 call方法
      • 4.4.2 使用call繼承
      • 4.4.3 原型鏈詳解
      • 4.4.4 通過“中間人”鏈接原型鏈
    • 4.5 class語法糖
      • 4.5.1 class實作繼承

摘要

下面文章中使用JS代替JavaScript

1 引言

JavaScript(以下統一簡稱JS)是目前最流行的腳本語言,沒有之一,在你的手機,pad,電腦等互動邏輯都是通過JS實作的,

JS是一種運行在瀏覽器中的解釋型的編程語言,nodejs將JS移植到了服務端,這讓JS成為了全能戰士

只要你想接觸前端,JS是你繞不開的話題,在web前端領域,JS是絕對的頂流

JS 歷史

1995年,還是一個靜態網頁時代,當時的網景公司憑借Navigator瀏覽器成為Web時代開啟時最著名的第一代互聯網公司,當時網景公司想在靜態頁面加一些動態效果,就讓Brendan Eich設計JS語言,這哥們真是一個天才,竟然在10天時間內寫出JS,沒錯,只有10天,至于為什么名字叫JavaScript,其實就是想蹭一下Java的熱度,語言本身與Java毫無關系,

ECMAScript

因為JavaScript的功能十分適合網頁的動態化,隨著計算機技術的不斷發展,人們也不再滿足于靜態網頁,微軟做為行業巨頭,自然也嗅到了這個機會,于是在JS問世后一年,微軟開發了Jscript,為了能夠讓JS成為全球標準,網景、微軟還有幾家公司聯合ECMA組織制定了Javascript語言標準,被稱為ECMAScript語言標準,

ECMAScript是一種語言標準,JavaScript是網景公司對ECMAScript標準的一種實作,

至于為什么不把JavaScript當作標準名稱呢,是因為JavaScript被網景注冊了商標,不是很嚴謹的場合可以把JS與ECMAScript當作一回事,

發展歷程,版本迭代

JS是10天被設計出來,雖然Eich很牛,但誰也架不住時間緊、任務重,所以,JS有很多設計缺陷,

2015年ES6標準發布

2 基礎

2.1 嵌入網頁

方式1

JS腳本可以被嵌入在網頁的各個部分,使用標簽,一般放在body或者head中

方式2 直接引入檔案

<script src="a.js"><script>

IDE 推薦

  • VScode
  • Sublime
  • Notepad++
  • HbuilderX

2.2 基本語法

JS每條陳述句以“;”結尾,陳述句塊用{,,,},JS并不強制要求在每個陳述句的結尾加“;”,解釋器負責給每個陳述句補上“;”,但是一般情況下,為了保持良好編程習慣,還是要在每行陳述句后面加上一個分號,

陳述句塊

var a = 10;
"hello world!";
var b = 123; var c = 456; // 這是兩條陳述句

注釋

// 單條
/* 
	多條注釋
*/

大小寫

JS大小寫敏感

2.3 資料型別

2.3.1 基本資料型別

Number

JS 不區分整數和浮點數,統一用Number表示

var a = 123;
console.log(typeof(a)); // number 
123; // 整數123
0.456; // 浮點數0.456
1.2345e3; // 科學計數法表示1.2345x1000,等同于1234.5
-99; // 負數
NaN; // NaN表示Not a Number,當無法計算結果時用NaN表示
Infinity; // Infinity表示無限大,當數值超過了JavaScript的Number所能表示的最大值時,就表示為Infinity

數字型別可以使用+、-、*、/ 、%求余運算

字串

//''或者“” 
// ``反引號可以包括多行文本
var s1 = "Hello";
var s2 = 'hello';
var s3 = `
		人生苦短
		我用JS
		多行文本輸出
			`;

布爾

true
false

布爾運算子多用于條件判斷,也可以進行邏輯運算,邏輯與&&,邏輯或||,邏輯非!

console.log(true && false); // false
console.log(true || false); // true
console.log(!true);         // false
var age = 15;
if(age>18){
	console.log("成年人");
}
else{
	console.log("未成年人"); // 未成年人
}

JS中的相等

<script>
    console.log(null === null); // true
	console.log(NaN === NaN);   // false 
	console.log(1/3 === (1-2/3)); // false 
	console.log(Math.abs(1/3)-Math.abs(1-(2/3))<0.0000001); // true 
	console.log('3'===3); // false
	console.log('3'==3);  // true 
</script>

2.3.2 高級資料型別

陣列

JS 的陣列(Array)可以包含任意資料型別,并通過索引來訪問每個元素,通過length屬性獲取Array的長度

  • length

    陣列內的元素是可以原地修改的,可以通過陣列的length屬性動態修改陣列的長度,

    var arr = [1,-9,null,true,99.9];
    console.log(arr.length);
    console.log(arr[1]);
    console.log(arr[2]);
    console.log(arr[4]);
    console.log(arr[5]); // 超過下標也不會報錯,返滬undefined
    arr.length = 8;
    arr[7] = 'hello';
    console.log(arr); // [1, -9, null, true, 99.9, undefined, undefined , "hello"]
    
  • indexOf

    獲取陣列內元素的索引,如果沒有這個元素,回傳-1.如果有這個元素,直接回傳這個元素對應的索引數值

    console.log(arr.indexOf(1)); //0 
    console.log(arr.indexOf(99.9)); //4
    console.log(arr.indexOf('fa')); //-1
    
  • slice

    截取陣列的部分元素,回傳一個新陣列,不包括結尾索引

    var arr = [1,-9,null,true,99.9];
    console.log(arr); //index.html:10 (5) [1, -9, null, true, 99.9]
    var arr_ = arr.slice(0,3);  // 回傳一個新陣列
    console.log(arr_);  // (5) [1, -9, null, true, 99.9]
    console.log(arr);   // (5) [1, -9, null, true, 99.9]
    
  • push/pop

    push:從陣列后面插入元素

    pop:從資料后面洗掉元素

    			var arr = ["三國戰將"]
    			arr.push("趙云");
    			arr.push("關羽");
    			arr.push("張飛");
    			console.log(arr); //(4) ["三國戰將", "趙云", "關羽", "張飛"]
    			console.log(arr.pop()); // 洗掉最后一個元素并回傳
    			console.log(arr);   // (3) ["三國戰將", "趙云", "關羽"]
    
  • unshift/shift

    unshift:從陣列頭部插入元素

    shift:從資料頭部洗掉元素

    			var arr = ["三國戰將"]
    			arr.unshift("趙云");
    			arr.unshift("關羽");
    			arr.unshift("張飛");
    			console.log(arr); //(4) ["張飛", "關羽", "趙云", "三國戰將"]
    			console.log(arr.shift()); // 洗掉第一個元素并回傳
    			console.log(arr);   // (3) ["關羽", "趙云", "三國戰將"]
    
  • sort

    對當前陣列進行排序,原地排序

    var a = ["C","B","A"];
    a.sort();
    console.log(a); // (3) ["A", "B", "C"]
    
  • reverse

    反轉陣列,原地反轉陣列

    var a = ["C","B","A"];
    a.reverse();
    console.log(a); // (3) ["A", "B", "C"]
    
  • splice

    splice()方法是修改Array的“萬能方法”,它可以從指定的索引開始洗掉若干元素,然后再從該位置添加若干元素:

    var a = ["喬丹","科比","艾弗森","卡特","詹姆斯"];
    // 從第二個索引開始,洗掉兩個元素,回傳被洗掉的元素,同時從第二個索引開始添加新元素
    var d = a.splice(2,2,"韋德","安東尼"); 
    console.log(d); //(2) ["艾弗森", "卡特"]
    console.log(a); // (5) ["喬丹", "科比", "韋德", "安東尼", "詹姆斯"]
    
  • concat

    把當前陣列和另一個陣列鏈接起來,回傳一個新陣列

    var a = ["C","B","A"];
    var b = a.concat(1,2,3,[7,8,9]);
    console.log(a); // (3) ["C", "B", "A"]
    console.log(b); //(9) ["C", "B", "A", 1, 2, 3, 7, 8, 9]
    
  • join

    把陣列中的每個元素用指定的字串鏈接起來,回傳鏈接后的字串

    var a = ["C","B","A"];
    var b = a.join('-');
    console.log(a); // (3) ["C", "B", "A"]
    console.log(b); //C-B-A
    
  • 多維陣列

    
    var a = [[1,2,3],[4,5,6]];
    console.log(a[1][1]); // 5
    console.log(a[0][2]); // 3
    

物件

JS的物件是一種無序的集合資料型別,由若干鍵值對組成,物件是面向物件編程的基礎,程式中的一個個物件就是對現實生活的抽象,

用{,,,}表示一個物件, key:value形式申明,每個kv對之間用逗號分割,最后一個鍵值對不需要再末尾加,如果加了,有些老舊瀏覽器將報錯;通過點號可以點出一個物件的屬性,也可以通過obj[attr]獲取屬性,如果屬性名有特殊字符,那么屬性名必須用引號括起來,取屬性的時候不能使用點號,所以物件的屬性盡量使用沒有特殊符號的單詞,做到見名知意

			var xiaoming = {
				name:'小明',
				birth:1994,
				height:1.86,
				weight:78.0,
				score:null
			}
			console.log(xiaoming.name); // 小明
			console.log(xiaoming.age);  // undefined
			console.log(xiaoming.birth); // 1994
			console.log(xiaoming['weight']); // 78
			xiaoming.xixi = 'haha';
			console.log(xiaoming.xixi); // haha
  • 即使物件沒有這個屬性,也不會報錯
  • 可以創建物件后,動態設定屬性,這是動態語言所特殊的
			console.log("xixi" in xiaoming);     // true
			console.log("toString" in xiaoming); // true
			
			console.log(xiaoming.hasOwnProperty('xixi'));  // true
			console.log(xiaoming.hasOwnProperty('age'));   // false
			
			delete xiaoming.xixi;
			console.log(xiaoming.hasOwnProperty('xixi')); // false
  • 判斷物件是否具備某個屬性

    可以使用in關鍵字,attr in object 回傳一個布林值,如上例,toString沒有在xiaoming這個物件中定義,但是同樣回傳true,這說明JS中所有物件的原型鏈都會有object物件,object物件有toString屬性;

    如果只想拿到物件本身的屬性,可以使用object.hasOwnProperty()方法

Map

Map是一組鍵值對結果,Map的查找時間復雜度為O(1)

  • 通過二維陣列構造一個Map

    var m = new Map([['語文',78],['數學',98],['英語',79]]);
    			console.log(m);//Map(3) {"語文" => 78, "數學" => 98, "英語" => 79}
    			console.log(m.get('語文')); // 78
    			console.log(m.has('英語'));  // true 
    			console.log(m.set('物理',100)); // Map(4) {"語文" => 78, "數學" => 98, "英語" => 79, "物理" => 100}
    			delete m.delete('語文');
    			console.log(m);
    			
    

    Map.get() 獲取一個key的值

    Map.has()判斷這個集合中是否有這個key

    Map.set() 設定key-value

    Map.delete() 洗掉map的某個key

Set

Set和Map類似,Set是一個key的集合,但不存盤value,由于key不能重復,所以Set中每個key都是唯一的,

創建一個Set,需要提供Array作為輸入,或者直接創建一個空Set

			var s = new Set();
			s.add(1);
			s.add(2);
			s.add(3);
			s.add(3);
			console.log(s); // Set(3) {1, 2, 3}
			var s1 = new Set([1,2,3,'3',3,3,3]);
			console.log(s1); // Set(4) {1, 2, 3, "3"}
			s1.delete('3');
			s1.delete(2);
			console.log(s1);  // Set(2) {1, 3}

2.4 程式結構

2.4.1 順序結構

JS中的順序結構就是從上而下執行的,

2.4.2 選擇結構

nullundefined0NaN和空字串''視為false,其他值一概視為true

'use strict';
			var height = parseFloat(prompt("請輸入身高(m):"));
			var weight = parseFloat(prompt("請輸入體重(kg):"));
			var bmi = weight / (height*height);
			if(bmi<18.5){
				console.log("過輕");
			}
			else if(bmi>=18.5 && bmi < 25){
				console.log("正常");
			}
			else if(bmi>=25 && bmi < 28){
				console.log("過重");
			}
			else if(bmi >=28 && bmi < 32){
				console.log("肥胖");
			}
			else if(bmi >=32){
				console.log("嚴重肥胖");
			}
			else{
				console.log("資料有誤");
			}

2.4.3 回圈結構

  • while

    先判斷條件,條件不滿足一次都不執行

    'use strict';
    var sum = 0;
    var i =0 ;
    while(i<=100){
    	sum += i;
    	i ++ 
    }
    console.log(sum); // 5050
    
  • do-while

    先執行回圈體,在判斷條件,至少會執行一次回圈體

    'use strict';
    var sum = 0;
    do{
    	sum += i;
    	i ++ 
    }while(i<=100);
    console.log(sum);
    

    通過一個小實體看一下while與do… while的區別

    
    			'use strict';
    			var sum = 0;
    			var sum_ = 0;
    			var i =1 ;
    			do{
    				sum += i;
    				i ++ 
    			}while(i>100);
    			console.log(sum);  // 1
    			
    			
    			while(i>100){
    				sum_ += i;
    				i++;
    			}
    			console.log(sum_); // 0
    
    

    回圈一定要注意結束條件,< 與 <= 會是完全不同的結果

  • 普通for回圈

    與C語言的for回圈基本相同

    var sum = 0;
    for(let i=0;i<=100;i++){
    	sum += i;
    }
    console.log(sum); // 5050 
    
  • for…in

    遍歷陣列和物件這種容器資料型別

    'use strict';
    var arr = ["張飛","關羽", "趙云"];
    for(let i in arr){
    	console.log(i);
    	console.log(arr[i]);
    }
    			
    var obj1 = {
    	name:'xiaohua',
    	age:14,
    	grade:4
    }
    for(let i in obj1){
    	console.log(i);
    	console.log(obj1[i]);
    }
    

在這里插入圖片描述

  • for…of

    遍歷Array可以采用下標回圈,遍歷MapSet就無法使用下標,為了統一集合型別,ES6標準引入了新的iterable型別,ArrayMapSet都屬于iterable型別,

    具有iterable型別的集合可以通過新的for ... of回圈來遍歷,

    'use strict';
    var arr = ["張飛","關羽", "趙云"];
    			
    for(let i of arr){
    	console.log(i);
    }
    			
    for(let i of new Map([['語文',12],['數學',78]])){
    	console.log(i);
    }
    			
    for(let i of new Set([1,2,3])){
    	console.log(i);
    }
    

在這里插入圖片描述

  • foreach

    iterable內置的forEach方法,它接收一個函式,每次迭代就自動回呼該函式,

    'use strict';
    var a = ['A', 'B', 'C'];
    a.forEach(function (element, index, array) {
        // element: 指向當前元素的值
        // index: 指向當前索引
        // array: 指向Array物件本身
        console.log(element + ', index = ' + index);
    });
    // 張飛, index = 0
    // 關羽, index = 1
    // 趙云, index = 2
    

3 函式

函式是對一系列動作的抽象

3.1 函式定義

3.1.1 定義函式的兩種方式

方式1:

'use strict';

function abs(x) {
	if (x >= 0) {
		return x;
	} else {
		return -x;
	}
}
var result = abs(-9);
console.log(result);

方式2

? 函式也是一個物件,通過function()關鍵字定義函式

'use strict';

var abs = function (x) {
	if (x >= 0) {
		return x;
	} else {
		return -x;
	}
}
var result = abs(-9);
console.log(result);

3.1.2 函式引數

JS函式對于引數沒有限制,可以多傳遞,也可以少傳遞,都不會報錯

'use strict';

var abs = function (x) {
	if (x >= 0) {
		return x;
	} else {
		return -x;
	}
}
var result = abs();
console.log(result); // NaN

result = abs(-9,1,'b','c','d','w');
console.log(result); // 9

arguments

arguments 是JS的一個關鍵字,這個關鍵字只有在函式內部有用,存盤的資訊是傳入函式的引數,arguments類似Array但它不是一個Array,

'use strict';

var abs = function (x) {
	console.log(arguments);
	for (let i=0; i<arguments.length;i++){
		console.log(arguments[i]);
	}
	if (x >= 0) {
		return x;
	} else {
		return -x;
	}
}
var result;
result = abs(-9,1,'b','c','d','w');
console.log(result); // 9

在這里插入圖片描述

通過實體可以發現,無論有沒有給函式加形式引數,都可以通過arguments關鍵字獲取,

rest 引數

ES6標準引入了rest引數,arguments獲取到了所有的輸入引數,rest引數只獲取額外的引數,rest引數前面使用…標識,

var test = function (a, b, ...rest){
	console.log(a); // 1
	console.log(b); // 2
	console.log(rest); // (4) [3, 4, 5, 6]
}

test(1,2,3,4,5,6);

小心return

var test = function (a, b, ...rest){
	console.log(a); // 1
	console.log(b); // 2
	console.log(rest); // (4) [3, 4, 5, 6]
	return //瀏覽器會默認添加一個分號
	10  // 這句話就執行不了了
}

var res = test(1,2,3,4,5,6);

console.log(res); // undefined 

3.2 變數作用域

如果一個變數在函式體內部申明,則該變數的作用域為整個函式體,在函式體外不能應用改變數

'use strict';

var f1 = function(){
	var a = 10;
	console.log(a);
}


console.log(a); //main.js:9 Uncaught ReferenceError: a is not defined at main.js:9

不同函式的相同函式名是相互獨立,互不干擾的

嵌套函式,內部函式可以訪問外部函式的作用域,外部函式訪問不到內部函式的作用域

'use strict';

function outer(){
	var a = 10;
	function inner(){
		var b = 11;
		console.log(a);
	}
	inner();  // 10
	console.log(b);  // ReferenceError: b is not defined
}


outer();

內外部函式具有相同名稱的變數,內部函式會覆寫外部函式

function outer(){
	var a = 10;
	function inner(){
		var a = 11;
		console.log(a);
	}
	inner();  // 11
	console.log(b);  // ReferenceError: b is not defined
}


outer();

這說明JavaScript的函式在查找變數時從自身函式定義開始,從“內”向“外”查找,如果內部函式定義了與外部函式重名的變數,則內部函式的變數將“屏蔽”外部函式的變數,

3.3 變數提升

JS有三種宣告變數的關鍵字,const, let, var

const 定義常量

'use strict'; 

const PI = 3.14;

PI = 3; // TypeError: Assignment to constant variable.

console.log(PI);
// 不能改變常量的值

// 具有塊級作用域
{
	const sum = 0 
	const a = 11;
	console.log(sum); // 0
}


{
	const sum =100;
	const a = 12;
	console.log(sum); // 110
}

console.log(sum); // main.js:18 Uncaught ReferenceError: sum is not defined

let 定義變數具有塊級作用域,沒有變數提升

// let不具備變數提升
var f1 = function(){
	var a = 1;
	console.log(a+b); //  ReferenceError: b is not defined
	let b =2;
}

f1() 

// 具有塊級作用域

{
	let sum = 0 
	let a = 11;
	sum += a;
	console.log(sum); // 11
}


{
	let sum =100;
	let a = 12;
	sum += a;
	console.log(sum); // 112
}

console.log(sum); // main.js:18 Uncaught ReferenceError: sum is not defined

vat 定義變數不具備塊級作用域,具有變數提升

// 未定義變數b,直接使用不報錯,是因為JS變數提升機制,但是賦值不會提升
var f1 = function(){
	var a = 1;
	console.log(a+b); // NaN
	var b =2;
}

f1() 

// 沒有塊級作用域
{
	var sum = 0 
	var a = 11;
	sum += a;
	console.log(sum); // 11
}


{
	var sum =100;
	var a = 12;
	sum += a;
	console.log(sum); // 112
}

console.log(sum); // 112



3.4 全域作用域

不在任何函式內定義的變數就具有全域作用域,實際上,JavaScript默認有一個全域物件window,全域作用域的變數實際上被系結到window的一個屬性

var sub = "learn";

console.log(sub);   // learn 
console.log(window.sub); // learn 

alert("hello");
window.alert('hello');

// 全域window

var temp = window.alert;

window.alert = function(){}

alert("hello"); // 沒反應

window.alert = temp;

alert("hello"); // 觸發

3.5 命名空間

使用命令空間可以凈化全域作用域

var myApp = {}


myApp.test = "hello"

myApp.f1 = function() {
	console.log("myapp f1 is running");
}

myApp.f1();


var myApp2 = {}

myApp2.test = "world";

myApp2.f1 = function() {
	console.log("myapp f2 is running");
}

myApp2.f1();

3.6 解構賦值

// 1 直接拆包
var [x,y,z] = ['hello','china','haha'];

console.log(x); // hello
console.log(y); // china
console.log(z);  // haha

// 2 格式必須相同
var [x,y,[a,b]] = ['中國','河北',['北京','天津']]; 
console.log(x); // 中國
console.log(y); // 河北
console.log(a); // 北京
console.log(b); // 天津

// 3 可以忽略一部分
var [,,x] = ['hello','china','haha']; 
console.log(x); // haha 

3.7 方法

在一個物件中系結函式,叫做這個物件得方法

var xiaoming = {
    name: '小明',
    birth: 1990,
	age:function(){
		var y = new Date().getFullYear();
		return y-this.birth;
	},
};

var age = xiaoming.age();
console.log(age);

this關鍵字

this是一個特殊的關鍵字,始終指向當前物件,也就是上例中的xiaoming物件,所以,this.birth可以拿到xiaoming的birth屬性,

// 拆開寫

3.8 高階函式

3.8.1 map/reduce

map 將一個函式作用在一個陣列的所有元素上

function pow(x){
	return x*x;
}

var arr = [1,2,3,4,5,6,7,8,9];

var new_arr = arr.map(pow);

console.log(arr); // (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(new_arr); // (9) [1, 4, 9, 16, 25, 36, 49, 64, 81]

// 同樣可以用for回圈實作

var new_arr = new Array();

for(let i=0; i<arr.length;i++){
	new_arr.push(pow(arr[i]));
}

console.log(new_arr); // (9) [1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce

function add(x,y){
	return x+y;
}
var arr = [1,2,3,4,5,6,7,8,9];
var res = arr.reduce(add);// = add(add(add(add(add(add(add(add(1,2),3),4),5),6),7,8,9)
console.log(res);

3.8.2 filter

對一個陣列內的元素進行過濾,滿足條件的保留,不滿足的剔除

'use strict';

var arr = [1,2,3,4,5,6,7,8,9];

function even(x){
	if ((x%2)==0){
		return true;
	}
	else{
		return false;
	}
}

var res = arr.filter(even);
console.log(res);  // (4) [2, 4, 6, 8]

3.8.3 sort

var arr = [10, 20, 1, 2];
arr.sort((x, y) => {
    return x - y
});
console.log(arr); // [1, 2, 10, 20]

4 面向物件

4.1 JS創建物件的方式

字面量

'use strict';

var obj = {
	"name":"zhangsan",
	"age":14,
	"grade":"一年級"
};


console.log(obj);

使用建構式創建物件

function Player(name, age){ // 這是一個建構式
	this.name = name;
	this.age = age;
	this.run = function() {
		console.log(this.name + " is running!"); 
	}

}

var kobe = new Player("kobe", 12);
kobe.run(); // kobe is running!
var james = new Player("James", 123);
james.run();//James is running!

如果不寫new,這就是一個普通函式,它回傳undefined,但是,如果寫了new,它就變成了一個建構式,它系結的this指向新創建的物件,并默認回傳this,也就是說,不需要在最后寫return this;

忘記寫new的后果

  • ‘use strict’; 模式下,this的指向是undefined,給一個undefined系結name會報錯

    'use strict';
    
    function Player(name, age){
    	this.name = name; // Cannot set properties of undefined (setting 'name')
    	this.age = age;
    	this.run = function() {
    		console.log(this.name + " is running!"); 
    	}
    
    }
    
    var kobe =  Player("kobe", 12);
    // main.js:5 Uncaught TypeError: Cannot set properties of undefined (setting 'name')
    
  • 不是嚴格模式下,this指向的是window,this.name會直接設定一個全域變數,這樣更危險,因為污染了命名空間

    function Player(name, age){
    	this.name = name; 
    	this.age = age;
    	this.run = function() {
    		console.log(this.name + " is running!"); 
    	}
    
    }
    
    
    Player("kobe", 11);
    console.log(name); //kobe
    console.log(age);  // 11
    run();  // kobe is running!
    

4.2 原型物件(prototype)和物件原型(_ _ proto _ _)

JS 中一切皆物件,每個物件都會設定一個原型,也就是物件原型_ _ proto _ _屬性,物件原型這個屬性指向它的原型物件,這里說起來比較繞,原型鏈也是JS中的重點和難點,原型鏈在JS中的地位就類似Python中魔法方法的地位,搞不懂就只能停留到初級階段,無法體會JS的精髓,

使用建構式創建物件存在的問題

在這里插入圖片描述

'use strict';


function Player(name, age){
	this.name = name; 
	this.age = age;
	this.run = function() {
		console.log(this.name + " is running!"); 
	}

}


var kobe = new Player("kobe",456);
var james = new Player("James", 123);

console.log(kobe.run == james.run); // false

通過上面的圖片和代碼的運行結果可以發現,每創建一個物件都會在記憶體中開辟出一個空間,保存這個物件的屬性和方法,屬性沒有關系,但是相同的方法卻被復制了很多次,如果創建的物件很多,那么程式的時間復雜度和空間復雜度會成倍增加,顯然這不是一個好辦法,

JS的發明者自然考慮到了這個問題,可以通過原型物件來解決,前面已經說過了JS中的每個物件都有一個原型物件,我們看一下什么是原型物件:

在這里插入圖片描述

'use strict';


function Player(name, age){
	this.name = name; 
	this.age = age;
}

Player.prototype.run = function(){
	console.log(this.name + "is running");
}


var kobe = new Player("kobe",456);
var james = new Player("James", 123);

console.log(kobe);

console.log(kobe.run == james.run); // false

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-odeYPvd4-1636016576605)(C:\Users\z004abwh\AppData\Roaming\Typora\typora-user-images\image-20211104151108745.png)]

物件的原型鏈

kobe------> Player.prototype ----------> Object.prototype ----------> null

4.3 原型物件(prototype)中的constructor屬性

原型物件的constructor屬性指向的是建構式本身,

console.log(kobe.__proto__.constructor); // 指向的就是其建構式

/*
? Player(name, age){
	this.name = name; 
	this.age = age;
}
*/

constructor用法:

如果一個建構式,類似下面這種方式網原型物件添加屬性,寫起來會很長,之間的關系不是很清晰

function Player(name, age){
	this.name = name; 
	this.age = age;
}

Player.prototype.run = function(){
	console.log(this.name + "is running");
}

Player.prototype.jump = function(){
	console.log(this.name + "is jumpping");
}

換一種方式:

function Player(name, age){
	this.name = name; 
	this.age = age;
}


Player.prototype = {

	constructor: Player, // 如果不加這個原型物件就會被覆寫,也就不知道實體是由哪個類實體化出來的

	run: function(){
		console.log(this.name + "is running");
	},
	jump:function(){
		console.log(this.name + "is jumpping");
	}
}


var kobe = new Player("kobe",456);
var james = new Player("James", 123);

console.log(kobe.__proto__.constructor);

console.log(kobe.__proto__)

console.log(kobe instanceof Player);

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PFHCdLPf-1636016576606)(C:\Users\z004abwh\AppData\Roaming\Typora\typora-user-images\image-20211104152436251.png)]

如果把constructor: Player這句話注釋掉,結果如下:

在這里插入圖片描述

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Q8G8KMaM-1636016576608)(C:\Users\z004abwh\AppData\Roaming\Typora\typora-user-images\image-20211104163927922.png)]

4.4 原型鏈實作繼承

4.4.1 call方法

function add(x, y){
	console.log(x+y);
}

function sub(x, y){
	console.log(x-y);
}

add.call(sub,1,3); // 4   用add函式替代sub函式
sub.call(add,1,3); // -2  用sub函式替代add函式

4.4.2 使用call繼承

function Sex(props){
	this.sex = props.sex;
}


function Person(props){
	this.name = props.name;
}


function Student(props){
	Person.call(this, props); 
	Sex.call(this, props);
	this.grade = props.grade;
}


var s1 = new Student({
	name:'zs',
	grade:123,
	sex:'男'
});

console.log(s1.name); // zs
console.log(s1.grade); // 123
console.log(s1.sex);  // 男

4.4.3 原型鏈詳解

function Person(props){
	this.name = props.name;
}

Person.prototype.say = function(){
	console.log("人都會說話的");
}

function Student(props){
	Person.call(this, props); 
	this.grade = props.grade;
}


var s1 = new Student({
	name:'zs',
	grade:123
});



console.log(s1);
s1.say(); // TypeError: s1.say is not a function
console.log(s1.__proto__ == Student.prototype)               // true
console.log(s1.__proto__.__proto__ == Object.prototype)      // true
console.log(s1.__proto__.__proto__.__proto__ == null)        // true

為什么出現這種報錯呢?

s1 ------> Student.prototype -------> Object.prototype --------> null

這是什么鳥繼承?只是繼承了屬性,但是原型鏈沒有經過Person.prototype,所以會報錯,

正確的原型鏈應該是這樣的:

s1 ------> Student.prototype -------> Person.prototype ------> Object.prototype --------> null

Student.prototype = Person.prototype這樣是不行的,因為Student和Person共享一個原型物件,那么創建兩個類也沒有意義,

4.4.4 通過“中間人”鏈接原型鏈

function Person(props){
	this.name = props.name;
}

Person.prototype.say = function(){
	console.log("人都會說話的");
}

function Mid(){}


function Student(props){
	Person.call(this, props); 
	this.grade = props.grade;
}


Mid.prototype = Person.prototype;  // 把Mid的原型指向 Person.prototype
Student.prototype = new Mid() ;    // 把Student的原型指向一個Mid物件, Mid物件的原型正好指向Person.prototype 
Student.prototype.constructor = Student;  // 把Student的原型的建構式恢復成Student


var s1 = new Student({
	name:'zs',
	grade:123
});



console.log(s1); 
s1.say();  //人都會說話的
console.log(s1.__proto__ == Student.prototype)               // true
console.log(s1.__proto__.__proto__ == Person.prototype)      // true
console.log(s1.__proto__.__proto__.__proto__ == Object.prototype)        // true

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xVWGsjwA-1636016576608)(C:\Users\z004abwh\AppData\Roaming\Typora\typora-user-images\image-20211104165043702.png)]

4.5 class語法糖

使用class創建類

'use strict';


class Person {
	constructor (name){
		this.name = name;
	}
	
	say() {
		console.log(this.name + " is saying !");
	}

}


var p1 = new Person("正常人");

p1.say()  // 正常人 is saying !

4.5.1 class實作繼承

ES6的新特性通過class實作繼承,class繼承的方式可以減少撰寫原型鏈的代碼,但是前提是瀏覽器要支持ES6.

'use strict';


class Person {
	constructor (name){
		this.name = name;
	}
	
	say() {
		console.log(this.name + " is saying !");
	}

}


class Student extends Person{
	constructor(name,grade){
		super(name);
		this.grade = grade;
	}

	study() {
		console.log(this.grade+"年級的學生就應該學習");
	}
}


var p1 = new Student("學生甲乙丙丁", 4);

p1.say();   //學生甲乙丙丁 is saying ! 
p1.study(); // 4年級的學生就應該學習

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/349656.html

標籤:其他

上一篇:簡單的 html拖動模態框 案例

下一篇:微軟將JavaScript API引入 Excel

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more