Js知识点

Posted by Solace Blog on March 6, 2019

JS知识点

闭包

闭包就是能够读取其他函数内部变量的函数;

function test() {
	var temp = 100;
	function foo() {
		document.write(temp);
	}
	return foo;
}

var tt = test();
tt(); // 100

上面代码块中,一旦test()执行完毕,那么我们认为temp变量在外部不可被访问。然而这段代码依然可以运行。造成这种现象的原因就是闭包,tt获取到了test()里面的foo()方法的引用,当执行时,自然而然可以访问test()内部的变量temp。

立即执行函数

在上面的闭包中,我们经常会写出这样的代码:

function test2() {
	var arr = [];
	for(var i = 0; i < 10; i ++) {
		arr[i] = function() {
			document.write(i + ', ');
		}
	}

	return arr;
}

var myArr = test2();
for(var j = 0; j < 10; j++) {
	myArr[j]();
}
// 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,

上面代码运行结果显然不是我们想要的结果,那么造成这种结果的原因是,对于arr数组的每个元素赋值时,每个元素只是引用了i,但当循环结束时i值已经变为10,所以后面运行时会每个元素所使用的i值都是10。解决这种问题有两种方法:

// 方法一:立即执行函数
for(var i = 0; i < 10; i ++) {
	(function(j) {
		arr[j] = function() {
			document.write(j + ', ');
		}
	})(i);
}
// 方法二:改变i的作用域
for(let i = 0; i < 10; i ++) {
	arr[i] = function() {
		document.write(i + ', ');
	}
}

立即执行函数格式为:

(function(j) {})(i)

(function(j) {}(i))

官方建议第一种,后面的()相当于是方法的调用。其中的i是函数接收的形参,j是实参。

原型链

在JavaScript中,每个实例对象(object )都有一个私有属性(称之为__proto__)指向它的原型对象(prototype),该原型对象也有一个自己的原型对象(proto) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法,原型也是对象。

  • 利用原型的特点和概念,可以提取出共有属性
Car.proptotype = {
    name: 'BMW',
    color: 'red'
}

function Car() {}

上面的Car对象中,使用prototype给Car对象的原型链增加了两个属性,这种对象通用的属性我们可以使用prototype来给对象赋上。

  • 对象如何查看原型 -> 隐式属性 _proto_
Car._proto_

几乎每个对象有个隐式属性(在F12开发者模式中,隐形属性使用浅紫色标识,深紫色标识我们手动赋予的属性或方法),其中_proto_属性指向的就是Car.prototype

  • 对象如何查看对象的构造函数 -> 隐式属性constructor
Car.constructor
  • 使用Object.create(原型)还可以通过指定某个对象作为原型对象来继承某个对象
var Animal = {
    color: 'white',
    name : 'xiaobai'
};

var dog = Object.create(Animal);

上面通过Object.create()方法来指定了Animal来作为了dog继承自Animal

apply/call

call和apply方法类似,区别是call接收的是一个参数列表,apply接收的是一个数组

作用:改变this指向
function Person(name, age) {
    this.anme = name;
    this.age = age;
}

var obj = {};
Person.call(obj, 'zing', '29');

console.log(obj); // {name: 'zing', age: '29'}

通过call方法可以改变Personthis的指向,相当于借用Person实现赋值。

使用场景:

// 小王的代码
function Person(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}

// 我的代码
function Student(name, age, sex, score, grade) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.score = score;
    this.grade = grade;
}

上面小王的很多代码和我代码重复了,那通过call就可以实现借用小王的代码实现我的功能:

// 我的代码
function Student(name, age, sex, score, grade) {
    Person.call(this, name, age, sex);
    this.score = score;
    this.grade = grade;
}

使用apply实现上面的代码

// 我的代码
function Student(name, age, sex, score, grade) {
    Person.apply(this, [name, age, sex]);
    this.score = score;
    this.grade = grade;
}