JavaScript 语法笔记

目录

 

 

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

        }

猜你喜欢

转载自blog.csdn.net/int__double/article/details/81909109