ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Stanford CS142: Web Applications Week2 JavaScript

2022-06-22 15:04:48  阅读:251  来源: 互联网

标签:function Web fileNo 函数 Stanford JavaScript let var console


目录

基本语法

变量的作用域

变量有两种作用域:全局范围和函数内部范围

var globalVar;
function foo() {
  /* 在这个位置也能输出localVar2,不过得到的结果会是undefined */
  var localVar;
  if (globalVar > 0) {
    varl localVar2 = 2;
  }
  /* localVar2在这里使用就是不合法的了 */
}

变量的语句也可以在变量声明之前使用(变量提升),但是不推荐。

/* 下面这两个代码是等价的 */
function foo() {
	var x;
  x = 2;
}

function foo() {
  x = 2;
  var x;
}

注意事项

  1. 慎用全局变量

  2. 变量提升在局部变量使用时会引起混乱,比如在赋值前就访问了变量

  3. 建议在函数开始时声明所有的变量

  4. 检查相等和不相等的是===!==,而不是==!=

  5. 最新的JavaScript标准ES6中引入了非提升的变量声明:letconst,某些环境下直接禁用var声明的方式

    console.log('Val is:', val); /* 输出undifined */
    ...
    for (var i = 0; i < 10; i++) {
      var val = 'different string'; /* 变量在函数之前提升 */
    }
    
    /* --------------------------------------------------- */
    console.log('Val is:', val); /* 语法错误 */
    ...
    for (var i = 0; i < 10; i++) {
      let val = 'different string';
    }
    

数字

数字类型(number type)都是以浮点数的形式表示,对应的是C语言中的double\(\text{MAX\_INT}=(2^{53}-1)=9007199254740991\)。

一些特殊值也属于数字类型,有:NaN, Infinity

由于是浮点数,所以会有浮点数的坑,比如(0.1+0.2)==0.3是false

但是对于位运算,结果确实32位的数字

字符串

字符串都是可变长度的,.length属性返回字符串的长度。

字符串之间可以用+来拼接。

除此之外,字符串还有许多有用的方法:

indexof(), charAt(), match(), search(), replace(), toUpperCase(), toLower(), slice(), substr(), ...

布尔值

布尔值只有两种情况:true false

JS中将值分为truthyfalsy,其中falsy值有: false 0 NaN "" undefined null除此之外,其余都是truthy

undefined和null

undefined是指变量还没有赋值的状态

null是指希望返回一个值,但是无法返回正确的值的结果

要注意null和undefined二者并不相等

函数

函数是可以提升的,也就是说可以先调用函数,再在后面定义。

函数可以返回多种类型,任何函数都会返回一个值,默认值是undefined

样例:

let aFuncVar = function (x) {
	console.log('Func called with', x);
	return x+1;
};
myFunc(aFuncVar);
function myFunc(routine) { // passed as a param
	console.log('Called with', routine.toString());
	let retVal = routine(10);
	console.log('retVal', retVal);
	return retVal;
}

输出结果:

Called with function (x) {
	console.log('Called with', x);
	return x+1;
}
Func called with 10
retVal 11

Object类型

JavaScript JSON (w3school.com.cn)

Object类型是value:key组成的称为对象(property)的无序集合

let foo = {};
let bar = {name: "Alice", age: 23, state: "California"};

其中name必须得是字符串,值可以是任何类型

访问:

  • bar.namebar["name"]
  • foo.nonExisent==undefined

属性是可以后续添加的,比如:

let foo = {};
foo.name = "Fred";

属性也可以后续删除:

left foo = { name: "Fred" };
delete foo.name; /* foo现在为空 */

列举使用的keys:

Object.keys({name: "Alice", age: 23}) = ["name", "age"]

数组

let anArr = [1,2,3];

数组的类型是object,所以有typeof anArr == 'object'

一个数组里能存放多种不同的类型。

数组有的方法:length push pop shift unshift sort reverse splice filter

  • length 返回数组的长度

  • push 在数组最后插入一个值,并返回下标

  • pop删除数组最后一个值,并返回删除的值

  • shift删除首元素,然后将数组的所有元素左移

  • unshift在数组头部插入新元素

  • sort数组排序

  • reverse数组翻转

  • splice(a, b, ...)在数组中添加a个新元素,删除b个元素,后面参数是添加的新元素

  • concat将两个数组合并后创建一个新数组

  • filter传入一个检查函数,将满足检查条件的元素组成一个新数组返回ß

日期

let date = new Date();

日期的类型是object,有typeof date == 'object'

日期类型的原始数据是UNIX时间戳

方法:

  • valueOf()返回时间戳
  • toISOString()以ISO时间格式返回日期2016-01-09T17:08:36.314Z
  • toLocalString()返回类似1/9/2016, 9:08:36 AM格式的日期

正则表达式

let re = /ab+c/let re2=new RegExp("ab+c")

字符串处理:

