javascript笔记

2017-12-31  本文已影响0人  lwz9103

数据类型

1.基本数据类型和引用类型

基本数据类型包含 number, string, boolean, undefined, 引用类型包含object 和 function.

它们之间的区别在于:

var a = "hello world"; // string为基本类型,没有属性和方法,在调用方法时,实际上是转换成了包装类型(object)
var b = {};                // b为object类型,可以自由的添加属性和方法
b.type = "";            
b.add = function() {};
var a = 1;
var b = a;  //可以认为a,b两个变量指向两个基本类型的值,此时它们的值相等,都为1
a = 2;        // a变量指向的值变成了另一个基本类型的值,b不变化
console.log(b); // 输出1

var obj1 = {age : 1}; // 在堆内存中创建了一个对象,obj1的值存放了这个对象的地址
var obj2 = obj1;  // 可以认为将obj1中存放对象的地址告诉了obj2
obj1.age = 2;  // .操作为访问对象的属性或方法,赋值操作将对象的age属性值更改为2
console.log(obj2.age); // 读取对象的age属性,此刻为2

2.各类数据类型的值

var x;   //仅声明了变量x,并没有赋值,此时类型为undefined
x;      // 特别注意,没有var表示声明变量,而直接使用,则默认为缺省window,此刻可认为 window.x = undefined
var x1 = 123;
var x2 = new Number("123abc");  // x2为object, 实际值为NaN
var x3 = parseInt("123abc");        // x3的值为123
var x4 = parseFloat("0.23acv");   // x4的值为0.23
var x = "hello world";
var x = 'hello world'; // 单引号和双引号均表示字符串,这与java不同
var x = ne'w String(); // x为object对象, "123".length,就是将基本类型转换成了包装类型
var x = true;  //
var x = 1 && 2; // 1为number类型,会隐式转换成boolean类型
var x = new Boolean(true); // Boolean为包装类,x 为对象类型
var x = null; // 对null进行typeof操作,结果为object
var x = {};     
var x = new Object();  // new关键字是执行类的构造函数,并返回该类的一个实例对象
//String, Object, Array, Date等等都是类,都是function类型
function A() {}; // 定义了一个function A,也可以称之为类A
var doAdd = new Function("iNum", "alert(iNum + 20)");
doAdd(10); // 注意这里,new 返回的实例不是对象,而是一个Function(类)
补充: object类型和function类型的区别
var x = function A() {return 1}; // 若是全局环境下定义函数,则函数将会作为window的一个属性
var obj = new x();  // 注意obj不为1,构造函数内的return在new关键字上是无效的
function test(){console.log(111)};
test();        // 此处调用函数默认缺省了this,完整的应该为this.test();
(function test(){console.log(111)})(); // 此处为函数直接量的写法
var obj = {};
test.call(obj);

3. 数据类型之间的转换

// 转换规则为
如果是number类型,0为false,非0为true
如果是string类型,空字符串""为false,其余为true
如果是object类型,null为false,其余为true
如果是undefined类型,一律为false
//转换规则为
如果有toString发放, 则调用toString方法
如果是undefined类型或者是null,返回"undefined"或者"null"
//转换规则为
如果是boolean类型,true变为1,false变为0
如果是undefined, 变为NaN
如果是null, 变为0
如果是string, 空字符串变为0,其余按字符串字面最前匹配转换,如不能转换则为NaN
如果是object,先调用valueOf(),按上述规则转换,如果是NaN,再调用toString,再按上述规则转换

4. 类型检测

var obj = {};
var arr = [];
function a(){}
var a = new a();
console.log(obj instanceof Object) // true
console.log(arr instanceof Array) // true
console.log(a instanceof a) // true

变量及执行环境

1.全局变量、属性变量、局部变量(包含方法实参)的定义

var x = 12;       // 全局执行环境下,利用var定义变量,会变为window的属性
function A(){    // 全局执行环境下,定义方法,也会变为window的属性
  y = 24;           // 函数执行环境下,不用var来声明变量,也会变为window的属性
}
console.log(window); // window增加了三个属性,x、A以及y
(function B(){})();//特别值得一提的是,函数直接量的写法使得B形成一个闭包,外部环境是无法访问的
B(); // B为闭包,在全局环境下无法访问,会出现 undefined提示

