学习react前需要知道的JS基础

以下是一些JS基础知识,是在我们学习react前需要了解的。
如果没能把以下的JS基础知识学懂,就去学习react,就是一种折磨。

1. bind call apply

bind call apply是Function.prototype中的方法,定义一个函数的时候,实例函数就能调用这些方法
我们都知道这些方法是可以改变this的指向
以下例子让我们重温一下 bind call apply 的不同点

let a = {
	name: 'aaa',
	fn(arg1,arg2){
		console.log(this,arg1,arg2)
	}	
}
let c = {
    name: 'ccc'
}
a.fn('xiaohei','xiaobai');//打印对象a和'xiaohei' 'xiaobai'

let fn = a.fn.bind(c,'xiaohei','xiaobai');//bind方法会返回一个改变了this指向的方法
fn(); //打印出对象c和'xiaohei' 'xiaobai'

a.fn.call(c,'xiaohei','xiaobai');
a.fn.apply(c,['xiaohei','xiaobai']);

执行a.fn()可打印出对象a
而执行fn()会打印出实例对象c和后面两个参数
因为bind方法会返回一个改变了this指向的方法

a.fn.bind(c,'xiaohei','xiaobai')() //不会执行,需要手动执行
a.fn.call(c,'xiaohei','xiaobai') //立即执行
a.fn.apply(c,['xiaohei','xiaobai']) //数组传参

以上三个方法可得到一样的结果

bind call apply 的不同点就是:

  1. bind 会返回一个改变this指向的方法,但不会执行
  2. call 会立即执行这个方法,相当于bind方法返回新的方法之后立即执行
  3. apply 和 call 用法相同,不同的是以一个数组的形式传参数

2. new一个对象时做了什么

js new一个对象时做了什么,以下是一个简单的例子

function Person (name,age) {
    this.name = name;
    this.age = age;
}
Person.prototype.getName = function(){
	console.log('my name is ' + this.name);
}
 
let person = new Person("xiaohei",18);
console.log(person);
person.getName();//my name is xiaohei

使用关键字new创建新实例对象经过了以下几步:

  1. 创建一个新对象
  2. 将新对象的_proto_指向构造函数的prototype对象(让实例对象可以访问原型对象上的方法)
  3. 将构造函数的作用域赋值给新对象 (将this指向新对象)
  4. 执行构造函数中的代码(将属性添加到实例对象上面)
  5. 返回新的对象
function Person (name,age) {
    this.name = name;
    this.age = age;
}
Person.prototype.getName = function(){
	console.log('my name is ' + this.name);
}
function createPerson(name,age){
	let obj = {};// 创建一个新对象
	obj.__proto__ =  Person.prototype;//将新对象的_proto_指向构造函数的prototype对象
	Person.call(obj,name,age,sex);//改变this指向,并执行函数内代码
	return obj;//返回对象
}
let person = new Person("xiaohei", 18);
let person2 = createPerson("xiaobai", 19);
console.log(person,person2);
person.getName();//my name is xiaohei
person2.getName();//my name is xiaobai

3. 类

在JS中,class是一种语法,其本质就是构造函数和其prototype对象
先定义一个最简单的类,让我们了解类是怎么定义的

class A {
	constructor(name){
		this.name = name
	}
	//类中constructor方法就是构造函数方法
	//在类中定义方法是不加逗号的
	getName(){
		console.log(this.name)
	}
	//类中的方法是绑定在类(构造函数)的原型对象上面的
}

如果把上面的这个A类,转换成构造函数和原型对象的形式是怎么样的?

function A(name){
	this.name = name;
}
//类中constructor方法就是构造函数方法
A.prototype.getName = function(){
	console.log(this.name)
}
//类中的方法是绑定在类(构造函数)的原型对象上面的

以上的构造函数和原型对象对应上面的类

需要注意的是:

  1. 在类中定义方法是不加逗号
  2. 类中的方法是绑定在类(构造函数)的原型对象prototype上面的
  3. 类中constructor方法就是构造函数方法
  4. 类的内部指定了严格模式,在严格模式下不允许this指向window对象

4. 实例方法和原型对象上的方法

