小飘不懂JS冒险记(—)

你不懂JS 1入门与进阶笔记

代码

一个程序,经常被称为 源代码 或者只是 代码,是一组告诉计算机要执行什么任务的特殊指令。

语句

一组单词,数字,和执行一种具体任务的操作符构成了一个 语句。

字面量: 比如2,它没有被存入一个变量,是独立的。
在源代码中直接包含的值称为字面量。 string 字面量被双引号"…"或单引号‘…’包围——唯一的区别是风格上的偏好
number 和 boolean 字⾯量⽤它们本身来表示(即, 42 , true ,等等)。

a = b *2;

  • 2 是⼀个 字⾯量表达式
  • b 是⼀个 变量表达式,它意味着取出它的当前值
  • b * 2 是⼀个 算数表达式,它意味着执⾏乘法
  • a = b * 2 是⼀个 赋值表达式,它意味着将表达式 b * 2 的结果赋值给变量 a

JavaScript引擎实际上在即时地 编译 程序然后⽴即运⾏编译好的代码
解释:将你编写的代码翻译为计算机可以理解的命令;
编译:翻译是提前完成的,成为代码的 编译。

a = 21; 
b = a * 2; 
console.log( b );

log( b ) 部分被称为⼀个函数调⽤,console. 部分是⼀个对象引⽤。

一个获取输⼊的简单的⽅法,使⽤ prompt(…) 函数:

age = prompt( "Please tell me your age:" ); 
console.log( age );

“Please tell me your age:” —— 被打印在弹出框中。

操作符

注意:42 -> a 在JavaScript中是不合法的。

  • 对象属性访问:⽐如 console.log() 的 .
  • 等价性: == (宽松等价), === (严格等价), != (宽松不等 价), !== (严格不等价)
  • ⽐较: < (⼩于), > (⼤于), <= (⼩于或宽松等价), >= (⼤于或宽松 等价)
  • 逻辑: && (与), || (或)

等价性

注意:== 在允许强制转换的条 件下检查的等价性,⽽ === 是在**不允许强制转换的条件下检查的等价性

何时使用===(严格等价):

  • ⼀个⽐较的两个值之⼀可能是 true 或 false 值
  • ⽐较的两个值之⼀可能是这些具体的值( 0 , “” ,或 [] —— 空数组)

array 默认情况下会通过使⽤逗号( , )连接所有值来被强制转换 为 string

var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";

a == c ;   //true
a == b ;   //false 

不等价性

  • string 值也可进⾏不等价性⽐较,它使⽤典型的字⺟顺序规则(也就是像字典中字⺟的排 列顺序),( “bar” < “foo” )。
  • 如果两个值之⼀不是 string ,就像 a < b ,那么两个值就将被强制转换成 number ,并进⾏⼀般的数字⽐较。

类型间的转换

强制转换:你有⼀个 number 但需要将它打印在屏幕上,那么你就需要将这个值转换为⼀ 个 string。

> var a = "42";
> var b = Number(a);
> console.log(a);       //  "42"
> console.log(b);       //   42

使用Number(…) (一个内建函数)是一种从任意其他类型到number类型的 明确的 强制转换。

内建类型:

  • string
  • number
  • boolean
  • null和undefined
  • object
  • symbol(ES6新增类型)

**typeof:**它可以检查⼀个值并告诉你它的类型是什么。

var a;
typeof a;   // "undefined"

a = "hello world";
typeof a;   // "string",不是string

a = null;
typeof a;    // "object" ——奇怪的bug

内建类型的方法:

var a = "hello world";
var b = 3.1415926;
a.length;          //11
a.toUpperCase();   //"HELLO WORLD"
b.toFixed(4);      // "3.1416"

⼀个 string 值可以被包装为⼀个 String 对象,⼀个 number 可以被包装为⼀ 个 Number 对象,⽽⼀个 boolean 可以被包装为⼀个 Boolean 对象。等等。

隐含的 强制转换:“99.99” == 99.99 ⽐较,,JavaScript会将左 ⼿边的 “99.99” 转换为它的 number 等价物 99.99 。

