JavaScript 語法筆記

水丸發表於2018-08-21

目錄

 

 

1.JS放在哪

2.定義變數

3.基本資料型別

  3.1 5種基本資料型別

  3.2  變數作用域

  3.3  變數提升 

  3.4 let變數

  3.5 const定義變數

4. 複合型別

   4.1 陣列

   4.2 函式

    4.2.1  函式的定義

    4.2.2 函式、類、物件、方法、變數

   4.2.3 函式的例項屬性和類屬性

   4.2.4 函式呼叫

   4.2.5 函式的獨立性

   4.2.6 函式提升

   4.2.7 變數與函式同名

   4.2.8 箭頭函式

5. 物件導向

  5.1 prototype實現繼承

  5.2 構造器實現偽繼承

  5.3 使用apply或call實現偽繼承

6. 建立物件


 

1.JS放在哪

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- 瀏覽器不支援或禁用javascript時該元素顯示-->
<noscript>
    <h1 >"請支援javascript功能"</h1>;
</noscript>

<!-- type one      action when click -->
<a href="javascript:alert('hello world!')">hello world!</a>

<!-- type two -->
<script type="text/javascript">
    alert("hello world!");
</script>

<!-- type three   defer:推遲指令碼執行  async:啟動新執行緒,非同步執行指令碼 -->
<!-- 兩種屬性只可用於此種外部指令碼檔案模式-->
<script src="first.js" type="text/javascript" defer async></script>


</body>
</html>

 

2.定義變數

javascript是弱型別語言,可以不定義變數直接而使用,存在顯示定義變數(使用關鍵字var)和隱式定義變數兩種,變數的資料型別也可隨意轉變。

<script type="text/javascript">
    var a = true;
    b = 2;
    b = false;
</script>

 

3.基本資料型別

  3.1 5種基本資料型別

  •       數值型別
<script type="text/javascript">
    //科學計數法
    var a = 3E2;  //300
    var b = 2.1e-2; //0.021

    //整數部分只有0時,可省略
    var c = 0.3;
    var d = .3;  //0.3

    //非十進位制計數
    var e = 0o14; //八進位制
    var f = 0x10; //十六進位制

</script>

 

  • 布林型別

 true 或 false

 

  •  字串型別

 必須用引號括起來,可為單引號,也可為雙引號

 

  • undefined型別

用於表示某個變數或屬性不存在,或已建立但未為其分匹配值

  • null型別

用於表示變數有值,且為null

 

 3.2  變數作用域

全域性變數:函式外定義的 + 函式內不用var定義的 變數

區域性變數:函式內用var定義的變數

  • 區域性變數的作用域僅限於該函式,javascript變數不存在塊範圍;
  • 當變數同名時,在區域性變數作用域內,區域性變數會覆蓋全域性變數

 

 3.3  變數提升 

變數提升機制,指的是變數宣告總是被直譯器“提升”到函式體的頂部。

  • 只是提升區域性變數
  • 只是提升宣告部分,不包括賦值部分
  • 只要有宣告變數的語句都會被提升,不論該語句是否執行或有沒有機會執行
<script type="text/javascript">
    var a = "全域性變數";
    function f(){
        alert(a); //undefined
        var a = "區域性變數";
        alert(a); //區域性變數
    }
    f();
</script>

所以以上程式碼效果等同於如下

<script type="text/javascript">
    var a = "全域性變數";
    function f(){
        var a; //變數宣告提升
        alert(a); //undefined
        a = "區域性變數";
        alert(a); //區域性變數
    }
    f();
</script>

 

 3.4 let變數

  • let 變數存在塊作用域
  • let變數不會自動新增為全域性window物件的屬性
  • let變數不會提前裝載
<script type="text/javascript">
    var a = "全域性變數";
    function f(){
        // 區域性變數a覆蓋了全域性變數a,故全域性變數無效
        // 由於let變數不會提前裝載,故此處的a為未定義的變數
        alert(a); //語法錯誤
        let a = "區域性變數";
        alert(a); //區域性變數
    }
    f();
</script>

 

 3.5 const定義變數

  • 必須在定義時指定初始值,且以後不能改變值

 