class A {
	constructor(name){
		this.name = name;
		this.getName = function(){
			console.log(11,this.name)
		}
	}
	getName(){
		console.log(22,this.name)
	}
}
let a = new A('xiaohei');
a.getName(); // 11 xiaohei

以上代码,是调用了实例对象a上面的getName方法,打印出 11 xiaohei

let a = {
	name: 'xiaohei',
	getName: function(){
		console.log(11,this.name)
	},
	__proto__: {
		getName(){
			console.log(22,this.name)
		}
	}
}
a.getName()

实例对象a先会调用getName方法
如果没有getName方法,才会调 __proto__对象的getName方法,也就是 构造函数A 的 原型对象A.prototype 上面找getName方法

5. 箭头函数

箭头函数是一种用来定义函数语法
与普通函数不同的是,箭头函数没有prototype属性,不能实例化对象

class A {
	constructor(name){
		this.name = name;
	}
	getName = () => {
		console.log(this,this.name)
	}
}

以上的代码,可使用以下伪代码实现

function A(name){
	let _self = this;
	this.getName = function(){
		console.log(_self,_self.name)
	}
	this.name = name;
}

箭头函数不能实例化对象,只能被调用,而调用箭头函数时,this会指向由该类实例化的对象
以下是实例化对象后调用的结果:

class A {
	constructor(name){
		this.name = name;
	}
	getName = () => {
		console.log(this,this.name)
	}
}
let a = new A('xiaohei');
a.getName(); //直接由a对象调用,this指向a;
let fn = a.getName;
fn(); //在window调用,this指向仍是a

伪代码如下:

function A(name){
	let _self = this;
	this.getName = function(){
		console.log(_self,_self.name)
	}
	this.name = name;
}
let a = new A('xiaohei');
a.getName(); //直接由a对象调用,this指向a;
let fn = a.getName;
fn(); //在window调用,this指向仍是a,而不是window

直接由a对象调用,this指向a对象
在window调用,this指向仍是a,而不是window(严格模式下为undefined)

6. this的指向

在调用方法时,如果不由实例去调用的话,this不指向实例对象
在react中,会用类似以下的方式去调用:

class A {
	constructor(name){
		this.name = name;
	}
	getName() {
		console.log(this,this.name)
	}
}
let a = new A('xiaohei');
let fn = a.getName;
fn();

在这样的方式调用getName方法,getName方法中的this不指向实例对象
要在window中调用方法时,并要将方法中的this指向该实例对象,可有以下的方法:

  1. 在调用方法前使用bind改变this指向,返回新的函数
class A {
	constructor(name){
		this.name = name;
	}
	getName() {
		console.log(this,this.name)
	}
}
let a = new A('xiaohei');
let fn = a.getName.bind(a);
fn();
  1. 在构造函数中,定义实例化对象时,为实例对象添加一个返回了 原形对象的getName方法改变this的指向的方法
class A {
	constructor(name){
		this.name = name;
		this.getName = this.getName.bind(this);
	}
	getName() {
		console.log(this,this.name)
	}
}
let a = new A('xiaohei');
let fn = a.getName;
fn();

实例化的对象a 会有添加一个指向自身的getName方法
在该实例对象new的时候会拿到原型上的getName方法,将其this指向改变,返回出来的函数绑定在该实例对象的getName属性上

  1. 使用箭头函数
class A {
	constructor(name){
		this.name = name;
	}
	getName = () => {
		console.log(this,this.name)
	}
}
let a = new A('xiaohei');
let fn = a.getName;
fn();

由上面的箭头函数解析中可以知道,使用箭头函数来添加方法的话,在构造函数被调用(也就是new一个实例对象)的时候,就会将方法绑定在实例上面,而不是添加在原型上,同时该方法的this指向其实例对象,不会指向调用该方法的对象
伪代码如下:

function A(name){
	let _self = this;
	this.getName = function(){
		console.log(_self,_self.name)
	}
	this.name = name;
}
let a = new A('xiaohei');
let fn = a.getName;
fn();

但使用该方式的缺点是会增加内存开销,因为每一个实例都会有一个getName方法,而不是在构造函数的原型上面

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值