// 函数直接量可以如下理解
function () {
  function B(){};  // 在函数执行环境下,定义了B方法,B属于局部变量,而不是全局变量
  B();                 // 在函数执行环境下,执行了B方法
}
var obj = {name : "lwz9103", age : 21}; // 为obj对象定义了name属性和age属性
obj.xyz = 123; // 为obj对象定义了xyz属性
function test(x, y) { 
  var txt = "nihao";  // 在函数执行环境下用var定义局部变量 txt
  return x + y
};
test(1, 2); // 方法执行时,定义了方法实参 x,y

// 函数执行时实参定义的过程可以这么理解
function test(x, y) {
  arguments = [1, 2]; // 将传入参数列表放入arguments对象,类似java的可变参数列表
  var x = 1;
  var y = 2;
}

2.执行环境及作用域链

对象与函数

1.this对象

全局环境下,this对象为window,函数环境下,this为函数的调用者,如果函数没有显示的调用者,则这个调用者为window

function B(){
   function C(){
      console.log(this); // window
   };
   C();
  console.log(this);  // b
};
var b = {add : B};
b.add();

2.对象创建方式

function factory(){
  var obj = new Object();
  obj.name = "lwz";
  obj.add = function() {};
  return obj;
}
var obj = factory();
// 工厂方法的缺陷是没有对象的类型信息, 且相同的方法每个实例都需要创建
function A(){
  this.age = 1;
  this.add = function(){};
}
var a = new A();
// 构造方法方式的缺陷是相同的方法每个实例都需要重新创建
function A(){
  this.age = 1;
}
A.prototype.add = function(){};
A.prototype.name = "张三";
var a1 = new A();
a1.name = "lwz";
var a2 = new A();
console.log(a2.name); // lwz
// 原型方法将对象方法都放在原型属性上,达到共用的目的
// 需要注意的是,原型属性会造成脏属性的情况,需要避免在原型上定义属性

3.函数原型对象

在定义函数时,同时会创建一个原型对象。该类(函数)在创建实例时,会有一个proto属性指向原型对象。

function A(){};
A.prototype.age = 12;
var a = new A();
它们之间的关系是:
函数A的prototype属性指向 A.prototype对象
A.prototype.constructor 指向函数A
a的_proto_属性指向 A.prototype
注:对象访问属性或者方法的规则
优先查找对象的一级属性/方法(for in能找到),如果不存在,则查找_proto_属性(即原型属性)下的属性和方法,依此逐级往下查找

4.继承

function B(){
  this.arr = [1,2,3];
};
B.prototype = new Array();
//这个也可以这么写
//B.prototype = {
//  length : 0,
//  ...
//  shift : function(){...},
//  push: function(){...},
//  ...
//}
var b = new B();
b.shift(1);
b.arr.push(4);
var c = new B();
console.log(c.arr); // 1,2,3,4
// 原型链继承缺陷是原型对象中可能包含引用属性,这样每个实例对象的这个属性变成了共用的,则会出现问题
function A(){
  this.arr = [1,2,3];
}
A.prototype.add = function(){};
function B(){
  A.call(this); // 赋值属性
}
B.prototype = new A();
B.prototype.constructor = B;
var b1 = new B();
b1.arr.push(4);
var b2 = new B();
console.log(b2.arr); // 1,2,3
// 组合继承是显示调用了A的构造方法,使得arr存在于实例的一级属性中,但是缺陷是三级属性中也包含了arr, 即b1._proto_._proto_.arr是存在的
function A(){
  this.arr = [1,2,3,4];
};
A.prototype.add = function() {};
function B(){
  A.call(this);
};
function inheritPrototype(x, y){
  var prototype = clone(x.prototype)
  prototype.constructor = x;
  y.prototype = prototype;
}
inheritPrototype(A, B);
// 寄生组合继承的特点是,属性拷贝了一份,原型属性也拷贝了一份,而不像组合继承那样,原型属性使用的是一个对象实例。
上一篇 下一篇

猜你喜欢

热点阅读