本文主要目的是向c++程序员阐述javascript的编程思想,以及编程中的误区。
变量声明:
1、变量声明的解析早于代码运行。JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行(This behaviour is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.)
2、给一个未声明的变量赋值等于创建一个全局变量
具体参见:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
http://www.nowamagic.net/librarys/veda/detail/1623
变量没有块作用域,只有函数作用域:
1、当初为了实现简单,只有function scope and not block scope,所以{}对变量作用域没起作用
http://stackoverflow.com/questions/17311693/why-does-javascript-not-have-block-scope
var x = 1; { var x = 2; } alert(x); // outputs 2
布尔条件判断:
除了以下值是假的,其他都是真的
false
undefined
null
0
NaN
""
) 例如,下面这个是假的:
var b = new Boolean(false); if (b) // this condition evaluates to true
闭包:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
一些特殊的函数:
bind apply call
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Function/bind
对象创建:
联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象。这种概念非常简单,即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。结果是,所有函数都只创建一次,而每个对象都具有自己的对象属性实例。
我们重写了前面的例子,代码如下:
function Car(sColor,iDoors,iMpg) { this.color = sColor; this.doors = iDoors; this.mpg = iMpg; this.drivers = new Array("Mike","John"); } Car.prototype.showColor = function() { alert(this.color); }; var oCar1 = new Car("red",4,23); var oCar2 = new Car("blue",3,25); oCar1.drivers.push("Bill"); alert(oCar1.drivers); //输出 "Mike,John,Bill" alert(oCar2.drivers); //输出 "Mike,John"
继承:
参考:http://www.w3school.com.cn/js/pro_js_inheritance_implementing.asp
由于 对象冒充 这种继承方法的流行,ECMAScript 的第三版为 Function 对象加入了两个方法,即 call() 和 apply()
嵌套函数调用this问题(definitive guide 8.2.2)
If a nested function is invoked as a function
then its thisvalue will be either the global object (non-strict mode) or undefined(strict
mode). It is a common mistake to assume that a nested function invoked as a function
can use thisto obtain the invocation context of the outer function. If you want to access
the thisvalue of the outer function, you need to store that value into a variable that is
in scope for the inner function. It is common to use the variable selffor this purpose.
For example:
var o = { // An object o. m: function() { // Method m of the object. var self = this; // Save the this value in a variable. console.log(this === o); // Prints "true": this is the object o. f(); // Now call the helper function f(). function f() { // A nested function f console.log(this === o); // "false": this is global or undefined console.log(self === o); // "true": self is the outer this value. } } };
对象作为实参,类似c的结构体参数,这样就不用记住参数顺序了。(definitive guide 8.3.3)
// Copy length elements of the array from to the array to. // Begin copying with element from_start in the from array // and copy that element to to_start in the to array. // It is hard to remember the order of the arguments. function arraycopy(/* array */ from, /* index */ from_start, /* array */ to, /* index */ to_start, /* integer */ length) { // code goes here } // This version is a little less efficient, but you don't have to // remember the order of the arguments, and from_start and to_start // default to 0. function easycopy(args) { arraycopy(args.from, args.from_start || 0, // Note default value provided args.to, args.to_start || 0, args.length); } // Here is how you might invoke easycopy(): var a = [1,2,3,4], b = []; easycopy({from: a, to: b, length: 4});
需要明白 lexical scoping和dynamic scope区别:(definitive guide 8.6)
作用域是描述名称对应的实体。
可以参考:
http://en.wikipedia.org/wiki/Scope_(computer_science)
Name resolution of properties of JavaScript objects is based on inheritance in the prototype tree – a path to the root in the tree is called a prototype chain– and is separate from name resolution of variables and functions.
javascript的对象属性走的是prototype chain,和名称解析无关。
http://www.zhihu.com/question/20032419
词法作用域(lexical scope)等同于静态作用域(static scope)。所谓的词法作用域其实是指作用域在词法解析阶段既确定了,不会改变。
我们要知道js是遵循静态作用域的。举个例子:
var foo=1;
function static(){
alert(foo);
}
!function(){
var foo=2;
static();
}();
在js中,会弹出1而非2,因为static的scope在创建时,记录的foo是1。
如果js是动态作用域,那么他应该弹出2。请体会一下两者的区别。
另外,借@贺师俊的话,eval 和 with可以产生动态作用域的效果。
9.2.1 Constructors and Class Identity
As we’ve seen, the prototype object is fundamental to the identity of a class: two objects
are instances of the same class if and only if they inherit from the same prototype object.
The constructor function that initializes the state of a new object is not fundamental:
two constructor functions may have prototypeproperties that point to the same prototype object. Then both constructors can be used to create instances of the same class.
Even through constructors are not as fundamental as prototypes, the constructor serves
as the public face of a class. Most obviously, the name of the constructor function is
usually adopted as the name of the class. We say, for example, that the Range()constructor creates Range objects. More fundamentally, however, constructors are used
with the instanceofoperator when testing objects for membership in a class. If we have
an object rand want to know if it is a Range object, we can write:
r instanceof Range // returns true if r inherits from Range.prototype
The instanceof operator does not actually check whether r was initialized by the
Rangeconstructor. It checks whether it inherits from Range.prototype. Nevertheless,
the instanceofsyntax reinforces the use of constructors as the public identity of a class.
We’ll see the instanceofoperator again later in this chapter
9.2.2 The constructor Property
In Example 9-2we set Range.prototypeto a new object that contained the methods for
our class. Although it was convenient to express those methods as properties of a single
object literal, it was not actually necessary to create a new object. Any JavaScript
functioncan be used as a constructor, and constructor invocations need a prototype
property. Therefore, every JavaScript function (except functions returned by the ECMAScript 5 Function.bind()method) automatically has a prototypeproperty. The value of this property is an object that has a single nonenumerable constructorproperty.
The value of the constructor property is the function object:
var F = function() {}; // This is a function object.
var p = F.prototype; // This is the prototype object associated with it.
var c = p.constructor; // This is the function associated with the prototype.
c === F // => true: F.prototype.constructor==F for any function
The existence of this predefined prototype object with its constructorproperty means
that objects typically inherit a constructorproperty that refers to their constructor.
Since constructors serve as the public identity of a class, this constructor property gives
the class of an object:
var o = new F(); // Create an object o of class F
o.constructor === F // => true: the constructor property specifies the class
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
9.3 Java-Style Classes in JavaScript
这个很重要,对比一下java和javascript的类