Truthy 与 Falsy 当⼀个⾮ boolean 值被强 制转换为⼀个 boolean 时,它是变成 true 还是 false ??

在在JavaScript中“falsy”的明确列表如下:

  • "" (空字符串)
  • 0,-0,NaN (非法的number)
  • null,undefined
  • false

任何不在这个“falsy”列表中的值都是“truthy”,例如:

  • {},{a:42} (对象)
  • [],[“1”,“2”] (数组)
  • function foo(){…} (函数)

变量

  • 静态类型( 类型强制):防止了意外的类型转换。声明⼀个变量**(容器)**来持有特定类型的值,比如number 和 string 。

  • 弱类型(动态类型):在上强调类型而非变量上,允许变量在任意时刻持有任意类型的值。
    注意:JavaScript 中使用的是弱类型,这意味着 变量可以持有任意 类型 的值 而没有任何 类型 强制约束。
    比如:

var  amount = 1;
console.log(amount);        //  1
amount = "$" + String(amount);
console.log(amount);         //  "$1”
  • 变量的另⼀种常⻅⽤法是将值的设定集中化:一般用于当你为⼀个在程序中通篇不打算改变的 值声明了⼀个变量时,它更⼀般地被称为 常量。

根据惯例,⽤做常量的JavaScript变量通常是⼤写 的,在多个单词之间使⽤下划线 _ 连接。、
比如:

var TAX_RATE = 0.08;

toFixed(…) 是⼀个可以在值 number 上被访问的函数:toFixed(…) 让我们指明四舍五⼊到⼩数点后多少位,并且返回一个string

注意:ES6 引入了一个常量声明的新方法,用 const 代替 var 。

 //  在ES6中
 const TAX_RATE = 0.08;

如果你试着在第⼀个声明之后给 TAX_RATE 赋予⼀个不同的值,你的程序将会拒绝这个改变(⽽且在Strict模式下,会产⽣⼀个错误)。

块儿

在代码中我们经常需要将⼀系列语句⼀起分为⼀组。在JavaScript中,⼀个块⼉被定义为包围在⼀个⼤括号 { … } 中的⼀个或多个语句。
注意:⼀个块⼉语句与不需要分号( ; )来终结它。

ES6允许你使⽤ let 关键字声明属于个别块⼉。

function foo(){
	var a = 1;
	if(a>=1){
		let b = 2;
		while(b<5){
			let c = b*2;
			b++;
			console.log(a+c);
		}
	}
}

let并非var,b将仅属于if语句而不属于整个foo()函数的作用域,c将仅属于while循环。

循环

⼀个循环包含测试条件和⼀个块⼉(通常是 { … } )。
每次循环块⼉执⾏,都称为 ⼀次 迭代
记得使⽤JavaScript的 break 语句来停⽌⼀个循环,否则会极其容易地创造⼀个永远运⾏的循环。

函数

一个函数一般来说是一段被命名的代码,它可以使用名称来被”调用“,而每次调用它内部的代码就会运行。

