js看书2简单记录

记的很乱有时间把发的博客再整理一遍

##### 变量作用域和内存问题

- 基本类型和引用类型

- 函数传递是以值的形式

  function setName(obj) {

  obj.name = "Nicholas";

  obj = new Object();

  obj.name = "Greg";

  }

  var person = new Object();

  setName(person);

  alert(person.name); //"Nicholas"

  //如果按引用类型的话  结果应该是greg

- 执行环境

  1. 作用域链

     1. 当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象

     2. 每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

     3. 叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁

     4. 作用域链的结构可以看出,在运行期上下文的作用域链中,标识符所在的位置越深,读写速度就会越慢。因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。

---------------------------------

引用数据类型

- 对象:

  1. 创建 new 构造函数,字面量{}

  2. .表示法和[‘属性名’]:后者可以是变量或者关键字等等,推荐使用.

  3. 如果可选参数很多 可以用对象传入

- array

  1. 新建:new array和字面量

  2. isArray判断是否是数组

  3. instanceof如果有两个全局执行环境的话会出错,因为两个环境的array不同

  4. 不影响原始数组的方法

     1concat:参数-----都可以,   返回值------构建的新数组

     2slice:参数-----startend索引位置,可以是负数,  返回值----指定参数开始到结尾或者第二个参数的所有项、不包括end位置,

     位置

     3indexof:参数-----item,起点位置),返回值-----找到就返回item的索引没找到返回-1

     4lastindexof:同上。从后往前

     遍历迭代数组

     5every:参数-----(函数(item,index,array),可选参数作用域对象),返回值----所有元素满足返回true否则false

     6some:参数同上,返回值-----一项满足返回true停止迭代

     7map:参数同上,返回值----经过处理的新数组

     8filter:参数同上,返回值----满足函数条件的新数组

     7foreach:参数同上,没有返回值

     归并数组

     9reduce:参数同上(函数(precurindexarray)),返回值----构建一个返回值 比如所有元素的和(pre+Cur

     10reduceright:同上,反方向处理数组

     11join转为字符串:参数----(分隔符字符串),返回值----字符串

     12tostring:返回逗号连接的字符串

     13tolocalstring

  5. 影响原始数组的方法

     1reverse:参数---无,返回值-----反转后的数组

     2sort: 参数-----比较函数,  返回值-----比较后的数组,tipssort是按照字符比较所以用函数,函数的返回值-101

     3splice:参数-----(起始位置,删除项数,添加项数),  返回值-----被删除的项的数组(没有删除就是空数组)

     4push从结尾插入元素:参数-----(数组oror其他),返回值-----返回新数组的长度

     5unshift从头插入:同上

     6pop结尾删除元素:返回值----删除的元素

     7shift从头删除元素:同上

- function

  1. 声明

       function name(){}会变量提升

     - 表达式。var 变量名=function执行到才会调用

     - 构造函数:不推荐,因为要解析两次:常规和传入的字符串

  2. 作为值,去掉括号是调用指针,加上括号才会执行

  3. 函数的参数:argumentsthis

     - arguments的属性:callee---指的是函数本身

     - caller:调用函数的函数

     - this指的是执行环境对象

  4. 函数的属性和方法

     1. 属性:

        - length-----函数本身定义的参数的个数

        - prototype----是保存所有实例方法的所在,而且不能枚举,不能用for-in

     2. 方法:改变this指向,扩充函数作用域,只是传入参数不同

        - call;参数为列举的数

        - apply:参数为数组

        - bind:创建函数的实例

        - 继承的tostring

- 基本包装类型:BooleanNumberSrting

  1. 当读取一个基本类型的数据,后台会经历三步

     1. 创建包装类型的实例

     2. 在实例上调用一些方法

     3. 销毁实例

          var s1 = new String("some text");

          var s2 = s1.substring(2);

          s1 = null

  2. 引用类型和包装类型的区别:对象的生存期;对象离开当前作用域一直都在,自动创建的包装对象只在这一行存在

  3. 包装类型用typeof返回object  ,都会被转换成true

  4. 使用new的包装类型和直接使用:new出来的是对象,后者是基本类型强制转换

  5. 基本类型和包装类型的区别

     1. typeof返回值不同

     2. instanceof object返回不同

  6. number方法

     - toFixed()

     - toExponential()

     - toPrecision()会根据要处理的数值决定到底是调用toFixed()还是调用toExponential()

  7. String

     1concat():参数----连接的字符串

     2charAt()charCodeAt():参数-----位置;返回值-----匹配的字符或者字符编码

     3、还提供了三个基于子字符串创建新字符串的方法:slice()substr()substring()

     这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数(在指定的情况下)表示子字符串到哪里结束,。而substr()的第二个参数指的则是返回的字符个

     var stringValue = "hello world";

     alert(stringValue.slice(3)); //"lo world"

     alert(stringValue.substring(3)); //"lo world"

     alert(stringValue.substr(3)); //"lo world"

     alert(stringValue.slice(3, 7)); //"lo w"

     alert(stringValue.substring(3,7)); //"lo w"

     alert(stringValue.substr(3, 7)); //"lo worl"

     slice()方法会将传

     入的负值与字符串的长度相加,substr()方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为0。最后,substring()方法会把所有负值参数都转换为0

     4、:indexOf()lastIndexOf():这两个方法都是从一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回-1)。

     5replace

  8. 内置对象globalmath