String: search(), match(), replace(), split()
RegExp: exec(), test()

/re/.test(str)检查字符串str中是否有匹配re的内容,返回trueorfalse

str.search(re)返回字符串str中匹配re的子串的开头的下标,若不存在返回-1

re.exec(str)返回str中匹配re的信息,自动往后匹配,直到返回null

str.match(re)以数组的形式返回str中所有匹配re的子串

str.replace(re, s)str中匹配re的子串用s来替换

异常

try {
  notExistentFunction();
  throw "Help!";
} catch (errstr) { // errstr === "Help!"
	console.log('Got exception', errstr);
} finally {
	// This block is executed after try/catch
}

在Web页面中使用JavaScript

  • 嵌入单独的.js文件

    <script type="text/javascript" src="code.js"></script>
    
  • 在HTML文件中嵌入

    <script type="text/javascript">
    //<![CDATA[
    Javascript goes here...
    //]]>
    </script>
    

JavaScript的面向对象

定义类

let obj = {count: 0};
obj.increment = function (amount) { 
	this.count += amount;
	return this.count;
}

上面的代码定义了一个类obj,该类有一个字段count,默认值为0;还有一个叫做increment的方法。

this

对于一个类的方法,this会绑定给该对象

let o = {oldProp: 'this is an old property'};
o.aMethod = function() { 
	this.newProp = "this is a new property";
	return Object.keys(this); // will contain 'newProp'
}
o.aMethod(); // will return ['oldProp','aMethod','newProp']

对于函数(不是类中的方法):

  • this会绑定到全局的object对象
  • 或者,如果使用了use strictthis会是undefined

函数

函数的属性

函数也可以定义自己的属性,详情见下面的代码:

function plus1(value) {
	if (plus1.invocations == undefined) {
		plus1.invocations = 0;
	}
	plus1.invocations++;
	return value + 1;
}
  • plus1.invocations在上段代码中,代表的含义就是函数调用的次数
  • 函数的属性表现上类似于面向对象中的静态字段、类字段,或静态变量

函数的方法

函数也是一种对象,函数默认内置了一下的方法:

function func(arg) { console.log(this,arg); }
  • toString()返回函数的代码,上面的样例中,返回的结果会是function func(arg) { console.log(this,arg); }
  • call(this, args)指定this和传入的参数来调用该函数
  • bind(this, args)返回一个this和传入的参数绑定后的新函数

绑定时,对于预留的参数可以用undefined来预留,当调用新生成的函数时,会根据没有绑定的参数依次填入传入的值。

面向对象编程

在JavaScript中,函数就是类(class),例如定义一个Rectangle类:

function Rectangle(width, height) {
  this.width = width;
  this.height = height;
  this.area = function() { return this.width*this.height; }
}
let r = new Rectangle(26, 14); // {width: 26, height: 14}
console.log(r) 
/* Rectangle { width: 26, height: 14, area: [Function] } */