function printAmount(){
	console.log(amount.toFixed(2);
}
var amount = 99.99;
printAmount();       //"99.99" ,注意是一个string类型
amount = amount * 2;
printAmount();       // "199.98"

函数可以选择性地接收参数值(也就是参数)—— 你传⼊的值,还可以选择性地返回一个值。

const TAX_RATE = 0.08;
function calculateFinalPurchaseAmount(amt) { 
// 计算带有税费的新费⽤ 
amt = amt + (amt * TAX_RATE);
// 返回新费⽤
return amt;
} 
var amount = 99.99; 
amount = calculateFinalPurchaseAmount( amount ); 
console.log( amount.toFixed( 2 ) );  // "107.99"

作用域

作⽤域基本上就是变量的集合,也是如何使⽤名称 访问这些变量的规则

注意:

  • 同⼀个作⽤域内变量名必须是唯⼀的 —— 不能有两个不同的变量 a 并排出现。
  • 一个作⽤域可以嵌套在另⼀个作⽤域中。
  • 在⼀个作⽤域中的代码既可以访问这个作⽤域中的变量,⼜可以访问任何在它外⾯的作⽤域的变量。

函数作用域

提升

无论var 出现在一个作用域内部的何处,这个声明都被认为是属于整个作用域的,而且
在作用域何处都可以访问它。

var a = 2;
foo();                   // 可以工作,因为 *'foo()'*声明被 "提升" 了
function foo(){
	a = 3;
	console.log(a);       //3
	var a;
}

嵌套的作用域

当你声明了⼀个变量时,它就在这个作⽤域内的任何地⽅都是可⽤的,包括任何下层/内部作用域。注意:下层不可用上层的。

function foo(){
	var a = 1;
	function bar(){
		var b = 2;
	}
	bar();
	console.log(a);   //1
}

b在foo()内部是不可用的,因为它是仅在内部的 bar() 作⽤域中被声明的。

如果你试着在⼀个作⽤域内访问⼀个不可⽤的变量的值,你就会得到⼀个被抛出 的 ReferenceError
如果你试着为⼀个还没有被声明的变量赋值,那么根据“strict模 式”的状态,你会要么得到⼀个在顶层全局作⽤域中创建的变量,要么得到 ⼀个错误。 非常差劲的做法

对象

object是一种复合值,在object中设置的属性持有各自类型的值。
比如:

var obj = {
	a:"hello world",
	b:42,
	c:true
};
obj.a;         // "hello world"
obj.b;         // 42
obj.c;         // true

obj["a"];      // "hello world"
obj["b"];      // 42
obj["c"];      // true

点号标记法: obj.a

方括号标记法: obj[“a”]

  • 当名称中含有特殊字符的属性名称,方括号标记法就很有用,比如:obj[“hello world”]
  • 当通过方括号标记法时,这样的属性通常称为
  • [ ]标记法要求有一个变量或者一个string字面量

数组

是一个object,是使⽤数字索引的位置 ,typeof 返回 “object”

函数

也是一个object,typeof 返回 “function”

function foo(){
	return 42;
}
foo.bar = "hello world";
typeof foo;     //"function"
typeof foo();     //  "number"
typeof foo.bar;    //"string"

typeof 返回 “function” ,这暗示 着 “function” 是⼀种主要类型 —— 因此也可以拥有属性,但是你⼀般仅会在有限情 况下才使⽤函数对象属性(⽐如 foo.bar )。

函数作为值

⼀个函数本身可以是⼀个值,它能够赋值给变量,传递给其他函数,或者从其它函数中返回。
匿名函数表达式:

var foo = function(){
	//...
};

命名函数表达式: (更理想)

var foo = function bar(){
	//...
};

变量

⼀个标识符必须以 a - z , A - Z , $ ,或 _ 开头。它可以包含任意这些字符外加数字 0 - 9 。

Strict模式

ES5在语⾔中加⼊了⼀个“strict模式”,它收紧了⼀些特定⾏为的规则。这些限制被视为使代码符合⼀组更安全和更合理的指导⽅针。

不允许因为省略了 var ⽽进⾏隐含的⾃动全局变量声明。

根据你摆放strict模式注解的位置,你可以为⼀个单独的函数,或者是整个⼀个⽂件切 换到strict模式:

function foo(){
	"uesr strict";
	//这部分代码是strict模式
	function bar(){
	}
}
//这部分代码不是strict模式
"user strict";
function foo(){
	//这部分代码是strict模式
}
//这部分代码是strict模式

立即被调用的函数表达式(IIFE)

var a = 42;
(function IIFE(){
	var a = 10;
	console.log(a);    //10
})();
console.log(a);        //42

在IIFE中的变量将不会影响围绕在IIFE外面的代码。

IIFE还可以有返回值:

var x = (function IIFE(){ 
	return 42;
})(); 
x;   // 42

闭包

即使函数已经完成了运行,它依然可以“记住”并持续访问函数的作用域。

function makeAdder(x) { 
// 参数 `x` 是⼀个内部变量
// 内部函数 `add()` 使⽤ `x`,所以它对 `x` 拥有⼀个“闭包”
function add(y) {
	return y + x;
}; 
	return add;
}
// `plusOne` 得到⼀个指向内部函数 `add(..)` 的引⽤,
// `add()` 函数拥有对外部 `makeAdder(..)` 的参数 `x`的闭包 
var plusOne = makeAdder( 1 );
var plusTen = makeAdder( 10 );

plusOne( 3 );   // 4 <-- 1 + 3
plusOne( 41 );  // 42 <-- 1 + 41
plusTen( 13 );  // 23 <-- 10 + 13

模块

模块让你定义对外⾯世界不可⻅的 私有实现细节(变量,函数),和对外⾯可访问公有API

function User(){
	var username,password;
	
	function doLogin(user,pw){
		username = uesr;
		password = pw;
		// 做登陆的工作
	}

	var publicAPI = {
		login:doLogin
	};
	return publicAPI;
}
  // 创建一个 ‘ User’ 对象
  var fred = User();
  fred.login("fred","123456!!");

**私有细节:**变量 username 和 password ,以及以及内部 doLogin() 函数。

警告: 我们在这⾥没有调⽤ new User() 。 User() 只是⼀个函数,不是⼀个要被初始化对象,所以它只是被⼀般地调⽤了。

this标识符

如果⼀个函数在它内部拥有⼀个 this 引⽤,那么这个 this 引⽤通常指向⼀ 个 object

this 关键字是根据函数如何被执⾏⽽动态绑定的。

注意:this 不是 指函数本身。
this 关键字不指代它所出现 的函数。

function foo(){
	console.log(this.bar);
}

var bar = "global";

var obj1 = {
	bar:"obj1",
	foo:foo;
};

var obj2 = {
	bar:"obj2"
};

foo();           //"global"
obj1.foo();      //"obj1"
foo.call(obj2);  //"obj2"
new foo();       // undefined

关于 this 如何被设置有四个规则,它们被展示在这个代码段的最后四⾏中:
1.foo() 最终在⾮strict模式中将 this 设置为全局对象 —— 在strict模式 中, this 将会是 undefined ⽽且你会在访问 bar 属性时得到⼀个错误 —— 所 以 this.bar 的值是 global 。
2. obj1.foo() 将 this 设置为对象 obj1 。
3. foo.call(obj2) 将 this 设置为对象 obj2 。
4. new foo() 将 this 设置为⼀个新的空对象。

原型

可以认为它⼏乎是在属性缺失时的备⽤对象
从⼀个对象到它备⽤对象的内部原型引⽤链接***发⽣在这个对象被创建的时候***。说明它 的最简单的⽅法是使⽤称为 Object.create(…) 的内建⼯具

var foo = {
	a:42;
};

//创建‘bar’ 并将它连接到 ‘foo’
var bar = Object.creat(foo);

bar.b = "hello world";
bar.b;    //"hello world"
bar.a;    // 42 <-- 委托到 `foo`

填补和转译(将新的JavaScript特性“带到”⽼版本的浏览器中)

填补

例如,ES6定义了⼀个称为 Number.isNaN(…) 的⼯具,来为检查 NaN 值提供⼀种准确 ⽆误的⽅法,同时废弃原来的 isNaN(…) ⼯具。这个⼯具可以很容易填补,因此你可 开始在你的代码中使⽤它,⽽不管最终⽤户是否在⼀个ES6浏览器中。

if (!Number.isNaN) { 
Number.isNaN = function isNaN(x) { 
	return x !== x;
	}; 
}

if 语句决定着在这个⼯具已经存在的ES6环境中不再进⾏填补。如果它还不存在, 我们就定义 Number.isNaN(…) 。

转译

使⽤⼀个⼯具将你的新版本代码转换为等价的⽼版本代码,一般没有任何办法可以填补语⾔中新增加的语法。

转译器

  • Babel :将 ES6+ 转译为 ES5
  • Traceur:将 ES6,ES7,和以后特性转译为 ES5

非JavaScript

你将会遇到的最常⻅的⾮JavaScript程序是DOM API。例如:

var el = document.getElementById( "foo" );

变量doucument作为一个全局变量存在,它是⼀种特殊的 object ,经常 被称为**“宿主对象”**。

发布了4 篇原创文章 · 获赞 3 · 访问量 91

猜你喜欢

转载自blog.csdn.net/fAng_ER_/article/details/101604038
今日推荐