4. 複合型別

   javascript複合型別大致有以下三種:

  • Object:物件
  • Array:陣列
  • Function:方法

   4.1 陣列

  • 陣列長度可變
  • 同一個陣列的元素型別可互不相同
  • 訪問陣列元素時不存在越界,訪問未賦值的陣列元素時,該元素值為undefined
    // 建立陣列的三種方式
    var a = new Array();
    var b = [];
    var c = [1,3,true];
  •  陣列作為棧使用

      push(e):元素入棧,返回入棧後陣列長度

      pop():元素出棧,返回出棧元素

 入棧還是出棧,都是在陣列的下標大的地方操作

  • 陣列作為佇列使用

   unshift(e):元素如佇列,返回如佇列後陣列長度

   shift():元素出佇列,返回出佇列元素

入佇列還是出佇列,都是在陣列下標小(0)的地方操作

 

4.2 函式

   for in迴圈

  •   當遍歷陣列時,迴圈計數器是陣列元素的索引值
  •   當遍歷物件時,迴圈計數器是物件的屬性名

    4.2.1  函式的定義

  • 返回值不需要資料型別宣告,形參也不需要資料型別宣告
     //命名函式
     function f1(param-list){
         statements
     }
     
     //匿名函式
     [var f2 = ] function(param-list){
         statements
     };

     [var f3 = ] new Function('param1','param2', ... , "statements");

   

    4.2.2 函式、類、物件、方法、變數

       函式是javascript中的“一等公民”,定義一個函式後,就得到了一個與函式名相同的,也得到了一個Function類例項物件,它通常會附加給某個物件(預設window),作為其方法,最後,它也是一個變數

<script type="text/javascript">
     var person = function(name, age){
         this.name = name;
         this.age = age;

         this.talk = function(){
             document.write("Hi,I`m "+name+"<br />");
         }

         var walk = function(){
             document.write("I am "+age+",I can walk..."+"<br />");
         }
         walk();
     }
     
     // person是Function的例項物件
     alert(typeof person);
      
     //person是一個方法,附屬於window
     person("Tom",18);
     
     // person是一個類
     var a = new person("Jerry",16);
     a.talk();
    
     //person是全域性變數,此處被重新賦值為字串
     person = "no function";

     alert(typeof person);

</script>

 

   4.2.3 函式的例項屬性和類屬性

    函式中的變數分為三種:

  • 區域性變數:在函式中用var宣告的變數
  • 例項屬性:在函式中以this字首修飾的變數
  • 類屬性:在函式中以函式名字首修飾的變數

 

   4.2.4 函式呼叫

       1. 直接呼叫函式

           呼叫者:函式附加的物件

          呼叫者.函式(引數...)

      2. 以call()方法呼叫

         函式.call(呼叫者, 引數...)

<script type="text/javascript">
    // 定義一個each函式
    var each = function(array , fn)
    {
        for(var index in array)
        {
            // 以window為呼叫者來呼叫fn函式,
            // index、array[index]是傳給fn函式的引數
            fn.call(null, index , array[index]);
        }
    }
    // 呼叫each函式,第一個引數是陣列,第二個引數是函式
    each([4, 20 , 3] , function(index , ele)
    {
        alert(this);
        document.write("第" + index + "個元素是:" + ele + "<br />");
    });
</script>

 call和apply的第一個引數是null/undefined時函式內的的this指向window或global    

     3.以apply()方法呼叫

      函式.apply(呼叫者,  [引數1, 引數2,... ])

 

 4.2.5 函式的獨立性

       雖然定義函式時,可以將函式定義為某個類、某個物件的方法(助於引用時標識該方法,個人理解),但函式是獨立的,不屬於其他的類或物件。

  •     樣例一
<script type="text/javascript">
    function Person(name)
    {
        this.name = name;

        this.info = function()
        {
            console.log("我的name是:" + this.name);
        }
    }
    var p = new Person("Tom");
    // 呼叫p物件的info方法
    p.info();
    var name = "win";
    // 以window物件作為呼叫者來呼叫p物件的info方法
    p.info.call(window);
