for (var i=0; i<10; i++) {
var str = 'hi';
console.log(str);
}
等同于
var i = 0;
for (; i<10; i++) {
var str = 'hi';
console.log(str);
}
{
var x = 1;
}
等同于
var x = 1;
{
}
function foo() {
var a = 1;
console.log(a); //1
}
foo();
console.log(typeof a); //undefined
声明语句var
function foo() {
//隐式的将b定义为全局变量
var a = b = 1;
}
foo();
console.log(typeof a); //undefined
console.log(typeof b); //number
function foo() {
//同时定义多个变量的正确方式
var a =1,b = 1;
}
foo();
console.log(typeof a); //undefined
console.log(typeof b); //undefined
function add(a, b) {
var x = a;
var y = b;
return x + b;
}
函数表达式
//一般表达式
var add = function(a, b) {
}
//立即调用表达式
(function() {
})();
//返回表达式
return function() {
};
//命名函数表达式
var add = function foo(a, b) {
}
函数声明和函数表达式的区别
他们最重要的区别就是函数声明能够提前,而函数表达式不行
var num = add(1, 3);
//4
console.log(num);
function add(a, b) {
var x = a;
var y = b;
return x + b;
}
var num1 = add1(1, 3);
//add1 is not a function
console.log(num1);
var add1 = function(a, b) {
var x = a;
var y = b;
return x + b;
}
function foo(x, y) {
console.log(x, y, this);
}
//1,2,Number(100)
foo.call(100, 1, 2);
//3,4,Boolean(true)
foo.apply(true, [3, 4]);
//undefined,undefined,window
foo.apply(null);
//undefined,undefined,window
foo.apply(undefined);
function foo(x, y) {
'use strict';
console.log(x, y, this);
}
//undefined,undefined,null
foo.apply(null);
//undefined,undefined,undefined
foo.apply(undefined);
bind方法
this.x = 9;
var module = {
x: 33,
getX: function() {
return this.x;
}
};
console.log(module.getX()); //33
var gn = module.getX;
console.log(gn()); //9
var gn1 = gn.bind(module);
console.log(gn1()); //33
bind与currying
函数有柯里化(currying)的特性,意思函数能拆分成多个单元。
function add(a, b, c) {
return a + b + c;
}
var fn = add.bind(undefined, 100);
console.log(fn(1, 2)); //103
var fn1 = fn.bind(undefined, 200);
console.log(fn1(10)); //310
if(!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if(typeof this !== 'function') {
throw new TypeError('what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1);
var fToBind = this;
var fNOP = function() {};
var fBound = function() {
return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
以上代码有做了些修改,原始代码以及分析请看下图:
理解闭包
闭包的栗子
function outer() {
var localVal = 30;
return localVal;
}
console.log(outer());
function outer1() {
var localVal2 = 33;
return function() {
return localVal2;
}
}
var fn = outer1();
console.log(fn())
//全局变量
var a = 10;
(function() {
//局部变量
var b = 20;
})();
//10
console.log(a);
//undefined
console.log(b);
for(var item in { a: 1, b: 2 }) {
//a b
console.log(item);
}
//b
console.log(item);
eval('var c = 100');
//100
console.log(c);
作用域链
function outer1() {
var local1 = 11;
function inter() {
var local2 = 22;
//11
console.log(local1);
//22
console.log(local2);
//33
console.log(global1);
}
inter();
}
var global1 = 33;
outer1();
function outer2() {
var local3 = 44;
var fn = new Function('console.log(typeof local3);');
//undefined
fn();
}
outer2();
前言
该份资料的来源为慕课网教程《JavaScript深入浅出》,内容几乎是全文摘抄下来,不喜勿喷啊。
数据类型
JavaScript被称为是一种弱类型的语言,原因就是数据类型居然能够随意转换而不报错,而且在定义变量的时候不用指定其类型,示例代码如下:
面试题常问的:JavaScript中原始类型有哪几种? 答:number、string、boolean、null、undefined。
隐式转换
1、加号(+)和减号(-) 在数字与字符串做运算的时候,加号做拼接,减号就做减法
2、等于号(==) 等于号判断原始类型的时候会有自动类型转换的特点,在判断引用类型的时候会从引用地址上进行判断。
3、严格等于(===) 相比于等于号,严格等于不会进行类型转换,它会一开始判断两者之间的类型,如果类型不同,直接返回false。类型相同且内容相同才返回true。
包装对象
JavaScript是面向对象的语言,使用”.”操作符可以访问对象的属性和方法,而对于基本类型(null,undefined, bool, number, string)应该是值类型,没有属性和方法,然而
结果很简单,但是仔细想想还真奇怪,string不是值类型吗!怎么又有属性又有方法的!其实只要是引用了字符串的属性和方法,JavaScript就会将字符串值通过new String(s)的方式转为内置对象String,一旦引用结束,这个对象就会销毁。所以上面代码在使用的实际上是String对象的length属性和indexOf方法。
同样的道理,数字和布尔值的处理也类似。null和undefined没有对应对象。既然有对象生成,能不能这样
结果并没有返回10,而是undefined!不是说好了是个对象吗!正如刚才提到第二行代码只是创建了一个临时的String对象,随即销毁,第三行代码又会创建一个新的临时对象(这就是低版本IE频繁处理字符串效率低的一个原因),自然没有b属性,这个创建的临时对象就成为包装对象。
类型检测
在JavaScript中,有很多种检测数据的类型,主要是有以下几种
1、typeof:一般用于检测原始数据类型,引用数据类型无法具体的检测出来
其实null是js设计的一个败笔,早期准备更改null的类型为null,由于当时已经有大量网站使用了null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。
2、instanceof:检测引用数据类型
可以看到前三个都是以对象字面量创建的基本数据类型,但是却不是所属类的实例,这个就有点怪了。后面三个是引用数据类型,可以得到正确的结果。如果我们通过new关键字去创建基本数据类型,你会发现,这时就会输出true,如下:
3、constructor:似乎完全可以应对基本数据类型和引用数据类型,都能检测出数据类型
事实上并不是如此,来看看为什么:
声明了一个构造函数,并且把他的原型指向了Array的原型,所以这种情况下,constructor也显得力不从心了。
4、Object.prototype.toString:终极数据检测方式
表达式和运算符
表达式
概念 表达式是指能计算出值的任何可用程序单元,或者可以这么说:表达式是一种JavaScript短语,可以使JavaScript解释器用来产生一个值。
原始表达式
复合表达式 比如:10*20
数组和对象的初始化表达式 比如:[1,2]、{x:1,y:2}等这些。
函数表达式 比如:var fe = function(){}或者(functiong(){console.log('hello world');})()
属性访问表达式 比如:var o = {x:1},访问属性的方式有o.x或者o['x']
调用表达式 比如:funName()
对象创建表达式 比如:new Func(1,2)或者new Object
运算符
太多太基础啦,不多说,稍微提一下以下几个运算符
语句
block语句和var语句
block语句 块语句常用于组合0~N个语句,往往用一对花括号定义。
在ES6出来之前,JavaScript是没有块级作用域的,具体看以下两段代码:
声明语句var
try-catch语句
try跟catch搭配使用可以检测try里边的代码有没有抛出error,如果有error就会跳转到catch里执行catch里的程序。执行顺序为:先try捕获异常,执行catch里面的内容,最后执行finally里面的内容,当然也可以只写catch或者finally两个中的一个,但是必须写try语句块。
嵌套使用
由于在嵌套层中并没有catch语句,因此输出结果的顺序为:finally、outer、oops。下面请看含有catch语句的
以上代码输出结果的顺序为:inner、oops、finally。原因是异常已经在内部处理过了,因此不会再到外部去处理。
更复杂的嵌套
以上代码输出结果的顺序为:inner、oops、finally、outer、oops。原因在内部的catch语句重新向外抛出了ex这个异常。
for in语句
有以下的特点:1、顺序不确定;2、enumerable为false时不会出现;3、fon in对象属性时会受到原型链的影响
严格模式
这里有一篇非常好的总结,传送门
对象
概述
对象中包含一系列的属性,这些属性是无序的,每一个属性都有一个字符串key和对应的value
创建对象
创建对象方式1—字面量:
创建对象方式2—通过构造函数
创建对象方式3—Object.create
属性操作
属性读写
属性删除
属性检测
属性枚举
getter()和setter()方法
get/set与原型链
属性标签
序列化
数组
数组中的方法
将数组转为字符串
将数组逆序输出
将数组进行排序
将数组合并
返回部分数组
将数组进行拼接
将数组进行遍历
将数组进行映射
将数组进行过滤
将数组进行判断
将数组元素进行累加操作
将数组进行检索
判断是否为数组
数组 VS 对象
数组 VS 字符串
字符串是一种类数组
函数和作用域
函数概念
函数是一块JavaScript代码,被定义一次,但可以执行和调用多次。JavaScript中的函数也是对象,所以函数可以像其他对象那样操作和传递,所以我们也常叫JavaScript中的函数为函数对象。
函数调用方式
函数声音和函数表达式
函数声明
函数表达式
函数声明和函数表达式的区别 他们最重要的区别就是函数声明能够提前,而函数表达式不行
this的栗子
全局的this(浏览器)
一般函数中的this
作为对象方法中函数的this
对象原型链上的this
get/set方法与this
构造器中的this
call/apply方法与this
bind方法与this
函数属性arguments
apply/call方法(浏览器)
bind方法
bind与currying 函数有柯里化(currying)的特性,意思函数能拆分成多个单元。
柯里化的实际运用
bind与new
bind方法模拟
以上代码有做了些修改,原始代码以及分析请看下图:
理解闭包
闭包的栗子
闭包概念 在计算机科学中,闭包(也成为词法闭包或者函数闭包)是指一个函数或者函数的引用,与一个引用环境绑定在一起,这个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表。
闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。
闭包特性
作用域
全局作用域、函数作用域和eval
作用域链
执行上下文
这个玩意太抽象了,看完视频对这个概念还是十分模糊,还是来这看一下比较容易理解的文章——王福朋深入理解JavaScript系列
OOP知识点
概念与继承
面向对象程序设计是一种程序设计规范,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
看了课程的相关知识点,发现远远没有下面几篇博文说的这么简单易懂与透彻,在这就不整理课程的内容了,一起来看看以下三个博客中内容: 冴羽博客JavaScript系列 汤姆大叔深入理解JavaScript系列 王福朋深入理解JavaScript系列
JavaScript正则表达式
这节课的内容也不摘抄了,因为之前做过这方面的总结,再继续总结一次我就认为是得不偿失了。 JavaScript正则表达式
参考资料
1、博客园小火柴的前端学习之路 2、冴羽博客JavaScript系列 3、汤姆大叔深入理解JavaScript系列 4、JavaScript包装对象 5、JavaScript检测数据类型四种方法 6、JavaScript中的new到底做了些什么 7、王福朋深入理解JavaScript系列 8、JavaScript正则表达式