用这种方式构造的函数也被称作生成器(constructor)`r.constructor.name == 'Rectangle'

JavaScript中每个对象都有一个对象原型(prototy)的概念。每个对象都有自己的原型,从而构成一个长链。

graph LR A(("Obj")) B(("Proto")) C(("Proto")) D(("null")) A====>B-...->C====>D

访问JavaScript的一个对象时,当一个对象的属性不存在时,继续向它的原型搜索,直到返回null

但是在修改对象的一个属性时,如果当前对象不包含该属性,那么就直接创建这个属性,不会搜寻原型。

下面是一个使用原型的例子:

function Rectangle(width, height) {
	this.width = width;
	this.height = height;
}
Rectangle.prototype.area = function() { 
	return this.width*this.height; 
}
let r = new Rectangle(26, 14); // {width: 26, height: 14}
let v = r.area(); // v == 26*14
Object.keys(r) == [ 'width', 'height' ] // own properties

改变对象的原型会引起所有实例的改变

原型与对象实例

假设我们有一个实例let r = new Rectangle(26, 14)要对线面

r.newMethod = function() { console.log('New Method called'); }
Rectangle.prototype.newMethod = 
		function() { console.log('New Method called'); }

继承

JavaScript的继承是面向原型的继承,支持单一继承和动态创建与修改。

所以原型赋值可以看作是在指定父类。

ECMAScript6的新内容

class Rectangle extends Shape { // 定义类和继承Shape
	constructor(height, width) {
		super(height, width);
		this.height = height;
		this.width = width;
	}
	area() { // 定义方法
		return this.width * this.height;
	}
	static countRects() { // 定义静态方法
		...
	}
}

函数式编程

JavaScript函数式编程的主要应用是匿名函数和lambda表达式。

下面的三个代码都是等价的:

/* code1 */
for (let i = 0; i < anArr.length; i++) { 
	newArr[i] = anArr[i]*i;
}
/* code2 匿名函数 */
newArr = anArr.map(function (val, ind) { 
	return val*ind;
});

/* code3 lambda expression */
newArr = anArr.map((val, ind) => val*ind);

闭包

闭包(closure)在编程语言中是一种比较高级的概念

let globalVar = 1;
function localFunc(argVar) { 
 let localVar = 0;
 function embedFunc() {return ++localVar + argVar + globalVar;}
 return embedFunc;
}
let myFunc = localFunc(10);

myFunc闭包包含argVar, localVar和globalVar

闭包常用于在类中实现私有字段,例如:

let myObj = (function() { 
 let privateProp1 = 1; let privateProp2 = "test"; 
 let setPrivate1 = function(val1) { privateProp1 = val1;}
 let compute = function() {return privateProp1 + privateProp2;}
 return {compute: compute, setPrivate1: setPrivate1};
})();
typeof myObj; // 'object'
Object.keys(myObj); // [ 'compute', 'setPrivate1' ]
myObj.compute(); // return '1test'

我们需要注意在嵌入函数中使用this

'use strict';
function readFileMethod() {
	fs.readFile(this.fileName, function (err, data) {
		if (!err) { 
			console.log(this.fileName, 'has length', data.length);
		}
	});
}
let obj = {fileName: "aFile"; readFile: readFileMethod};
obj.readFile();

这段代码会产生错误,因为this的值时undefined,因为readFile只是一个函数,并不是一个方法。

闭包在命令式的代码中也会产生棘手的问题:

// Read files './file0' and './file1' and return their length
for (let fileNo = 0; fileNo < 2; fileNo++) {
	fs.readFile('./file' + fileNo, function (err, data) {
		if (!err) { 
			console.log('file', fileNo, 'has length', data.length);
		}
	});
}

程序的运行结果是输出两个flie 2 has length,这是为什么呢?

在执行fs.readFile时,有两个参数,当一个参数是字符串,代表读取文件的名字,第二个参数是一个函数,当fs.readFile结束之后,回调这个函数。

fs.readFile执行后,回调函数执行前,fileNo++;当执行回调函数的时候,闭包内的fileNo变成了2,所以最终的运行结果是输出两次2。

当我们把代码修改成下面的形式时:

for (let fileNo = 0; fileNo < 2; fileNo++) {
	var localFileNo = fileNo;
	fs.readFile('./file' + localFileNo, function (err, data) {
		if (!err) { 
			console.log('file', localFileNo,'has length',data.length);
		}
	});
}

输出的localFileNo会一直是1。

我们换一种思路来解决——用调用的方式为fileNo制作一个私有副本:

function printFileLength(aFileNo) {
	fs.readFile('./file' + aFileNo, function (err, data) {
		if (!err) { 
			console.log('file', aFileNo, 'has length', data.length);
		}
	});
}

for (let fileNo = 0; fileNo < 2; fileNo++) {
	printFileLength(fileNo);
}

另一个思路——用let来制作fileNo的私有拷贝。

for (let fileNo = 0; fileNo < 2; fileNo++) {
  let localFileNo = fileNo;
	fs.readFile('./file' + localFileNo, function (err, data) {
		if (!err) { 
			console.log('file', localFileNo, 'has length', data.length);
		}
	});
}

但是这两种方式都会有有时出现输出乱序的问题。

JSON

JavaScript JSON | 菜鸟教程 (runoob.com)

JSON的一些方法:

  • JSON.stringify(obj):以字符串的形式返回obj的内容
  • JSON.parse(s)

JavaScript的一些新特性

导入全局变量

/* old */
var exportedName = 
  (function () {
    var x, y, x;
     ...
    return {x: x, y: y};
})();

/* new */
var x, y, x;
...
var exportedName = { x: x, y: y };
export exportedName;

默认值

/* old */
function myFunc(a, b) {
  a = a || 1;
  b = b || "Hello";
}

/* new */
function myFunc(a = 1, b = "Hello") {
  
}

其他参数

/* old */
function myFunc() {
  var a = args[0];
  var b = args[1];
  var c = args[2];
  ...
}

/* new */
function myFunc(a, b, ...theArgsArray) {
  var c = theArgsArray[0];
}

模板字符串

/* old */
function formatGreetings(name, age) { 
	var str = 
	"Hi " + name + 
	" your age is " + age;
/* new */
function formatGreetings(name, age) { 
	let str = 
	`Hi ${name} your age is ${age}`;

For of

var a = [5, 6, 7]
/* old */
for (var i = 0; i < a.length; i++) {
  console.log(a[i]);
}

/* new */
for (ent of a) {
  console.log(ent);
}

数组、字符串、集合、哈希表都可以使用

自判断链

obj?.prop /* 如果obj是undefined或者null就返回undefined 否则返回obj.prop */

BigInt

BigInt - JavaScript | MDN (mozilla.org)

标签:function,Web,fileNo,函数,Stanford,JavaScript,let,var,console
来源: https://www.cnblogs.com/FrankOu/p/16400581.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有