</script>

執行結果

 

 

 

 

 

函式的呼叫者,只是指明瞭函式執行的環境(this),p.info() 呼叫者是p物件,其name屬性值為Tom;p.info.call(window) 呼叫者是window,其name屬性值為win

  •  樣例二
<script type="text/javascript">
    // 定義Dog函式,等同於定義了Dog類
    function Dog(name , age , bark)
    {
        // 將name、age、bark形參賦值給name、age、bark例項屬性
        this.name = name;
        this.age = age;
        this.bark = bark;
        // 使用內嵌函式為Dog例項定義方法
        this.info = function()
        {
            return this.name + "的年紀為:" + this.age
                + ",它的叫聲:" + this.bark;
        }
    }
    // 建立Dog的例項
    var dog = new Dog("旺財" , 3 , '汪汪,汪汪...');
    // 建立Cat函式,對應Cat類
    function Cat(name,age)
    {
        this.name = name;
        this.age = age;
    }
    // 建立Cat例項。
    var cat = new Cat("kitty" , 2);
    // 將dog例項的info方法分離出來,再通過call方法完呼叫info方法,
    // 此時以cat為呼叫者
    console.log(dog.info.call(cat));
</script>

執行結果

 

4.2.6 函式提升

函式提升的前提是該函式採用命名函式的形式定義函式

  • 樣例一(提升)
<script type="text/javascript">
	// 呼叫add函式
	console.log(add(2, 5));
	// 定義add函式(會發生函式提升)
	function add(a , b)
	{
		console.log("執行add函式");
		return a + b;
	}
</script>

 相當於

<script type="text/javascript">
    // 定義add函式
	function add(a , b)
	{
		console.log("執行add函式");
		return a + b;
	}
	// 呼叫add函式
	console.log(add(2, 5));
	
</script>

 

  • 樣例二(不提升)
<script type="text/javascript">
	// 呼叫add函式
	console.log(add(2, 5));  //error
	// 定義add函式,此時只提升add變數名,函式定義不會被提升
	var add = function(a , b)
	{
		console.log("執行add函式");
		return a + b;
	}
</script>

相當於

<script type="text/javascript">
        var add; 
	// 呼叫add函式
	console.log(add(2, 5));
	// 定義add函式,此時只提升add變數名,函式定義不會被提升
	add = function(a , b)
	{
		console.log("執行add函式");
		return a + b;
	}
</script>
  • 樣例三(提升)
<script type="text/javascript">
	function test(){
		// 呼叫add函式
		console.log(add(2, 5));
		// 定義add函式(會發生函式提升)
		function add(a , b)
		{
			console.log("執行add函式");
			return a + b;
		}
	}
	test();
</script>

相當於

<script type="text/javascript">
	function test(){
	    function add(a , b)
		    {
		    	console.log("執行add函式");
		    	return a + b;
		    }
		// 呼叫add函式
		console.log(add(2, 5));
	
	}
	test();
</script>
  • 樣例四(不提升)
<script type="text/javascript">
	function test(){
		// 呼叫add函式
		console.log(add(2, 5)); //error
		// 定義add函式,此時只提升add變數名,函式定義不會被提升
		var add = function(a , b)
		{
			console.log("執行add函式");
			return a + b;
		}
	}
	test();
</script>

相當於

<script type="text/javascript">
	function test(){
        var add;
		// 呼叫add函式
		console.log(add(2, 5)); //error
		// 定義add函式,此時只提升add變數名,函式定義不會被提升
		add = function(a , b)
		{
			console.log("執行add函式");
			return a + b;
		}
	}
	test();
</script>

4.2.7 變數與函式同名

 定義變數時賦值,不論在同名函式前還是後,都會覆蓋同名函式;定義變數時不賦值,不論在同名函式前還是後,同名函式都會覆蓋變數

<script type="text/javascript">
	function a(){
	}
	var a; // 定義變數,不指定初始值
	console.log(a);// 輸出a的函式體
	var b; // 定義變數,不指定初始值
	function b(){
	}
	console.log(b);// 輸出b的函式體
	var c = 1; // 定義變數,並指定初始值
	function c(){
	}
	console.log(c);// 輸出1
	function d(){
	}
	var d = 1; // 定義變數,並指定初始值
	console.log(d);// 輸出1