#### 面向函数对象

###### 创建对象

1. 字面量

2. 创建Object的实例

3. 工厂模式

   ```

   function createPerson(name, age, job){

   var o = new Object();

   o.name = name;

   o.age = age;

   o.job = job;

   o.sayName = function(){

   alert(this.name);

   };

   return o;

   }

   ```

4. 构造函数模式:必须使用new-----隐式的创建了对象

   - (1) 创建一个新对象;

     (2) 将构造函数的作用域赋给新对象(因此this 就指向了这个新对象);

     (3) 执行构造函数中的代码(为这个新对象添加属性);

     (4) 返回新对象。

     每个方法都要在每个实例上重新创建一遍

     ```

     function Person(name, age, job){

     this.name = name;

     this.age = age;

     this.job = job;

     this.sayName = function(){

     alert(this.name);

     };

     }

     ```

5. 原型模式

   ```

   function Person(){

   }

   Person.prototype.name = "Nicholas";

   Person.prototype.age = 29;

   Person.prototype.job = "Software Engineer";

   Person.prototype.sayName = function(){

   alert(this.name);

   };

   ```

   - 所有属性和方法都共享

   - 实例添加属性和方法会覆盖原型同名的属性和方法----可以用delete删除实例的属性

   - 通过hasOwnProperty()可以知道属性是实例本身true还是原型的

   - in操作符是无论实例还是原型都返回true

   - for-in返回的是通过对象访问的可枚举的属性

   - 获取所有可枚举属性用object.keys()

   - 获取所有属性用getOwnPropertyNames()

   - 包含引用类型的值不能用这个方法创建

6. 组合使用构造函数:定义实例属性和原型模式:定义共享的方法

   ```

   function Person(name, age, job){

   this.name = name;

   this.age = age;

   this.job = job;

   this.friends = ["Shelby", "Court"];

   }

   Person.prototype = {

   constructor : Person,

   sayName : function(){

   alert(this.name);

   }

   }

###### 原型对象:

每个函数都会有prototype属性,指向原型对象。

1. constructor---指向构造这个对象的构造函数

2. 构造函数.prototype==实例.____proto___

###### 对象属性

1. 数据属性

   - Configurable:能否通过delete 删除属性从而重新定义属性----默认值为true

   - Enumerable:能否通过for-in 循环返回属性---性默认值为true

   - [Writable:能否修改属性的值----性默认值为true

   - Value:包含这个属性的数据值------默认值为undefined

2. 要修改属性默认的特性,必须使用Object.defineProperty()方法-------参数(对象,属性,属性的描述:可修改等等)。----访问器属性

   1. Get:在读取属性时调用的函数。默认值为undefined

   2. Set:在写入属性时调用的函数。默认值为undefined

###### 继承

1. 通过原型链:利用原型让一个类型继承另一个类型

   ```

   function SuperType(){

   this.property = true;

   }

   SuperType.prototype.getSuperValue = function(){

   return this.property;

   };

   function SubType(){

   this.subproperty = false;

   }

   //继承了SuperType

   SubType.prototype = new SuperType();

   SubType.prototype.getSubValue = function (){

   return this.subproperty;

   };

   var instance = new SubType();

   alert(instance.getSuperValue()); //true

   ```

2. 搜索首先会在实例中搜索该属性。如果没有找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。找不到属性或方法的情况下,搜索过程总是要一环一环地前行到原型链末端才会停下来

3. 所有函数的默认原型都是Object 的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString()valueOf()等默认方法的根本原因

4. 引用类型会共用

   1. 解决借用构造函数:每个实例就都会具有自己的 属性副本。

      ```

      function SuperType(){

      this.colors = ["red", "blue", "green"];

      }

      function SubType(){

      //继承了SuperType

      SuperType.call(this);

      }

      var instance1 = new SubType();

      instance1.colors.push("black");

      alert(instance1.colors); //"red,blue,green,black"

      var instance2 = new SubType();

      alert(instance2.colors); //"red,blue,green"

      ```

   2. 圣杯模式

      ```

      function object(o){

      function F(){}

      F.prototype = o;

      return new F();

      }

      `

   3. create

   4. 原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。

      原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。解决这个问题的技术是借用构造函数,子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。

#### 函数表达式

###### 函数创建

1. 函数声明会函数声明提升

2. 函数表达式:匿名函数-----和表达式一样,必须先赋值

函数闭包

1. 能访问另一个函数作用域中的变量的函数

2. 作用域链:函数被调用的时候创建一个执行环境及相应的作用域链,然后初始化活动对象-----函数外部的活动对象处在第二位---一直往外-----到全局作用域

3. 闭包的话会把函数外部那个不属于本身的活动对象保存在自己的scope内部属性中,就算外部那个函数执行完毕活动对象被销毁,因为闭包保存下来所以仍然可以访问,直到闭包不存在为止

4. 闭包会携带包含它的函数的作用域,所以会占用更多的内存

5. ```

   闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。

   function createFunctions(){

   var result = new Array();

   for (var i=0; i < 10; i++){

   result[i] = function(){

   return i;

   };

   }

   return result;

   }全是10

   ```

###### this

1. 基于函数对象执行环境绑定的,全局==this,作为方法==实例对象

2. 如果想访问arguments必须吧this=that引用保存下来

####

原文地址:https://www.cnblogs.com/zjj-study/p/13307851.html