You can access object properties with [] instead of .
这允许您查找与变量匹配的属性 .
obj = {a:"test"};
var propname = "a";
var b = obj[propname]; // "test"
您还可以使用它来获取/设置名称不是合法标识符的对象属性 .
obj["class"] = "test"; // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.
有些人不知道这一点并最终使用这样的 eval() ,这是一个非常糟糕的主意:
var propname = "a";
var a = eval("obj." + propname);
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
// A private method only visible from within this constructor
function calcFullName() {
return firstName + " " + lastName;
}
// A public method available to everyone
this.sayHello = function () {
alert(calcFullName());
}
}
//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();
// This fails since the method is not visible from this scope
alert(person1.calcFullName());
我知道'm late to the party, but I just can' t相信 + 运算符's usefulness hasn' t已被提及超出"convert anything to a number" . 也许这是隐藏一个功能有多好?
// Quick hex to dec conversion:
+"0xFF"; // -> 255
// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();
// Safer parsing than parseFloat()/parseInt()
parseInt("1,000"); // -> 1, not 1000
+"1,000"; // -> NaN, much better for testing user input
parseInt("010"); // -> 8, because of the octal literal prefix
+"010"; // -> 10, `Number()` doesn't parse octal literals
// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null; // -> 0;
// Boolean to integer
+true; // -> 1;
+false; // -> 0;
// Other useful tidbits:
+"1e10"; // -> 10000000000
+"1e-4"; // -> 0.0001
+"-12"; // -> -12
当然,您可以使用 Number() 代替这一切,但 + 运算符更漂亮!
您还可以通过覆盖原型的 valueOf() 方法为对象定义数字返回值 . 对该对象执行的任何数字转换都不会产生 NaN ,而是 valueOf() 方法的返回值:
var A = {
foo : 'greetings'
};
var B = Object.beget(A);
alert(B.foo); // 'greetings'
// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo); // 'hello'
A.bar = 'world';
alert(B.bar); // 'world'
// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo); // 'hello'
B.bar = 'universe';
alert(A.bar); // 'world'
//Takes a function that filters numbers and calls the function on
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
var filteredNumbers = [];
for (var index = 0; index < numbers.length; index++)
{
if (filterFunction(numbers[index]) == true)
{
filteredNumbers.push(numbers[index]);
}
}
return filteredNumbers;
}
//Creates a function (closure) that will remember the value "lowerBound"
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
return function (numberToCheck) {
return (numberToCheck > lowerBound) ? true : false;
};
}
var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];
var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);
numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);
numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);
在此之后我们创建一个Dog类,其中 extends Pet and overrides the .toString() 方法再次改变它的行为(多态) . 此外,我们还为子类添加了一些其他属性 .
在此之后,我们检查继承链以显示Dog仍然是Dog类型,Pet类型和Object类型 .
// Defines a Pet class constructor
function Pet(name)
{
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
}
// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function()
{
return 'This pets name is: ' + this.getName();
};
// end of class Pet
// Define Dog class constructor (Dog : Pet)
function Dog(name, breed)
{
// think Dog : base(name)
Pet.call(this, name);
this.getBreed = function() { return breed; };
}
// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();
// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;
// Now we override Pet.prototype.toString
Dog.prototype.toString = function()
{
return 'This dogs name is: ' + this.getName() +
', and its breed is: ' + this.getBreed();
};
// end of class Dog
var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);
// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true
try {
myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
// statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
// statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
// statements to handle EvalError exceptions
} catch (e) {
// statements to handle any unspecified exceptions
logMyErrors(e); // pass exception object to error handler
}
var recurse = function() {
if (condition) arguments.callee(); //calls recurse() again
}
如果你想做这样的事情,这很有用:
//do something to all array items within an array recursively
myArray.forEach(function(item) {
if (item instanceof Array) item.forEach(arguments.callee)
else {/*...*/}
})
Objects
关于对象成员的一个有趣的事情:它们可以有任何字符串作为其名称:
//these are normal object members
var obj = {
a : function() {},
b : function() {}
}
//but we can do this too
var rules = {
".layout .widget" : function(element) {},
"a[href]" : function(element) {}
}
/*
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
var elements = document.querySelectorAll(rules[item]);
for (var e, i = 0; e = elements[i++];) rules[item](e);
}
Strings
String.split可以将正则表达式作为参数:
"hello world with spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]
String.replace可以将正则表达式作为搜索参数,将函数作为替换参数:
var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"
373
您可以在大多数时间使用对象而不是开关 .
function getInnerText(o){
return o === null? null : {
string: o,
array: o.map(getInnerText).join(""),
object:getInnerText(o["childNodes"])
}[typeis(o)];
}
更新:如果您担心事先评估的效率低下(为什么您在设计程序的早期担心效率?)那么您可以这样做:
function getInnerText(o){
return o === null? null : {
string: function() { return o;},
array: function() { return o.map(getInnerText).join(""); },
object: function () { return getInnerText(o["childNodes"]; ) }
}[typeis(o)]();
}
let getInnerText = o -> ({
string: o -> o,
array: o -> o.map(getInnerText).join(""),
object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);
162
迭代对象的属性时,请务必使用 hasOwnProperty 方法:
for (p in anObject) {
if (anObject.hasOwnProperty(p)) {
//Do stuff with p here
}
}
这样做是为了您只访问 direct properties of anObject ,而不使用原型链下的属性 .
var test = function () {
//private members
var x = 1;
var y = function () {
return x * 2;
};
//public interface
return {
setx : function (newx) {
x = newx;
},
gety : function () {
return y();
}
}
}();
assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());
30 回答
你没有't need to define any parameters for a function. You can just use the function' s
arguments
类似数组的对象 .我可以引用Douglas Crockford的大部分优秀书籍JavaScript: The Good Parts .
但我会为你拿一个,总是使用
===
和!==
而不是==
和!=
==
不是传递性的 . 如果您使用===
,则会按预期为所有这些语句提供false .我不得不说自动执行功能 .
因为Javascript doesn't have block scope,如果要定义局部变量,可以使用自执行函数:
这里,
myvar
不会干扰或污染全局范围,并在函数终止时消失 .函数是JavaScript中的一等公民:
Functional programming techniques can be used to write elegant javascript .
特别是,函数可以作为参数传递,例如Array.filter()接受回调:
您还可以声明仅存在于特定函数范围内的“私有”函数:
您可以使用 in 运算符检查对象中是否存在键:
如果您发现对象文字太丑陋,可以将它与无参数函数提示结合起来:
Assigning default values to variables
您可以在赋值表达式中使用逻辑或运算符||来提供默认值:
仅当
b
为假(null
,false
,undefined
,0
,empty string
或NaN
)时,a
变量才会获得c
的值,否则a
将获得b
的值 .当你想在没有提供的情况下给参数提供默认值时,这通常在函数中很有用:
事件处理程序中的IE回退示例:
以下语言功能已经使用了很长时间,所有JavaScript实现都支持它们,但直到ECMAScript 5th Edition它们才是规范的一部分:
The debugger statement
描述于:§12.15调试器语句
此语句允许您通过以下方式以编程方式在代码中放置断点:
如果调试器存在或处于活动状态,它将导致它立即在该行上断开 .
否则,如果调试器不存在或处于活动状态,则此语句没有可观察到的影响 .
Multiline String literals
描述于:§7.8.4字符串文字
你必须要小心,因为
\
旁边的字符必须是行终止符,如果你在_1035186之后有一个空格,例如,代码看起来完全一样,但它会引发一个SyntaxError
.JavaScript does not have block scope(但它有closure所以让我们称它为偶数?) .
You can access object properties with [] instead of .
这允许您查找与变量匹配的属性 .
您还可以使用它来获取/设置名称不是合法标识符的对象属性 .
有些人不知道这一点并最终使用这样的 eval() ,这是一个非常糟糕的主意:
这很难阅读,更难找到错误(不能使用jslint),执行速度较慢,并且可能导致XSS攻击 .
如果您正在使用Google搜索关于给定主题的合适JavaScript引用,请在查询中包含“mdc”关键字,并且您的第一批结果将来自Mozilla开发人员中心 . 我没有随身携带任何离线参考书或书籍 . 我总是使用“mdc”关键字技巧来直接找到我正在寻找的东西 . 例如:
谷歌:javascript array sort mdc
(在大多数情况下,你可以省略"javascript")
Update: Mozilla Developer Center 已更名为Mozilla Developer Network . "mdc"关键字技巧仍然有效,但很快我们可能需要 start using "mdn" instead .
对某些人来说可能有点明显......
安装Firebug并使用console.log("hello") . 比使用随机警报()更好,我记得几年前做了很多 .
Private Methods
对象可以具有私有方法 .
在Crockford的“Javascript:The Good Parts”中也提到过:
parseInt()
很危险 . 如果你传递一个字符串而没有通知它正确的基数,它可能会返回意外的数字 . 例如parseInt('010')
返回8而不是10.将基数传递给parseInt使其正常工作:函数是对象,因此可以具有属性 .
Know how many parameters are expected by a function
Know how many parameters are received by the function
以下是一些有趣的事情:
将
NaN
与任何内容(甚至NaN
)进行比较始终为false,包括==
,<
和>
.NaN
代表不是数字,但如果你要求输入类型,它实际上会返回一个数字 .Array.sort
可以采用比较器功能,并由类似快速排序的驱动程序调用(取决于实现) .正则表达式"constants"可以保持状态,就像它们匹配的最后一样 .
某些版本的JavaScript允许您在正则表达式上访问
$0
,$1
,$2
成员 .null
与众不同 . 它既不是对象,也不是布尔值,数字,字符串,也不是undefined
. 这有点像"alternate"undefined
. (注:typeof null == "object"
)在最外层的上下文中,
this
产生否则无法命名的[Global]对象 .使用
var
声明变量,而不仅仅依赖于变量的自动声明,使运行时有机会优化对该变量的访问with
构造将破坏此类优化变量名称可以包含Unicode字符 .
JavaScript正则表达式实际上不是常规的 . 它们基于Perl的正则表达式,并且可以构建具有前瞻性的表达式,这些表达式需要花费非常长的时间来进行评估 .
可以标记块并将其用作
break
的目标 . 可以标记循环并将其用作continue
的目标 .数组不稀疏 . 设置其他空数组的第1000个元素应该用
undefined
填充它 . (取决于实施)if (new Boolean(false)) {...}
将执行{...}
块Javascript 's regular expression engine' s是特定于实现的:例如可以编写"non-portable"正则表达式 .
[根据好的评论稍作更新;请看评论]
我知道'm late to the party, but I just can' t相信
+
运算符's usefulness hasn' t已被提及超出"convert anything to a number" . 也许这是隐藏一个功能有多好?当然,您可以使用
Number()
代替这一切,但+
运算符更漂亮!您还可以通过覆盖原型的
valueOf()
方法为对象定义数字返回值 . 对该对象执行的任何数字转换都不会产生NaN
,而是valueOf()
方法的返回值:“Extension methods in JavaScript”通过原型属性 .
这将为所有
Array
对象添加contains
方法 . 您可以使用此语法调用此方法要从对象中正确删除属性,应删除该属性,而不是仅将其设置为undefined:
属性prop2仍然是迭代的一部分 . 如果你想完全摆脱prop2,你应该做:
当您遍历属性时,属性prop2将不再出现 .
with .
它很少使用,坦率地说,很少有用......但是,在有限的情况下,它确实有其用途 .
例如:对象文字对于在新对象上快速设置属性非常方便 . 但是,如果您需要更改现有对象的一半属性,该怎么办?
Alan Storm指出这可能有点危险:如果用作上下文的对象没有分配其中一个属性,它将在外部范围内解析,可能创建或覆盖全局变量 . 如果您习惯于编写代码来处理具有默认值或空值的属性未定义的对象,那么这将特别危险:
因此,避免使用
with
语句进行此类分配可能是个好主意 .另请参阅:JavaScript的“with”语句是否有合法用途?
可以在对象上调用方法(或函数),这些方法不是它们设计用于的类型 . 这很适合在自定义对象上调用本机(快速)方法 .
此代码崩溃,因为
listNodes
不是Array
此代码有效,因为
listNodes
定义了sort()
使用的足够类似数组的属性(length,[]运算符) .Prototypal inheritance (由道格拉斯·克罗克福德推广)彻底改变了你在Javascript中思考大量内容的方式 .
这是一个杀手!可惜几乎没有人使用它 .
它允许您“生成”任何对象的新实例,扩展它们,同时保持(实时)原型继承链接到其他属性 . 例:
有人会称之为品味,但是:
可以将三元运算符链接起来像Scheme(cond ...):
可写成......
这非常“实用”,因为它可以在没有副作用的情况下分支您的代码 . 所以代替:
你可以写:
同样适用于递归:)
数字也是对象 . 所以你可以做很酷的事情:
在JavaScript中如何 closures (类似于匿名C#v2.0中的方法 . 您可以创建一个创建函数或"expression"的函数 .
closures 的示例:
你也可以 extend (inherit) classes and override properties/methods 使用原型链 spoon16 提到 .
在下面的示例中,我们创建了一个Pet类并定义了一些属性 . 我们还覆盖从Object继承的.toString()方法 .
在此之后我们创建一个Dog类,其中 extends Pet and overrides the .toString() 方法再次改变它的行为(多态) . 此外,我们还为子类添加了一些其他属性 .
在此之后,我们检查继承链以显示Dog仍然是Dog类型,Pet类型和Object类型 .
这个问题的答案都是从great MSDN article by Ray Djajadinata.修改的代码
您可以根据类型捕获异常 . 引自MDC:
NOTE: 条件catch子句是Netscape(因此也是Mozilla / Firefox)扩展,它不是ECMAScript规范的一部分,因此除特定浏览器外不能依赖它 .
我的头顶......
Functions
arguments.callee是指托管“arguments”变量的函数,因此它可用于递归匿名函数:
如果你想做这样的事情,这很有用:
Objects
关于对象成员的一个有趣的事情:它们可以有任何字符串作为其名称:
Strings
String.split可以将正则表达式作为参数:
String.replace可以将正则表达式作为搜索参数,将函数作为替换参数:
您可以在大多数时间使用对象而不是开关 .
更新:如果您担心事先评估的效率低下(为什么您在设计程序的早期担心效率?)那么您可以这样做:
键入(或读取)比使用开关或对象更加繁琐,但它保留了使用对象而不是开关的好处,详见下面的注释部分 . 这种风格也使它更容易将它变成适当的“阶级”,一旦它长大了 .
update2:对于ES.next提出了语法扩展,这就变成了
迭代对象的属性时,请务必使用 hasOwnProperty 方法:
这样做是为了您只访问 direct properties of anObject ,而不使用原型链下的属性 .
具有公共接口的私有变量
它使用一个带有自调用函数定义的巧妙小技巧 . 返回的对象内的所有内容都可以在公共界面中使用,而其他所有内容都是私有的 .