笔记-JS高级程序设计-变量,作用域和内存问题

1在将一个值赋给变量时,解析器必须确认这个值是基本类值还是引用类型值,基本类型值是按值访问的,可以操作保存在在变量中的实际值,引用类型是保 存在内存中的对象,JS不允许直接访问内存中的位置,所以实际操作的是对象的引用而不是实际对象。(当复制保存这对象的某个变量时,操作的是对象的引用,但是为对象添加属性的时候,操作的却是实际对象)。

2"JS一切皆对象",当然了简单值就不是对象。对象就是若干属性的集合,所以说对象只有属性,没有方法。其实方法也是属性,因为他的属性表现为键值对,对象可以随意的扩充属性:

var obj = {
  a:10,
  b:function(){
    console.log(panrui) } c:{ name:panrui, age:
23 } }

 

当然了数组和函数不能,但是他们有另外一种形式

var fn = function () {
            alert(100);
        };
    fn.a = 10;
    fn.b = function () {
         alert(123);
    };
    fn.c = {
        name: "panrui",
        year: 1994
    };

3对象都是通过函数创建的,每个函数都有一个prototype的属性,这个属性的值又是一个对象,这个对象默认只有一个属性constructor,指向这个函数本身。prototype所以称之为原型对象,因为他的值是一个对象。既然作为一个对象,就当然有很多的属性,不信你看Object(它是一个函数)。这位大佬就用友很多属性了。

每个对象都有一个__proto__属性,它的值也是一个对象,我们称之为隐式原型。因为object.__proto__ == Object.prototype。也就是说对象的__proto__属性引用了,创建这个对象的函数的prototype。所以也验证上面所说对象全是函数创建的,但是上面也提到函数也是一种对象,是不是有点晕。

4Object是所有对象是始祖,既然Object是函数,那么肯定存在Object.prototype这个原型对象了,那么肯定也存在Object.prototype.__proto__这个隐式原型了,那么这个对象又是继承那个函数的prototype呢,答案是Object.prototype.__proto__其实是null,已经到终点了。

5我们上面提到过,函数也是一种对象,那么Object函数(既是函数,也是对象)也肯定存在__proto__这个隐式原型吧,那么这个对象是被谁创建的呢?答案是Function函数。那么Function函数是被谁创建的呢,因为他也可以看做是一个对象啊,答案是他自己创建了自己。

6Instanceof的解析:判断变量是不是给定引用类型的实例。简单点说A Instanceof B,既然是判断A是不是B的实例,就是沿着A.__proto__ 和B.prototype去判断,如果最后能够指到同一个地方,那么就是返回true。

7JS的继承通过原型链来体现,访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。那么如何判断属性是在对象上面,还是在原型链上面呢,答案就是hasOwnProperty,人家是一个方法,作为参数的属性名还必须用字符串形式指定,例如Object.hasOwnProperty("name"),判断属性name是在Object对象上面,还是在原型链上面

8执行上下文

  1在一段代码拿来真正运行(已经调用了,但是还没有具体执行哪一行代码)之前,浏览器会做一些准备工作,包含变量的声明(赋值操作是在运行的时候执行的),给this赋值(至于this的取值情况取决与调用函数的父级对象),同时还需要给函数声明赋值。如果在函数当中,除了上面的三个,还包含给arguments对象赋值以及函数参数赋值,虽然函数内部调用参数的时候其实是调用arguments对象的。另外一点,函数当中的自由变量是在定义的时候就确定了,不是函数执行的时候来取值。

  2this的取值问题:函数定义的时候是不能确定this的指向,只有函数执行的时候才可以确定。那么如何确定呢?实际上this的最终指向的是那个调用它的对象

//如果函数作为普通函数,在全局环境下面,this指向window
function
a(){ var user = "panrui"; console.log(this.user); //undefined console.log(this); //Window } a();
//构造函数版this 如果函数作为构造函数,那么当中的this指向的是新创建的实例
function Fn(){
    this.user = "panrui";
}
var a = new Fn();
console.log(a.user); //panrui
//函数是在对象当中调用的,所以this指向的是对象o
var o = { user:"panrui", fn:function(){ console.log(this.user); //panrui } } o.fn();
//通过call和apply的引用,改变this的指向
var a = {
    user:"panrui",
    fn:function(){
        console.log(this.user); //panrui
    }
}
var b = a.fn;
b();//undefined b.call(a);//改变了函数b里面的this指向,指向我们传入的对象a,所以结果为panrui
//另外call与apply的不同点在于apply的第二个参数必须为数组形式,而call只需要按顺序依次就行。如果第一个参数为null,那么this指向的就是window
bind方法也可以改变this的指向,不同点在于bind方法返回的是一个修改过后的方法,不会立刻去执行,并且参数可以在执行的时候添加进去。

  3作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的,作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突,作用域在函数定义时就已经确定了,而不是在函数调用时确定。作用域只是一个“地盘”,一个抽象的概念,其中没有变量,要通过作用域对应的执行上下文环境来获取变量的值(比如说函数A,定义A的时候就已经确定了作用域的范围,但是A每执行一次,就会产生一个执行上下文,),作用域中变量的值是在执行过程中产生的确定的,而作用域范围却是在函数创建时就确定了。

  4闭包应用的两种情况,一种是函数作为返回值,另一种是函数作为参数传递。

 

posted @ 2018-03-20 22:36  初心不负  阅读(200)  评论(0编辑  收藏  举报