</script>

 

4.2.8 箭頭函式

箭頭函式相當於Lambda表示式,形如 (param1, param2, ... )  => { statements }

  • 只有一個形參時,可省略括號
  • 沒有形參時,不可省略括號
  • 只有一條語句時,可省略花括號
  • 只有一條語句,且是return語句時,可省略return
  • 箭頭函式不繫結arguments,所以箭頭函式的arguments總是引用當前上下文的arguments
<script type="text/javascript">
//var arguments = "Tom";
// 箭頭函式中arguments引用當前上下的arguments,即"Tom"字串
var arr = () => arguments;
console.log(arr()); // 輸出Tom
function foo()
{
	// 箭頭函式中arguments引用當前上下的arguments,
	// 此時arguments代表呼叫foo函式的引數
	var f = (i) => 'Hello,' + arguments[0];
	return f(2);
}
console.log(foo("Tom", "Jerry")); // 輸出Hello,Tom
</script>

對於普通函式

如果直接呼叫普通函式,函式中的this代表全域性物件(window);如果通過new呼叫函式建立物件,那麼函式中的this代表所建立的物件。

<script type="text/javascript">
   var f = function(){
       this.age = 100;

       console.log(this + this.age);
       window.age = 90;
       console.log(this + this.age);
   }
   f(); //直接呼叫函式f,則函式f中的this代表window
   new f();  //通過new建立物件使函式f得到呼叫,此時函式f中的this代表f物件
</script>

 

再看一個例子

<script type="text/javascript">
function Person() {
	// Person()作為構造器使用時,this代表該構造器建立的物件
	this.age = 0;
	setInterval(function growUp(){
		// 對於普通函式來說,直接執行該函式時,this代表全域性物件(window)
		// 因此下面的this不同於Person構造器中的this
		console.log(this === window);
		this.age++;
	}, 1000);
}
var p = new Person();
setInterval(function(){
	console.log(p.age); // 此處訪問p物件的age,將總是輸出0
}, 1000);
</script>

此處growUp方法裡的this是始終為window,區別於以下箭頭函式時。

 

對於箭頭函式

箭頭函式中的this總是代表包含箭頭函式的上下文

<script type="text/javascript">
function Person() {
	// Person()作為構造器使用時,this代表該構造器建立的物件
	this.age = 0;
	setInterval(() => {
		// 箭頭函式中this總代表包含箭頭函式的上下文。
		console.log(this === window);
		// 此處的this,將完全等同於Person構造器中的this
		this.age++;
	}, 1000);
}
var p = new Person();
setInterval(function(){
	console.log(p.age); // 此處訪問p物件的age,將總是輸出數值不斷加1
}, 1000);
</script>

值得注意的是,此處箭頭函式裡的this等同於Person構造器裡的this,此處Person構造器裡的this代表Person物件,故箭頭函式裡的this為Person物件

<script type="text/javascript">
    function Person() {
        // Person()作為構造器使用時,this代表該構造器建立的物件
        this.age = 0;
        setInterval(() => {
            // 箭頭函式中this總代表包含箭頭函式的上下文。
            console.log(this === window); //true
            // 此處的this,將完全等同於Person構造器中的this
            this.age++;
        }, 1000);
    }
    Person();
    setInterval(function(){
        console.log(window.age); // 此處訪問window物件的age,將總是輸出數值不斷加1
    }, 1000);
</script>

此時直接呼叫Person函式,導致Person函式裡的this代表window,也就是箭頭函式的上下文是window,所以箭頭函式的this就是window


 

5. 物件導向

   javascript函式定義不支援繼承語法,沒有完善的繼承機制,因此習慣上稱Javascript是基於物件的指令碼語言。所有的類是Object類的子類外,沒有其他父子繼承關係。

 

 5.1 prototype實現繼承

       javascript的prototype屬性代表了該類的原型物件,其是一Object物件,將javascript的prototye屬性設為父類例項,可實現javascript語言的繼承。

