js 基础

js 的作用域

var scope = 'global'; 
 
var f = function() {
	console.log(scope);// 输出 undefined
	var scope = 'f';
}
f();

上面代码和预想的不一样,没有输出 global,而是undefined,这是为什么呢? 这是 JavaScript 的一个特性,按照作用域搜索顺序,在 console.log 函数访问 scope 变 量时,JavaScript 会先搜索函数 f 的作用域,恰巧在 f 作用域里面搜索到 scope 变量, 所以上层作用域中定义的 scope 就被屏蔽了,但执行到 console.log 语句时,scope 还 没被定义,或者说初始化,所以得到的就是 undefined 值了。

我们还可以从另一个角度来理解:对于开发者来说,在访问未定义的变量或定义了但没 有初始化的变量时,获得的值都是 undefined。于是我们可以认为,无论在函数内什么地 方定义的变量,在一进入函数时就被定义了,但直到 var 所在的那一行它才被初始化,所 以在这之前引用到的都是 undefined 值。(事实上,JavaScript 的内部实现并不是这样,未 定义变量和值为 undefined 的变量还是有区别的。)

闭包

闭包的严格定义是“由函数(环境)及其封闭的自由变量组成的集合体”。通俗地讲,JavaScript 中每个的函数都是一个闭包,但通常意义上嵌套的函数更能够体现出闭包的特性。

let generateClosure = function(){
	let count = 0
	let get = function(){
		count++
		return count
	}
	return get
}
var counter = generateClosure()
console.log(counter())
console.log(counter())
console.log(counter())

理解:闭包是能够读取其他函数内部变量的函数
实现:定义在一个函数内部的函数
用途:

  • 可以读取函数内部的变量
  • 让这些变量的值始终保持在内存中

缺点:

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

对象

JavaScript 中的对象实际上就是一个由属性组成的关联数组,属性由名称和值组成,值 的类型可以是任何数据类型,或者函数和其他对象。

创建对象

// 方法一
var foo = {}
// 方法二: 显式地创建一个对象
var foo = new Object()
// 使用对象初始化器创建对象 
var foo = {
	'prop1': 'bar'
}

创建对象(new Object/ {})的区别

前者是用构造函数实例化对象,后者是直接创建JSON对象,后者的初始化比较方便,可以在初始化的时候同时赋值。

添加属性

// 方法一:点运算符
foo.prop1 = 'bar'
// 方法二:关联数组
foo['prop1'] = 'bar'

在 JavaScript 中,使用句点运算符和关联数组引用是等价的,也就是说任何对象(包括 this 指针)都可以使用这两种模式。使用关联数组的好处是,在我们不知道对象的属性名 称的时候,可以用变量来作为关联数组的索引。

var some_prop = 'prop2'
foo[some_prop] = false

上下文对象

callapply

call 和 apply 的功能是 以不同的对象作为上下文来调用某个函数。简而言之,就是允许一个对象去调用另一个对象 的成员函数。灵活使用 call 和 apply 可以节省不少时间,在后面我们可以看到,call 可以用于实现对象的继承。

call 和 apply 的功能是一致的,两者细微的差别在于 call 以参数表来接受被调用函 数的参数,而 apply 以数组来接受被调用函数的参数。call 和 apply 的语法分别是:

func.call(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg[, argsArray])

其中,func 是函数的引用,thisArg 是 func 被调用时的上下文对象,arg1、arg2 或 argsArray 是传入 func 的参数。我们以下面一段代码为例介绍 call 的工作机制:

var someuser = {
	name: 'byvoid',
	display: function(words) {
		console.log(this.name + ' says ' + words);
		}
	}
var foo = {name: 'foobar'}
 
someuser.display.call(foo, 'hello'); // 输出 foobar says hello 

bind

前面说过,可以用 call 或 apply 方法改变被调用函数的上下文。但如果重复使用会不方便,因为每次都要把上下文对象作为参数传递,而且还会使代码变得不直观。针对这种情况,我们可以使用bind方法来永久地绑定函数的上下文,使其无论被谁调用,上下文都是固定的。bind 语法如下:

func.bind(thisArg[, arg1[, arg2[, ...]]]) 

其中 func 是待绑定函数,thisArg 是改变的上下文对象,arg1、arg2 是绑定的参 数表。bind 方法返回值是上下文为 thisArg 的 func。通过下面例子可以帮你理解 bind 的使用方法:

var someuser = {
	name: 'byvoid',
	func: function() {
	console.log(this.name); 
  }
}
var foo = {name: 'foobar' }

foo.func = someuser.func;
foo.func(); // 输出 foobar 
 
foo.func1 = someuser.func.bind(someuser);
foo.func1(); // 输出 byvoid 
 
func = someuser.func.bind(foo);
func(); // 输出 foobar 
 
func2 = func;
func2(); // 输出 foobar

上面代码直接将 foo.func 赋值为 someuser.func,调用 foo.func() 时,this指 针为 foo,所以输出结果是 foobar。foo.func1 使用了 bind 方法,将 someuser 作 为this指针绑定到 someuser.func,调用 foo.func1() 时,this指针为 someuser, 所以输出结果是 byvoid。全局函数 func 同样使用了 bind 方法,将 foo 作为 this 指 针绑定到 someuser.func,调用 func() 时,this 指针为 foo,所以输出结果是 foobar。 而 func2 直接将绑定过的 func 赋值过来,与 func 行为完全相同。

####使用 bind 绑定参数表
bind 方法还有一个重要的功能:绑定参数表

var person = {   name: 'byvoid',
	says: function(act, obj) {
	console.log(this.name + ' ' + act + ' ' + obj)
	}
} 
person.says('loves', 'diovyb'); // 输出 byvoid loves diovyb
byvoidLoves = person.says.bind(person, 'loves'); byvoidLoves('you'); // 输出 byvoid loves you

可以看到,byvoidLoves 将 this 指针绑定到了 person,并将第一个参数绑定到 loves,之后在调用 byvoidLoves 的时候,只需传入第三个参数。这个特性可以用于创建 一个函数的“捷径”,之后我们可以通过这个“捷径”调用,以便在代码多处调用时省略重 复输入相同的参数。

##数组
数组合并:

  • concat code: arr1.concat( arr2 )
  • apply code: Array.prototype.push.apply(arr1, arr2)
  • 循环遍历
var arr1 = [1,2,3], arr2 = [4,5,6];
====================
concat:
var arr3 = arr1.concat(arr2);
console.log(arr3)	// 1,2,3,4,5,6
console.log(arr1)	// 1,2,3
====================
apply:
方法一:Array.prototype.push.apply(arr1,arr2)
方法二:arr1.push.apply(arr1,arr2)
console.log(arr1)	//1,2,3,4,5,6
console.log(arr2)	//4,5,6
====================

##对象
对象合并:

  • $.extend()
  • Obj.assign()
  • 遍历赋值
	var obj1= {'a': 1};
	var obj2= {'b': 2, 'c': 3};
	var c = $.extend(obj1, obj2);

判断 数组/对象: Object.prototype.toString

JavaScript里使用 typeof 来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object” 五种。而对于数组、函数、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串。

Object.prototype.toString 的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于"[object Array]"的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这 个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。

function isArrayFn (o) {
    return Object.prototype.toString.call(o) === '[object Array]';
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值