Fork me on GitHub

js的作用域链,原型链,以及闭包函数理解

代码一:

this.number = 10
function a() {
  this.number = 20
}
a.prototype.init = () => console.log(this.number)

const test = new a() // 构造函数生成一个独立新对象
test.init() // 10

解析:之所以输出10,可以把 arrow function(箭头函数) 里的 this 和 arguments 关键字理解为函数作用域里的变量(因为自身没有),他访问变量沿着作用域链向上找而不是直接访问对象属性走原型链,代码中的init上头的作用域就是window,所以他的this指向window.

注:可以试试把上例代码中的箭头函数换成普通匿名函数(输出就是直接走原型链访问对象属性,number = 20)

代码二:

this.number = 10
function a(){ //闭包函数
   return {
     show: () => console.log(this.number) 
   }  
}    
a().show() // 10 函数a的this的指向window
a.call({number: 20}).show() // 20 call改变了函数a的this指向,箭头函数的作用域指向改变后的函数作用域
a.call({number: 30}).show() // 30

解析:闭包函数里return出的箭头函数被调用的时候会一直引用外层函数的变量this或者arguments,所以外层函数this指向被改变,return出的箭头函数里的this也改变了.

this的指向可理解为两大类:

1:test();==test.call(window,参数);//直接调用函数,this指向window

2:obj.test(); == obj.test.call(obj,参数);//函数作为对象的方法被调用,this指向该对象

注:this指向是在被调用时分配的

代码三:

function a() {
 this.say = function() {
 console.log(1)
}
}
a.prototype.say = function() {
console.log(2)
}
var test = new a()
test.say() // 1

只有函数有prototype,对象对应_proto_,prototype可以对主函数进行扩充,但不会覆盖主函数内的方法(如果主函数里没有此对象属性就在原型链里查找)。

简单一句话~js中访问变量沿着作用域链向上走(this),直接访问对象上的属性沿着原型链往下走~(都是就近查找哦)

对call和apply做补充:

相同点:都是为了改变对象this指向,参数二不同:call是传进单个参数,apply是数组形式

apply可以接受一个数组或者类数组对象,console.log(...arguments) === console.log.apply(this,arguments)

 

posted @ 2018-01-25 12:00  天满  阅读(333)  评论(0编辑  收藏  举报