JavaScript是一种弱类型脚本语言,所谓弱类型指的是定义变量时,不须要什么类型,在程序运行过程当中会自动判断类型javascript
typeof xxx
获得的值有一下类型:undefined、boolean、number、string、object、function、symbol
前端
typeof null
结果是object
,实际这是typeof
的一个bug
,null
是原始值,非引用类型typeoof [1,2]
结果是object
,结果中没有这一项,引用类型除了function
其余的所有都是objecttypeof Symbol()
用typeof
获取symbol
类型的值获得的是symbol
,这是ES6
新增的知识点用于实例和构造函数的对应。例如判断一个变量是不是数组,使用typeof
没法判断,但可使用[1,2] instanceof Array来判断。由于,[1,2]
是数组,它的构造函数就是Array:同理java
function Foo(name) { this.name = name } var foo = new Foo('bar') console.log(foo instanceof Foo) // true
除了原始类型,ES还有引用类型,上文提到的typeof识别出来的类型中,只有object和function是引用类型,其余都是值类型数组
根据JavaScript中的变量类型传递方式,又分为值类型
和引用类型
值类型包括:Boolean、string、number、undefined、null
;
引用类型包括:object类的全部,如Date、Array、function等。
在参数传递方式上,值类型是按值传递,引用类型是按地址传递promise
// 值类型 var a = 10 var b = a b = 20 console.log(a) // 10 console.log(b) // 20
上述代码中,a b都是值类型,二者分别修改赋值,相互之间没有任何影响。再看引用类型的例子:浏览器
// 引用类型 var a = {x: 10, y: 20} var b = a b.x = 100 b.y = 200 console.log(a) // {x: 100, y: 200} console.log(b) // {x: 100, y: 200}...
上述代码中,a b都是引用类型。在执行了b = a以后,修改b的属性值,a的也跟着变化。由于a和b都是引用类型,指向了同一个内存地址,即二者引用的是同一个值,所以b修改属性时,a的值随之改动。
再借助题目进一步讲解一下。闭包
function foo(a){ a = a * 10; } function bar(b){ b.value = 'new'; } var a = 1; var b = {value: 'old'}; foo(a); bar(b); console.log(a); // 1 console.log(b); // value: new...
经过代码执行,会发现:ecmascript
Number
类型的a
是按值传递的,而Object
类型的b
是按地址传递的。** JS 中这种设计的缘由是:**按值传递的类型,复制一份存入栈内存,这类类型通常不占用太多内存,并且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会由于不停复制内容而形成内存的浪费。...异步
引用类型常常会在代码中按照下面的写法使用,或者说容易不知不觉中形成错误!函数
var obj = { a: 1, b: [1,2,3] } var a = obj.a var b = obj.b a = 2 b.push(4) console.log(obj, a, b)
虽然obj自己是个引用类型的变量(对象),可是内部的a和b一个是值类型一个是引用类型,a的赋值不会改变obj.a,可是b的操做却会反映到obj对象上。
JavaScript 是基于原型的语言,原型理解起来很是简单,但却特别重要,下面仍是经过题目来理解下JavaScript 的原型概念。
对于这个问题,能够从下面这几个要点来理解和回答,下面几条必须记住而且理解
// 要点一:自由扩展属性 var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn () {} fn.a = 100; // 要点二:__proto__ console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__); // 要点三:函数有 prototype console.log(fn.prototype) // 要点四:引用类型的 __proto__ 属性值指向它的构造函数的 prototype 属性值 console.log(obj.__proto__ === Object.prototype)...
// 构造函数 function Foo(name, age) { this.name = name } Foo.prototype.alertName = function () { alert(this.name) } // 建立示例 var f = new Foo('zhangsan') f.printName = function () { console.log(this.name) } // 测试 f.printName() f.alertName()...
执行printName时很好理解,可是执行alertName时发生了什么?这里再记住一个重点 当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找,所以f.alertName就会找到Foo.prototype.alertName。...
那么如何判断这个属性是否是对象自己的属性呢?使用hasOwnProperty,经常使用的地方是遍历一个对象的时候。
var item for (item in f) { // 高级浏览器已经在 for in 中屏蔽了来自原型的属性,可是这里建议你们仍是加上这个判断,保证程序的健壮性 if (f.hasOwnProperty(item)) { console.log(item) } }...
仍是接着上面的示例,若是执行f.toString()时,又发生了什么?
// 测试 f.printName() f.alertName() f.toString()
由于f
自己没有toString()
,而且f.__proto__
(即Foo.prototype
)中也没有toString
。这个问题仍是得拿出刚才那句话——当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的__proto__
(即它的构造函数的prototype
)中寻找。
若是在f.__proto__
中没有找到toString
,那么就继续去f.__proto__.__proto__
中寻找,由于f.__proto__
就是一个普通的对象而已嘛!...
f.__proto__
即Foo.prototype
,没有找到toString
,继续往上找f.__proto__.__proto__
即Foo.prototype.__proto__
。Foo.prototype
就是一个普通的对象,所以Foo.prototype.__proto__
就是Object.prototype
,在这里能够找到toString...
f.toString
最终对应到了Object.prototype.toString
这样一直往上找,你会发现是一个链式的结构,因此叫作“原型链”。若是一直找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 —— Object.prototype.__proto__ === null
全部从原型或更高级原型中获得、执行的方法,其中的this
在执行时,就指向了当前这个触发事件执行的对象。所以printName
和alertName
中的this
都是f
。