<script type="text/javascript">
	// 定義一個Person類
	function Person(name, age)
	{
		this.name = name;
		this.age = age;
	}
	// 使用prototype為Person類新增sayHello方法
	Person.prototype.sayHello = function()
	{
		console.log(this.name + "向您打招呼!");
	}
	var per = new Person("牛魔王", 22);  
	per.sayHello(); // 輸出:牛魔王向您打招呼!
	// 定義一個Student類
	function Student(grade){
		 this.grade = grade;
	}
	// 將Student的prototype設為Person物件
	Student.prototype = new Person("未命名" , 0);
	// 使用prototype為Student類新增intro方法
	Student.prototype.intro = function(){  
		console.log("%s是個學生,讀%d年級" , this.name, this.grade);
	}
	var stu = new Student(5);
	stu.name = "孫悟空";
	console.log(stu instanceof Student); // 輸出true
	console.log(stu instanceof Person); // 輸出true
	stu.sayHello(); // 輸出:孫悟空向您打招呼! 
	stu.intro(); //輸出:孫悟空是個學生,讀5年級
</script>

       Student的原型是Person物件,相當於設定Student繼承了Person,這樣Student類將會得到Person類的屬性和方法。Student物件既可呼叫Person的例項方法,也可呼叫Student的例項方法。

 

   5.2 構造器實現偽繼承

<script type="text/javascript">
	// 定義一個Person類
	function Person(name, age)
	{
		this.name = name;
		this.age = age;
		// 為Person類定義sayHello方法
		this.sayHello = function()
		{
			console.log(this.name + "向您打招呼!");
		}
	}
	var per = new Person("牛魔王", 22);
	per.sayHello(); // 輸出:牛魔王向您打招呼!
	// 定義Student類
	function Student(name, age, grade)
	{
		// 定義一個例項屬性引用Person類
		this.inherit_temp = Person;
		// 呼叫Person類的構造器
		this.inherit_temp(name, age);
		this.grade = grade;
	}
	// 使用prototype為Student類新增intro方法
	Student.prototype.intro = function(){  
		console.log("%s是個學生,讀%d年級" , this.name, this.grade);
	}
	var stu = new Student("孫悟空", 34, 5);
	console.log(stu instanceof Student); // 輸出true
	console.log(stu instanceof Person); // 偽繼承,所以輸出false
	stu.sayHello(); // 輸出:孫悟空向您打招呼!
	stu.intro(); //輸出:孫悟空是個學生,讀5年級
</script>

       第21行,以this為呼叫者,呼叫了Person的構造器,這樣Person構造器中的this就是Student。Student物件既可呼叫Person的例項方法,也可呼叫Student的例項方法。

   

     5.3 使用apply或call實現偽繼承

          這種方式和5.2相似

<script type="text/javascript">
	// 定義一個Person類
	function Person(name, age)
	{
		this.name = name;
		this.age = age;
		// 為Person類定義sayHello方法
		this.sayHello = function()
		{
			console.log(this.name + "向您打招呼!");
		}
	}
	var per = new Person("牛魔王", 22);
	per.sayHello(); // 輸出:牛魔王向您打招呼!
	// 定義Student類
	function Student(name, age, grade)
	{
		Person.call(this, name, age);
//		Person.apply(this, [name, age]);
		this.grade = grade;
	}
	// 使用prototype為Student類新增intro方法
	Student.prototype.intro = function(){  
		console.log("%s是個學生,讀%d年級" , this.name, this.grade);
	}
	var stu = new Student("孫悟空", 34, 5);
	console.log(stu instanceof Student); // 輸出true
	console.log(stu instanceof Person); // 偽繼承,所以輸出false
	stu.sayHello(); // 輸出:孫悟空向您打招呼!
	stu.intro(); //輸出:孫悟空是個學生,讀5年級
</script>

 

6. 建立物件

  • 使用new關鍵字呼叫構造器建立物件

          var p = new Person();

  • 使用Object類建立物件

         var obj = new Object();

  • 使用JSON語法建立物件

         var person = {

                 name:"Tom",

                age:20

        }

 

 

相關文章