题目描述
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
1 | 输入: [-2,1,-3,4,-1,2,1,-5,4], |
代码实现
下面这个解法的思想就是求各个位置的最大值
1 | /** |
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
1 | 输入: [-2,1,-3,4,-1,2,1,-5,4], |
下面这个解法的思想就是求各个位置的最大值
1 | /** |
1 | // 字面量方式创建对象 |
虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码,如上面的代码,每创建一个类似的person对象,就会重复上面的写法,代码较为冗余。
1 | function createPerson(name, age, job) { |
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。
使用构造函数模式将前面的例子重写如下:
1 | function Person(name, age, job) { |
要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4个步骤:
在前面例子的最后,person1 和 person2 分别保存着 Person 的一个不同的实例。这两个对象都有一个constructor(构造函数)
属性,该属性指向 Person,如下所示。
1 | console.log(person1.constructor == Person); //true |
创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型;而这正是构造函数模式胜过工厂模式的地方。在这个例子中,person1 和 person2 之所以同时是 Object 的实例,是因为所有对象均继承自 Object。
使用构造函数的主要问题,就是每个方法(这里是sayname)都要在每个实例上重新创建一遍。
1 | console.log(person1.sayName == person2.sayName) // false |
1 | function Person() {} |
与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。换句话说,person1 和 person2 访问的都是同一组属性和同一个 sayName()函数。
1 | function Person() {} |
在上面的代码中,我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外:constructor 属性不再指向 Person 了。前面曾经介绍过,每创建一个函数,就会同时创建它的prototype 对象,这个对象也会自动获得 constructor 属性。而我们在这里使用的语法,本质上完全重写了默认的 prototype 对象,因此 constructor 属性也就变成了新对象的 constructor 属性(指向 Object 构造函数),不再指向 Person 函数。此时,尽管 instanceof 操作符还能返回正确的结果,但通过 constructor 已经无法确定对象的类型了。
如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。
1 | function Person() {} |
调用构造函数时会为实例添加一个指向最初原型的 [[Prototype]]
指针,而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。
请记住:实例中的指针仅指向原型,而不指向构造函数。
1 | function Person() {} |
在上面的代码中,我们先创建了 Person 的一个实例,然后又重写了其原型对象。然后在调用 friend.sayName()时发生了错误,因为 friend 指向的原型中不包含以该名字命名的属性。
原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于包含引用类型值的属性来说,问题就比较突出了。而这个问题正是我们很少看到有人单独使用原型模式的原因所在。
1 | function Person() {} |
1 | function Person(name, age, job) { |
在这个例子中,实例属性都是在构造函数中定义的,而由所有实例共享的属性 constructor 和方法 sayName()则是在原型中定义的。而修改了 person1.friends(向其中添加一个新字符串),并不会影响到 person2.friends,因为它们分别引用了不同的数组。
这种构造函数与原型混成的模式,是目前在 ECMAScript 中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。
1 | // 属性要为索引 (数字) 属性,必须有length属性,最好加上push |
1 | let obj = { |
1 | let arrayLike = { |
1 | let arrayLike = { |
Use Array.from
for converting an array-like object to an array.
用 Array.from
去将一个类数组对象转成一个数组。
1 | const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; |
说到类数组对象,arguments对象就是一个类数组对象。在客户端 JavaScript 中,一些 DOM 方法document.getElementsByTagName()
等也返回类数组对象。
To convert an iterable object to an array, use spreads ...
instead of Array.from
.
用 ...
运算符而不是Array.from
来将一个可迭代的对象转换成数组。
1 | const foo = document.querySelectorAll('.foo'); |
参考