坑之作用域
JavaScript的函数定义先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部,所以下面的程序并不会报错,而是会弹出 Hello, undefinded
变量 b 成了undefinded
:
(如果是Python一定会报local variable … referenced before assignment,因为变量未赋值前就引用了)
'use strict';
function run(){
var a = 'Hello, ';
alert(a+b);
var b = 'Bob';
}
alert(run());
所以,最好严格遵守一些规范,首先申明好所有要用变量:
function factorial(){
var
a = 1,
t; // undefinded
for (t=1; t<=10; t++){
a = a*t;
}
return a;
}
JavaScript 在ES6中引入关键字 let
可让 for
语句中的变量申明为局部变量。
function count(){
var
a = 0,
b;
for (let x=1; x<=10; x++){
a += x;
}
b = x; // SyntaxError
}
关键字const
可定义常量,常量名一般大写。
坑之对象
在JS中,对象类似与Python的字典, this 关键字类似于Python中的 self,在对象中定义的函数叫做方法。
var Bird = {
name: 'pre-definded',
age: 2,
run: function (name){
if (arguments.length === 1){
this.name = name;
}
return ('My name is: ' + this.name);
}
};
console.log(Bird.run('Bob')); // 正常
如果把方法放到对象外面:
function getRun(name){
if (arguments.length === 1){
this.name = name;
}
return ('My name is: ' + this.name);
}
var Bird = {
name: 'pre-definded',
age: 2,
run: getRun
};
console.log(Bird.run('Bob')); // 正常
console.log(getRun('Bob')); // NaN
// 但如果这么写
var fn = Bird.run; // 其实拿到的是getRun函数
fn(); // NaN
这是个设计缺陷,所以ECMA规定在 'use strict'
让 this 指向undefinded
, 但并没有修正这个错误:
'use strict';
var Bird = {
name: 'pre-definded',
age: 2,
run: function (name){
if (arguments.length === 1){
this.name = name;
}
return ('My name is: ' + this.name);
}
};
var f = Bird.run;
f(); // Uncaught TypeError: Cannot read property 'birth' of undefined
标准对象和包装对象
null [] {}
的类型都是 object
因此它们之间无法用typeof
来区分。
typeof 123; //"number"
typeof 123.2; //"number"
typeof NaN; // "number"
typeof 'str'; //"string"
typeof true; //"boolean"
typeof []; //"object"
typeof {}; // "object"
typeof null; //"object"
typeof undefined; //"undefined"
typeof Math.abs; //"function"
使用new
创建包装对象
typeof new String('123'); // object
new String('123') === '123'; //false
可以看出如果加了关键字 new 创造出来的对象类型为 object
如果没有关键字 new 呢?
typeof Number('123'); //Number
Number('123') === 123; //true
Number('123')
相当于parseInt('123')
或者parseFloat('123')
使用方法toSting()
转换为String
类型:(null和undefined没有toString()方法)
'123'.toString(); //会报错
'123'..toString(); // 123
('123').toString(); //123
构造函数
原型链
下面创建一个数组:
var arr = [1, 2, 3];
这个数组对象的原型链为:
arr --> Array.prototype --> Object.prototype --> null
所以如果在当前对象上找不到属性时,会去 Array.prototype 上查找,再找不到去 Object.prototype上找,最后找不到,返回undefined。
普通函数的原型链为:
f --> Function.prototype --> Object.prototype --> null
由于Function.prototype定义了apply()等方法,因此,所有函数都可以调用apply()方法
function f(){
alert('alert')
}
对象的创建方法 :
var person = {
name: 'bob',
say: function (){
return ("I'm " + this.name );
}
}
构造函数来创建对象:
function Bird(name){
this.name = name || 'unnamed';
this.say = function(){
return ('Hello '+this.name);
}
}
var bob = new Bird('Bob');
var lusi = new Bird('Lusi');
bob.name; // 'Bob'
lusi.name; // 'Lusi'
this指向新创建的对象,如果没有new来创建,那它就是一个普通的函数,返回undefined,其原型链为:
bob ↘
--> Bird.prototype --> Object.prototype --> null
lusi ↗
对象的方法是不共享的:
bob.say === lusi.say; //false
要让创建的对象共享同一个函数,根据对象的属性查找原则,我们只要把函数移动到对象共同的原型上就可以了,也就是Bird.prototype:
Bird.prototype.say = function (){
return ('Hello '+this.name);
};